<commit_before>port module Arborist.Framework exposing (
    Test,
    Tests,
    Name,
    run,
    test,
    assert
  )

{-| Arborist is a test framework for asynchronous code.

It is intended for use mostly with Tasks. Tests are defined as assertions on
tasks, which are executed in parallel and reported on the command line.

# Declaring tests
@docs Test, Tests, Name, test

# Assertions
@docs assert

# Running tests
@docs run
-}

import Html
import Html.App exposing (program)
import List
import String
import Task exposing (Task)

import Arborist.Assertions
import Arborist.Matchers exposing (Matcher)

{-| The name of a test. -}
type alias Name = String

{-| A test case, usually constructed with the `test` function. -}
type Test = Test { name : Name, assertion : Assertion }

{-| A list of `Test` cases. -}
type alias Tests = List Test

type alias Assertion = Arborist.Assertions.Assertion
type alias FailureMessage = Arborist.Assertions.FailureMessage
type alias FailureMessages = Arborist.Assertions.FailureMessages

port output : String -> Cmd message

{-| Runs test cases in parallel, and prints the output to the command line. -}
run : List Test -> Program Never
run tests =
  program {
    init = ((), constructTests tests),
    update = \message model -> ((), output message),
    view = \model -> Html.div [] [],
    subscriptions = always Sub.none
  }

{-| Defines a test case.

    test "One plus one is most definitely two" (
      assert (Task.succeed (1 + 1)) (equals (Task.succeed 2))
    )
-}
test : Name -> Assertion -> Test
test name assertion =
  Test { name = name, assertion = assertion }

constructTests : List Test -> Cmd String
constructTests tests =
  tests
    |> List.reverse
    |> List.map (\(Test { name, assertion }) ->
      assertion
        |> Task.map (\(testPassed, failureMessages) ->
          if testPassed
            then passed name
            else failed name failureMessages)
        |> (flip Task.onError) (\failureMessages -> Task.succeed (failed name failureMessages))
        |> Task.perform identity identity)
    |> Cmd.batch

{-| `assert` runs a matcher against a value. All values are generally wrapped in tasks.

    let
      a = Task.succeed 7
      b = Task.succeed 3
      c = Task.map2 (+) a b
    in
      assert c (equals (Task.succeed 10))
-}
assert : Task a b -> Matcher a b -> Assertion
assert = Arborist.Assertions.assert

passed : Name -> String
passed name = green (name ++ " PASSED")

failed : Name -> FailureMessages -> String
failed name failureMessages =
  failureMessages
    |> List.map (\(key, value) -> "\n  " ++ key ++ ":\n  " ++ value)
    |> String.join ""
    |> (\messages -> name ++ " FAILED" ++ messages)
    |> red

green string = "\x1b[32m" ++ string ++ reset

red string = "\x1b[31m" ++ string ++ reset

reset = "\x1b[0m"<commit_msg>Add types for functions in Framework.<commit_after>port module Arborist.Framework exposing (
    Test,
    Tests,
    Name,
    run,
    test,
    assert
  )

{-| Arborist is a test framework for asynchronous code.

It is intended for use mostly with Tasks. Tests are defined as assertions on
tasks, which are executed in parallel and reported on the command line.

# Declaring tests
@docs Test, Tests, Name, test

# Assertions
@docs assert

# Running tests
@docs run
-}

import Html
import Html.App exposing (program)
import List
import String
import Task exposing (Task)

import Arborist.Assertions
import Arborist.Matchers exposing (Matcher)

{-| The name of a test. -}
type alias Name = String

{-| A test case, usually constructed with the `test` function. -}
type Test = Test { name : Name, assertion : Assertion }

{-| A list of `Test` cases. -}
type alias Tests = List Test

type alias Assertion = Arborist.Assertions.Assertion
type alias FailureMessage = Arborist.Assertions.FailureMessage
type alias FailureMessages = Arborist.Assertions.FailureMessages

port output : String -> Cmd message

{-| Runs test cases in parallel, and prints the output to the command line. -}
run : List Test -> Program Never
run tests =
  program {
    init = ((), constructTests tests),
    update = \message model -> ((), output message),
    view = \model -> Html.div [] [],
    subscriptions = always Sub.none
  }

{-| Defines a test case.

    test "One plus one is most definitely two" (
      assert (Task.succeed (1 + 1)) (equals (Task.succeed 2))
    )
-}
test : Name -> Assertion -> Test
test name assertion =
  Test { name = name, assertion = assertion }

constructTests : List Test -> Cmd String
constructTests tests =
  tests
    |> List.reverse
    |> List.map (\(Test { name, assertion }) ->
      assertion
        |> Task.map (\(testPassed, failureMessages) ->
          if testPassed
            then passed name
            else failed name failureMessages)
        |> (flip Task.onError) (\failureMessages -> Task.succeed (failed name failureMessages))
        |> Task.perform identity identity)
    |> Cmd.batch

{-| `assert` runs a matcher against a value. All values are generally wrapped in tasks.

    let
      a = Task.succeed 7
      b = Task.succeed 3
      c = Task.map2 (+) a b
    in
      assert c (equals (Task.succeed 10))
-}
assert : Task a b -> Matcher a b -> Assertion
assert = Arborist.Assertions.assert

passed : Name -> String
passed name = green (name ++ " PASSED")

failed : Name -> FailureMessages -> String
failed name failureMessages =
  failureMessages
    |> List.map (\(key, value) -> "\n  " ++ key ++ ":\n  " ++ value)
    |> String.join ""
    |> (\messages -> name ++ " FAILED" ++ messages)
    |> red

green : String -> String
green string = "\x1b[32m" ++ string ++ reset

red : String -> String
red string = "\x1b[31m" ++ string ++ reset

reset : String
reset = "\x1b[0m"
{'fraction_non_alphanumeric': 0.11252395053126633, 'fraction_numerical': 0.005573941821982233, 'mean_word_length': 2.9221311475409837, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '90815', 'n_tokens_mistral': 1767, 'n_tokens_neox': 1675, 'n_words': 642}