🎨 elm-format
This commit is contained in:
5
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/.gitignore
vendored
Normal file
5
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*~
|
||||
node_modules/
|
||||
elm-stuff/
|
||||
docs/
|
||||
*.html
|
||||
46
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/.travis.yml
vendored
Normal file
46
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/.travis.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- test/elm-stuff/build-artifacts
|
||||
- sysconfcpus
|
||||
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- ELM_VERSION=0.18.0-beta TARGET_NODE_VERSION=node
|
||||
- ELM_VERSION=0.18.0-beta TARGET_NODE_VERSION=4.0
|
||||
|
||||
before_install:
|
||||
- if [ ${TRAVIS_OS_NAME} == "osx" ];
|
||||
then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh;
|
||||
fi
|
||||
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
- | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142
|
||||
if [ ! -d sysconfcpus/bin ];
|
||||
then
|
||||
git clone https://github.com/obmarg/libsysconfcpus.git;
|
||||
cd libsysconfcpus;
|
||||
./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus;
|
||||
make && make install;
|
||||
cd ..;
|
||||
fi
|
||||
|
||||
install:
|
||||
- nvm install $TARGET_NODE_VERSION
|
||||
- nvm use $TARGET_NODE_VERSION
|
||||
- node --version
|
||||
- npm --version
|
||||
- cd tests
|
||||
- npm install -g elm@$ELM_VERSION elm-test
|
||||
- mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old
|
||||
- printf '%s\n\n' '#!/bin/bash' 'echo "Running elm-make with sysconfcpus -n 2"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old "$@"' > $(npm config get prefix)/bin/elm-make
|
||||
- chmod +x $(npm config get prefix)/bin/elm-make
|
||||
- npm install
|
||||
- elm package install --yes
|
||||
|
||||
script:
|
||||
- npm test
|
||||
27
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/LICENSE
vendored
Normal file
27
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/LICENSE
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2016 Richard Feldman and Max Goldstein
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of elm-test nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
107
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/README.md
vendored
Normal file
107
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/README.md
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
# elm-test [](http://travis-ci.org/elm-community/elm-test)
|
||||
|
||||
Write unit and fuzz tests for your Elm code, in Elm.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Here are three example tests:
|
||||
|
||||
```elm
|
||||
suite : Test
|
||||
suite =
|
||||
describe "The String module"
|
||||
[ describe "String.reverse" -- Nest as many descriptions as you like.
|
||||
[ test "has no effect on a palindrome" <|
|
||||
\() ->
|
||||
let
|
||||
palindrome =
|
||||
"hannah"
|
||||
in
|
||||
Expect.equal palindrome (String.reverse palindrome)
|
||||
|
||||
-- Expect.equal is designed to be used in pipeline style, like this.
|
||||
, test "reverses a known string" <|
|
||||
\() ->
|
||||
"ABCDEFG"
|
||||
|> String.reverse
|
||||
|> Expect.equal "GFEDCBA"
|
||||
|
||||
-- fuzz runs the test 100 times with randomly-generated inputs!
|
||||
, fuzz string "restores the original string if you run it again" <|
|
||||
\randomlyGeneratedString ->
|
||||
randomlyGeneratedString
|
||||
|> String.reverse
|
||||
|> String.reverse
|
||||
|> Expect.equal randomlyGeneratedString
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
This code uses a few common functions:
|
||||
|
||||
* [`describe`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Test#test) to add a description string to a list of tests
|
||||
* [`test`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Test#test) to write a unit test
|
||||
* [`Expect`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Expect) to determine if a test should pass or fail
|
||||
* [`fuzz`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Test#fuzz) to run a function that produces a test several times with randomly-generated inputs
|
||||
|
||||
Check out [a large real-world test suite](https://github.com/rtfeldman/elm-css/tree/master/tests) for more.
|
||||
|
||||
### Running tests locally
|
||||
|
||||
There are several ways you can run tests locally:
|
||||
|
||||
* [from your terminal](https://github.com/rtfeldman/node-test-runner) via `npm install -g elm-test`
|
||||
* [from your browser](https://github.com/rtfeldman/html-test-runner)
|
||||
|
||||
Here's how to set up and run your tests using the CLI test runner:
|
||||
|
||||
1. Run `npm install -g elm-test` if you haven't already.
|
||||
2. `cd` into the project's root directory that has your `elm-package.json`.
|
||||
3. Run `elm-test init`. It will create a `tests` directory inside this one,
|
||||
with some files in it.
|
||||
4. Copy all the dependencies from `elm-package.json` into
|
||||
`tests/elm-package.json`. These dependencies need to stay in sync, so make
|
||||
sure whenever you change your dependencies in your current
|
||||
`elm-package.json`, you make the same change to `tests/elm-package.json`.
|
||||
5. Run `elm-test`.
|
||||
6. Edit `tests/Tests.elm` to introduce new tests.
|
||||
|
||||
### Running tests on CI
|
||||
|
||||
Here are some examples of running tests on CI servers:
|
||||
|
||||
* [`travis.yml`](https://github.com/rtfeldman/elm-css/blob/6ba8404f53269bc110c2e08ab24c9caf850da515/.travis.yml)
|
||||
* [`appveyor.yml`](https://github.com/rtfeldman/elm-css/blob/6ba8404f53269bc110c2e08ab24c9caf850da515/appveyor.yml)
|
||||
|
||||
## Strategies for effective testing
|
||||
|
||||
* [Make impossible states unrepresentable](https://www.youtube.com/watch?v=IcgmSRJHu_8) so that you don't have to test that they can't occur.
|
||||
* When doing TDD, treat compiler errors as a red test. So feel free to write the test you wish you had even if it means calling functions that don't exist yet!
|
||||
* How do you know when to stop testing? This is an engineering tradeoff without a perfect answer. If you don't feel confident in the correctness of your code, write more tests. If you feel you are wasting time testing better spent writing your application, stop writing tests for now.
|
||||
* Prefer fuzz tests to unit tests, when possible. But don't be afraid to supplement them with unit tests for tricky cases and regressions.
|
||||
* For simple functions, it's okay to copy the implementation to the test; this is a useful regression check. But if the implementation isn't obviously right, try to write tests that don't duplicate the suspect logic. The great thing about fuzz tests is that you don't have to arrive at the exact same value as the code under test, just state something that will be true of that value.
|
||||
* If you're writing a library that wraps an existing standard or protocol, use examples from the specification or docs as unit tests. Anything in your README should be backed by a unit test (sadly there's no easy way to keep them in sync).
|
||||
* Not even your test modules can import unexposed functions, so test them only as the exposed interface uses them. Don't expose a function just to test it. Every exposed function should have tests. (If you practice TDD, this happens automatically!)
|
||||
* `elm-test` is designed to test functions, not effects. To test them, use [elm-testable](http://package.elm-lang.org/packages/avh4/elm-testable/latest). For integration or end-to-end testing, use your favorite PhantomJS or Selenium webdriver, such as Capybara.
|
||||
|
||||
## Upgrading
|
||||
### From 0.17
|
||||
You will need to delete `elm-stuff` and `tests/elm-stuff`.
|
||||
|
||||
If you are using the Node runner, you will need to pull down the new `Main.elm`: `curl -o tests/Main.elm https://raw.githubusercontent.com/rtfeldman/node-test-runner/master/templates/Main.elm`
|
||||
|
||||
### From the old elm-test
|
||||
[`legacy-elm-test`](http://package.elm-lang.org/packages/rtfeldman/legacy-elm-test/latest) provides a
|
||||
drop-in replacement for the `ElmTest 1.0` API, except implemented in terms of
|
||||
the current `elm-test`. It also includes support for `elm-check` tests.
|
||||
|
||||
This lets you use the latest test runners right now, and upgrade incrementally.
|
||||
|
||||
## Releases
|
||||
| Version | Notes |
|
||||
| ------- | ----- |
|
||||
| [**3.1.0**](https://github.com/elm-community/elm-test/tree/3.1.0) | Add Expect.all
|
||||
| [**3.0.0**](https://github.com/elm-community/elm-test/tree/3.0.0) | Update for Elm 0.18; switch the argument order of `Fuzz.andMap`.
|
||||
| [**2.1.0**](https://github.com/elm-community/elm-test/tree/2.1.0) | Switch to rose trees for `Fuzz.andThen`, other API additions.
|
||||
| [**2.0.0**](https://github.com/elm-community/elm-test/tree/2.0.0) | Scratch-rewrite to project-fuzzball
|
||||
| [**1.0.0**](https://github.com/elm-community/elm-test/tree/1.0.0) | ElmTest initial release
|
||||
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/elm-package.json
vendored
Normal file
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/elm-package.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"summary": "Unit and Fuzz testing support with Console/Html/String outputs.",
|
||||
"repository": "https://github.com/elm-community/elm-test.git",
|
||||
"license": "BSD-3-Clause",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"exposed-modules": [
|
||||
"Test",
|
||||
"Test.Runner",
|
||||
"Expect",
|
||||
"Fuzz"
|
||||
],
|
||||
"dependencies": {
|
||||
"elm-community/lazy-list": "1.0.0 <= v < 2.0.0",
|
||||
"elm-community/shrink": "2.0.0 <= v < 3.0.0",
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"mgold/elm-random-pcg": "4.0.2 <= v < 5.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
649
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Expect.elm
vendored
Normal file
649
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Expect.elm
vendored
Normal file
@@ -0,0 +1,649 @@
|
||||
module Expect
|
||||
exposing
|
||||
( Expectation
|
||||
, pass
|
||||
, fail
|
||||
, getFailure
|
||||
, equal
|
||||
, notEqual
|
||||
, atMost
|
||||
, lessThan
|
||||
, greaterThan
|
||||
, atLeast
|
||||
, true
|
||||
, false
|
||||
, equalLists
|
||||
, equalDicts
|
||||
, equalSets
|
||||
, onFail
|
||||
, all
|
||||
)
|
||||
|
||||
{-| A library to create `Expectation`s, which describe a claim to be tested.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
* [`equal`](#equal) `(arg2 == arg1)`
|
||||
* [`notEqual`](#notEqual) `(arg2 /= arg1)`
|
||||
* [`lessThan`](#lessThan) `(arg2 < arg1)`
|
||||
* [`atMost`](#atMost) `(arg2 <= arg1)`
|
||||
* [`greaterThan`](#greaterThan) `(arg2 > arg1)`
|
||||
* [`atLeast`](#atLeast) `(arg2 >= arg1)`
|
||||
* [`true`](#true) `(arg == True)`
|
||||
* [`false`](#false) `(arg == False)`
|
||||
|
||||
## Basic Expectations
|
||||
|
||||
@docs Expectation, equal, notEqual, all
|
||||
|
||||
## Comparisons
|
||||
|
||||
@docs lessThan, atMost, greaterThan, atLeast
|
||||
|
||||
## Booleans
|
||||
|
||||
@docs true, false
|
||||
|
||||
## Collections
|
||||
|
||||
@docs equalLists, equalDicts, equalSets
|
||||
|
||||
## Customizing
|
||||
|
||||
@docs pass, fail, onFail, getFailure
|
||||
-}
|
||||
|
||||
import Test.Expectation
|
||||
import Dict exposing (Dict)
|
||||
import Set exposing (Set)
|
||||
import String
|
||||
|
||||
|
||||
{-| The result of a single test run: either a [`pass`](#pass) or a
|
||||
[`fail`](#fail).
|
||||
-}
|
||||
type alias Expectation =
|
||||
Test.Expectation.Expectation
|
||||
|
||||
|
||||
{-| Passes if the arguments are equal.
|
||||
|
||||
Expect.equal 0 (List.length [])
|
||||
|
||||
-- Passes because (0 == 0) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because the expected value didn't split the space in "Betty Botter"
|
||||
String.split " " "Betty Botter bought some butter"
|
||||
|> Expect.equal [ "Betty Botter", "bought", "some", "butter" ]
|
||||
|
||||
{-
|
||||
|
||||
[ "Betty", "Botter", "bought", "some", "butter" ]
|
||||
╷
|
||||
│ Expect.equal
|
||||
╵
|
||||
[ "Betty Botter", "bought", "some", "butter" ]
|
||||
|
||||
-}
|
||||
-}
|
||||
equal : a -> a -> Expectation
|
||||
equal =
|
||||
compareWith "Expect.equal" (==)
|
||||
|
||||
|
||||
{-| Passes if the arguments are not equal.
|
||||
|
||||
-- Passes because (11 /= 100) is True
|
||||
90 + 10
|
||||
|> Expect.notEqual 11
|
||||
|
||||
|
||||
-- Fails because (100 /= 100) is False
|
||||
90 + 10
|
||||
|> Expect.notEqual 100
|
||||
|
||||
{-
|
||||
|
||||
100
|
||||
╷
|
||||
│ Expect.notEqual
|
||||
╵
|
||||
100
|
||||
|
||||
-}
|
||||
-}
|
||||
notEqual : a -> a -> Expectation
|
||||
notEqual =
|
||||
compareWith "Expect.notEqual" (/=)
|
||||
|
||||
|
||||
{-| Passes if the second argument is less than the first.
|
||||
|
||||
Expect.lessThan 1 (List.length [])
|
||||
|
||||
-- Passes because (0 < 1) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (0 < -1) is False
|
||||
List.length []
|
||||
|> Expect.lessThan -1
|
||||
|
||||
|
||||
{-
|
||||
|
||||
0
|
||||
╷
|
||||
│ Expect.lessThan
|
||||
╵
|
||||
-1
|
||||
|
||||
-}
|
||||
-}
|
||||
lessThan : comparable -> comparable -> Expectation
|
||||
lessThan =
|
||||
compareWith "Expect.lessThan" (<)
|
||||
|
||||
|
||||
{-| Passes if the second argument is less than or equal to the first.
|
||||
|
||||
Expect.atMost 1 (List.length [])
|
||||
|
||||
-- Passes because (0 <= 1) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (0 <= -3) is False
|
||||
List.length []
|
||||
|> Expect.atMost -3
|
||||
|
||||
{-
|
||||
|
||||
0
|
||||
╷
|
||||
│ Expect.atMost
|
||||
╵
|
||||
-3
|
||||
|
||||
-}
|
||||
-}
|
||||
atMost : comparable -> comparable -> Expectation
|
||||
atMost =
|
||||
compareWith "Expect.atMost" (<=)
|
||||
|
||||
|
||||
{-| Passes if the second argument is greater than the first.
|
||||
|
||||
Expect.greaterThan -2 List.length []
|
||||
|
||||
-- Passes because (0 > -2) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (0 > 1) is False
|
||||
List.length []
|
||||
|> Expect.greaterThan 1
|
||||
|
||||
{-
|
||||
|
||||
0
|
||||
╷
|
||||
│ Expect.greaterThan
|
||||
╵
|
||||
1
|
||||
|
||||
-}
|
||||
-}
|
||||
greaterThan : comparable -> comparable -> Expectation
|
||||
greaterThan =
|
||||
compareWith "Expect.greaterThan" (>)
|
||||
|
||||
|
||||
{-| Passes if the second argument is greater than or equal to the first.
|
||||
|
||||
Expect.atLeast -2 (List.length [])
|
||||
|
||||
-- Passes because (0 >= -2) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (0 >= 3) is False
|
||||
List.length []
|
||||
|> Expect.atLeast 3
|
||||
|
||||
{-
|
||||
|
||||
0
|
||||
╷
|
||||
│ Expect.atLeast
|
||||
╵
|
||||
3
|
||||
|
||||
-}
|
||||
-}
|
||||
atLeast : comparable -> comparable -> Expectation
|
||||
atLeast =
|
||||
compareWith "Expect.atLeast" (>=)
|
||||
|
||||
|
||||
{-| Passes if the argument is 'True', and otherwise fails with the given message.
|
||||
|
||||
Expect.true "Expected the list to be empty." (List.isEmpty [])
|
||||
|
||||
-- Passes because (List.isEmpty []) is True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because List.isEmpty returns False, but we expect True.
|
||||
List.isEmpty [ 42 ]
|
||||
|> Expect.true "Expected the list to be empty."
|
||||
|
||||
{-
|
||||
|
||||
Expected the list to be empty.
|
||||
|
||||
-}
|
||||
-}
|
||||
true : String -> Bool -> Expectation
|
||||
true message bool =
|
||||
if bool then
|
||||
pass
|
||||
else
|
||||
fail message
|
||||
|
||||
|
||||
{-| Passes if the argument is 'False', and otherwise fails with the given message.
|
||||
|
||||
Expect.false "Expected the list not to be empty." (List.isEmpty [ 42 ])
|
||||
|
||||
-- Passes because (List.isEmpty [ 42 ]) is False
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (List.isEmpty []) is True
|
||||
List.isEmpty []
|
||||
|> Expect.false "Expected the list not to be empty."
|
||||
|
||||
{-
|
||||
|
||||
Expected the list not to be empty.
|
||||
|
||||
-}
|
||||
-}
|
||||
false : String -> Bool -> Expectation
|
||||
false message bool =
|
||||
if bool then
|
||||
fail message
|
||||
else
|
||||
pass
|
||||
|
||||
|
||||
{-| Passes if the arguments are equal lists.
|
||||
|
||||
-- Passes
|
||||
[1, 2, 3]
|
||||
|> Expect.equalLists [1, 2, 3]
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which, and reports which index the lists first
|
||||
differed at or which list was longer:
|
||||
|
||||
-- Fails
|
||||
[ 1, 2, 4, 6 ]
|
||||
|> Expect.equalLists [ 1, 2, 5 ]
|
||||
|
||||
{-
|
||||
|
||||
[1,2,4,6]
|
||||
first diff at index index 2: +`4`, -`5`
|
||||
╷
|
||||
│ Expect.equalLists
|
||||
╵
|
||||
first diff at index index 2: +`5`, -`4`
|
||||
[1,2,5]
|
||||
|
||||
-}
|
||||
-}
|
||||
equalLists : List a -> List a -> Expectation
|
||||
equalLists expected actual =
|
||||
if expected == actual then
|
||||
pass
|
||||
else
|
||||
let
|
||||
result =
|
||||
List.map2 (,) actual expected
|
||||
|> List.indexedMap (,)
|
||||
|> List.filterMap
|
||||
(\( index, ( a, e ) ) ->
|
||||
if e == a then
|
||||
Nothing
|
||||
else
|
||||
Just ( index, a, e )
|
||||
)
|
||||
|> List.head
|
||||
|> Maybe.map
|
||||
(\( index, a, e ) ->
|
||||
[ toString actual
|
||||
, "first diff at index index " ++ toString index ++ ": +`" ++ toString a ++ "`, -`" ++ toString e ++ "`"
|
||||
, "╷"
|
||||
, "│ Expect.equalLists"
|
||||
, "╵"
|
||||
, "first diff at index index " ++ toString index ++ ": +`" ++ toString e ++ "`, -`" ++ toString a ++ "`"
|
||||
, toString expected
|
||||
]
|
||||
|> String.join "\n"
|
||||
|> fail
|
||||
)
|
||||
in
|
||||
case result of
|
||||
Just failure ->
|
||||
failure
|
||||
|
||||
Nothing ->
|
||||
case compare (List.length actual) (List.length expected) of
|
||||
GT ->
|
||||
reportFailure "Expect.equalLists was longer than" (toString expected) (toString actual)
|
||||
|> fail
|
||||
|
||||
LT ->
|
||||
reportFailure "Expect.equalLists was shorter than" (toString expected) (toString actual)
|
||||
|> fail
|
||||
|
||||
_ ->
|
||||
pass
|
||||
|
||||
|
||||
{-| Passes if the arguments are equal dicts.
|
||||
|
||||
-- Passes
|
||||
(Dict.fromList [ ( 1, "one" ), ( 2, "two" ) ])
|
||||
|> Expect.equalDicts (Dict.fromList [ ( 1, "one" ), ( 2, "two" ) ])
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which, and reports which keys were missing from
|
||||
or added to each dict:
|
||||
|
||||
-- Fails
|
||||
(Dict.fromList [ ( 1, "one" ), ( 2, "too" ) ])
|
||||
|> Expect.equalDicts (Dict.fromList [ ( 1, "one" ), ( 2, "two" ), ( 3, "three" ) ])
|
||||
|
||||
{-
|
||||
|
||||
Dict.fromList [(1,"one"),(2,"too")]
|
||||
diff: -[ (2,"two"), (3,"three") ] +[ (2,"too") ]
|
||||
╷
|
||||
│ Expect.equalDicts
|
||||
╵
|
||||
diff: +[ (2,"two"), (3,"three") ] -[ (2,"too") ]
|
||||
Dict.fromList [(1,"one"),(2,"two"),(3,"three")]
|
||||
|
||||
-}
|
||||
-}
|
||||
equalDicts : Dict comparable a -> Dict comparable a -> Expectation
|
||||
equalDicts expected actual =
|
||||
if Dict.toList expected == Dict.toList actual then
|
||||
pass
|
||||
else
|
||||
let
|
||||
differ dict k v diffs =
|
||||
if Dict.get k dict == Just v then
|
||||
diffs
|
||||
else
|
||||
( k, v ) :: diffs
|
||||
|
||||
missingKeys =
|
||||
Dict.foldr (differ actual) [] expected
|
||||
|
||||
extraKeys =
|
||||
Dict.foldr (differ expected) [] actual
|
||||
in
|
||||
fail (reportCollectionFailure "Expect.equalDicts" expected actual missingKeys extraKeys)
|
||||
|
||||
|
||||
{-| Passes if the arguments are equal sets.
|
||||
|
||||
-- Passes
|
||||
(Set.fromList [1, 2])
|
||||
|> Expect.equalSets (Set.fromList [1, 2])
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which, and reports which keys were missing from
|
||||
or added to each set:
|
||||
|
||||
-- Fails
|
||||
(Set.fromList [ 1, 2, 4, 6 ])
|
||||
|> Expect.equalSets (Set.fromList [ 1, 2, 5 ])
|
||||
|
||||
{-
|
||||
|
||||
Set.fromList [1,2,4,6]
|
||||
diff: -[ 5 ] +[ 4, 6 ]
|
||||
╷
|
||||
│ Expect.equalSets
|
||||
╵
|
||||
diff: +[ 5 ] -[ 4, 6 ]
|
||||
Set.fromList [1,2,5]
|
||||
|
||||
-}
|
||||
-}
|
||||
equalSets : Set comparable -> Set comparable -> Expectation
|
||||
equalSets expected actual =
|
||||
if Set.toList expected == Set.toList actual then
|
||||
pass
|
||||
else
|
||||
let
|
||||
missingKeys =
|
||||
Set.diff expected actual
|
||||
|> Set.toList
|
||||
|
||||
extraKeys =
|
||||
Set.diff actual expected
|
||||
|> Set.toList
|
||||
in
|
||||
fail (reportCollectionFailure "Expect.equalSets" expected actual missingKeys extraKeys)
|
||||
|
||||
|
||||
{-| Always passes.
|
||||
|
||||
import Json.Decode exposing (decodeString, int)
|
||||
import Test exposing (test)
|
||||
import Expect
|
||||
|
||||
|
||||
test "Json.Decode.int can decode the number 42." <|
|
||||
\() ->
|
||||
case decodeString int "42" of
|
||||
Ok _ ->
|
||||
Expect.pass
|
||||
|
||||
Err err ->
|
||||
Expect.fail err
|
||||
-}
|
||||
pass : Expectation
|
||||
pass =
|
||||
Test.Expectation.Pass
|
||||
|
||||
|
||||
{-| Fails with the given message.
|
||||
|
||||
import Json.Decode exposing (decodeString, int)
|
||||
import Test exposing (test)
|
||||
import Expect
|
||||
|
||||
|
||||
test "Json.Decode.int can decode the number 42." <|
|
||||
\() ->
|
||||
case decodeString int "42" of
|
||||
Ok _ ->
|
||||
Expect.pass
|
||||
|
||||
Err err ->
|
||||
Expect.fail err
|
||||
-}
|
||||
fail : String -> Expectation
|
||||
fail =
|
||||
Test.Expectation.Fail ""
|
||||
|
||||
|
||||
{-| Return `Nothing` if the given [`Expectation`](#Expectation) is a [`pass`](#pass).
|
||||
|
||||
If it is a [`fail`](#fail), return a record containing the failure message,
|
||||
along with the given inputs if it was a fuzz test. (If no inputs were involved,
|
||||
the record's `given` field will be `""`).
|
||||
|
||||
For example, if a fuzz test generates random integers, this might return
|
||||
`{ message = "it was supposed to be positive", given = "-1" }`
|
||||
|
||||
getFailure (Expect.fail "this failed")
|
||||
-- Just { message = "this failed", given = "" }
|
||||
|
||||
getFailure (Expect.pass)
|
||||
-- Nothing
|
||||
-}
|
||||
getFailure : Expectation -> Maybe { given : String, message : String }
|
||||
getFailure expectation =
|
||||
case expectation of
|
||||
Test.Expectation.Pass ->
|
||||
Nothing
|
||||
|
||||
Test.Expectation.Fail given message ->
|
||||
Just { given = given, message = message }
|
||||
|
||||
|
||||
{-| If the given expectation fails, replace its failure message with a custom one.
|
||||
|
||||
"something"
|
||||
|> Expect.equal "something else"
|
||||
|> Expect.onFail "thought those two strings would be the same"
|
||||
-}
|
||||
onFail : String -> Expectation -> Expectation
|
||||
onFail str expectation =
|
||||
case expectation of
|
||||
Test.Expectation.Pass ->
|
||||
expectation
|
||||
|
||||
Test.Expectation.Fail given _ ->
|
||||
Test.Expectation.Fail given str
|
||||
|
||||
|
||||
reportFailure : String -> String -> String -> String
|
||||
reportFailure comparison expected actual =
|
||||
[ actual
|
||||
, "╷"
|
||||
, "│ " ++ comparison
|
||||
, "╵"
|
||||
, expected
|
||||
]
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
reportCollectionFailure : String -> a -> b -> List c -> List d -> String
|
||||
reportCollectionFailure comparison expected actual missingKeys extraKeys =
|
||||
[ toString actual
|
||||
, "diff:" ++ formatDiffs Missing missingKeys ++ formatDiffs Extra extraKeys
|
||||
, "╷"
|
||||
, "│ " ++ comparison
|
||||
, "╵"
|
||||
, "diff:" ++ formatDiffs Extra missingKeys ++ formatDiffs Missing extraKeys
|
||||
, toString expected
|
||||
]
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
type Diff
|
||||
= Extra
|
||||
| Missing
|
||||
|
||||
|
||||
formatDiffs : Diff -> List a -> String
|
||||
formatDiffs diffType diffs =
|
||||
if List.isEmpty diffs then
|
||||
""
|
||||
else
|
||||
let
|
||||
modifier =
|
||||
case diffType of
|
||||
Extra ->
|
||||
"+"
|
||||
|
||||
Missing ->
|
||||
"-"
|
||||
in
|
||||
diffs
|
||||
|> List.map toString
|
||||
|> String.join ", "
|
||||
|> (\d -> " " ++ modifier ++ "[ " ++ d ++ " ]")
|
||||
|
||||
|
||||
compareWith : String -> (a -> b -> Bool) -> b -> a -> Expectation
|
||||
compareWith label compare expected actual =
|
||||
if compare actual expected then
|
||||
pass
|
||||
else
|
||||
fail (reportFailure label (toString expected) (toString actual))
|
||||
|
||||
|
||||
{-| Passes if each of the given functions passes when applied to the subject.
|
||||
|
||||
**NOTE:** Passing an empty list is assumed to be a mistake, so `Expect.all []`
|
||||
will always return a failed expectation no matter what else it is passed.
|
||||
|
||||
Expect.all
|
||||
[ Expect.greaterThan -2
|
||||
, Expect.lessThan 5
|
||||
]
|
||||
(List.length [])
|
||||
|
||||
-- Passes because (0 > -2) is True and (0 < 5) is also True
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because (0 > -10) is False
|
||||
List.length []
|
||||
|> Expect.all
|
||||
[ Expect.greaterThan -2
|
||||
, Expect.lessThan -10
|
||||
, Expect.equal 0
|
||||
]
|
||||
|
||||
{-
|
||||
|
||||
0
|
||||
╷
|
||||
│ Expect.lessThan
|
||||
╵
|
||||
-10
|
||||
|
||||
-}
|
||||
-}
|
||||
all : List (subject -> Expectation) -> subject -> Expectation
|
||||
all list query =
|
||||
if List.isEmpty list then
|
||||
fail "Expect.all received an empty list. I assume this was due to a mistake somewhere, so I'm failing this test!"
|
||||
else
|
||||
allHelp list query
|
||||
|
||||
|
||||
allHelp : List (subject -> Expectation) -> subject -> Expectation
|
||||
allHelp list query =
|
||||
case list of
|
||||
[] ->
|
||||
pass
|
||||
|
||||
check :: rest ->
|
||||
case check query of
|
||||
Test.Expectation.Pass ->
|
||||
allHelp rest query
|
||||
|
||||
outcome ->
|
||||
outcome
|
||||
802
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Fuzz.elm
vendored
Normal file
802
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Fuzz.elm
vendored
Normal file
@@ -0,0 +1,802 @@
|
||||
module Fuzz exposing (Fuzzer, custom, constant, unit, bool, order, char, float, floatRange, int, tuple, tuple3, tuple4, tuple5, result, string, percentage, map, map2, map3, map4, map5, andMap, andThen, maybe, intRange, list, array, frequency, frequencyOrCrash)
|
||||
|
||||
{-| This is a library of *fuzzers* you can use to supply values to your fuzz
|
||||
tests. You can typically pick out which ones you need according to their types.
|
||||
|
||||
A `Fuzzer a` knows how to create values of type `a` in two different ways. It
|
||||
can create them randomly, so that your test's expectations are run against many
|
||||
values. Fuzzers will often generate edge cases likely to find bugs. If the
|
||||
fuzzer can make your test fail, it also knows how to "shrink" that failing input
|
||||
into more minimal examples, some of which might also cause the tests to fail. In
|
||||
this way, fuzzers can usually find the smallest or simplest input that
|
||||
reproduces a bug.
|
||||
|
||||
## Common Fuzzers
|
||||
@docs bool, int, intRange, float, floatRange, percentage, string, maybe, result, list, array
|
||||
|
||||
## Working with Fuzzers
|
||||
@docs Fuzzer, constant, map, map2, map3,map4, map5, andMap, andThen, frequency, frequencyOrCrash
|
||||
|
||||
## Tuple Fuzzers
|
||||
Instead of using a tuple, consider using `fuzzN`.
|
||||
@docs tuple, tuple3, tuple4, tuple5
|
||||
|
||||
## Uncommon Fuzzers
|
||||
@docs custom, char, unit, order
|
||||
|
||||
-}
|
||||
|
||||
import Array exposing (Array)
|
||||
import Char
|
||||
import Util exposing (..)
|
||||
import Lazy.List exposing (LazyList)
|
||||
import Shrink exposing (Shrinker)
|
||||
import RoseTree exposing (RoseTree(..))
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import Fuzz.Internal as Internal exposing (Fuzz(..))
|
||||
|
||||
|
||||
{-| The representation of fuzzers is opaque. Conceptually, a `Fuzzer a`
|
||||
consists of a way to randomly generate values of type `a`, and a way to shrink
|
||||
those values.
|
||||
-}
|
||||
type alias Fuzzer a =
|
||||
Internal.Fuzzer a
|
||||
|
||||
|
||||
{-| Build a custom `Fuzzer a` by providing a `Generator a` and a `Shrinker a`.
|
||||
Generators are defined in [`mgold/elm-random-pcg`](http://package.elm-lang.org/packages/mgold/elm-random-pcg/latest),
|
||||
which is not core's Random module but has a compatible interface. Shrinkers are
|
||||
defined in [`elm-community/shrink`](http://package.elm-lang.org/packages/elm-community/shrink/latest/).
|
||||
|
||||
Here is an example for a record:
|
||||
|
||||
import Random.Pcg as Random
|
||||
import Shrink
|
||||
|
||||
type alias Position =
|
||||
{ x : Int, y : Int }
|
||||
|
||||
position : Fuzzer Position
|
||||
position =
|
||||
Fuzz.custom
|
||||
(Random.map2 Position (Random.int -100 100) (Random.int -100 100))
|
||||
(\{ x, y } -> Shrink.map Position (Shrink.int x) |> Shrink.andMap (Shrink.int y))
|
||||
|
||||
Here is an example for a custom union type, assuming there is already a `genName : Generator String` defined:
|
||||
|
||||
type Question
|
||||
= Name String
|
||||
| Age Int
|
||||
|
||||
question =
|
||||
let
|
||||
generator =
|
||||
Random.bool |> Random.andThen (\b ->
|
||||
if b then
|
||||
Random.map Name genName
|
||||
else
|
||||
Random.map Age (Random.int 0 120)
|
||||
)
|
||||
|
||||
shrinker question =
|
||||
case question of
|
||||
Name n ->
|
||||
Shrink.string n |> Shrink.map Name
|
||||
Age i ->
|
||||
Shrink.int i |> Shrink.map Age
|
||||
in
|
||||
Fuzz.custom generator shrinker
|
||||
|
||||
It is not possible to extract the generator and shrinker from an existing fuzzer.
|
||||
-}
|
||||
custom : Generator a -> Shrinker a -> Fuzzer a
|
||||
custom generator shrinker =
|
||||
let
|
||||
shrinkTree a =
|
||||
Rose a (Lazy.List.map shrinkTree (shrinker a))
|
||||
in
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
if noShrink then
|
||||
Gen generator
|
||||
else
|
||||
Shrink <| Random.map shrinkTree generator
|
||||
)
|
||||
|
||||
|
||||
{-| A fuzzer for the unit value. Unit is a type with only one value, commonly
|
||||
used as a placeholder.
|
||||
-}
|
||||
unit : Fuzzer ()
|
||||
unit =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
if noShrink then
|
||||
Gen <| Random.constant ()
|
||||
else
|
||||
Shrink <| Random.constant (RoseTree.singleton ())
|
||||
)
|
||||
|
||||
|
||||
{-| A fuzzer for bool values.
|
||||
-}
|
||||
bool : Fuzzer Bool
|
||||
bool =
|
||||
custom Random.bool Shrink.bool
|
||||
|
||||
|
||||
{-| A fuzzer for order values.
|
||||
-}
|
||||
order : Fuzzer Order
|
||||
order =
|
||||
let
|
||||
intToOrder i =
|
||||
if i == 0 then
|
||||
LT
|
||||
else if i == 1 then
|
||||
EQ
|
||||
else
|
||||
GT
|
||||
in
|
||||
custom (Random.map intToOrder (Random.int 0 2)) Shrink.order
|
||||
|
||||
|
||||
{-| A fuzzer for int values. It will never produce `NaN`, `Infinity`, or `-Infinity`.
|
||||
|
||||
It's possible for this fuzzer to generate any 32-bit integer, but it favors
|
||||
numbers between -50 and 50 and especially zero.
|
||||
-}
|
||||
int : Fuzzer Int
|
||||
int =
|
||||
let
|
||||
generator =
|
||||
Random.frequency
|
||||
[ ( 3, Random.int -50 50 )
|
||||
, ( 0.2, Random.constant 0 )
|
||||
, ( 1, Random.int 0 (Random.maxInt - Random.minInt) )
|
||||
, ( 1, Random.int (Random.minInt - Random.maxInt) 0 )
|
||||
]
|
||||
in
|
||||
custom generator Shrink.int
|
||||
|
||||
|
||||
{-| A fuzzer for int values within between a given minimum and maximum value,
|
||||
inclusive. Shrunken values will also be within the range.
|
||||
|
||||
Remember that [Random.maxInt](http://package.elm-lang.org/packages/elm-lang/core/latest/Random#maxInt)
|
||||
is the maximum possible int value, so you can do `intRange x Random.maxInt` to get all
|
||||
the ints x or bigger.
|
||||
-}
|
||||
intRange : Int -> Int -> Fuzzer Int
|
||||
intRange lo hi =
|
||||
custom
|
||||
(Random.frequency
|
||||
[ ( 8, Random.int lo hi )
|
||||
, ( 1, Random.constant lo )
|
||||
, ( 1, Random.constant hi )
|
||||
]
|
||||
)
|
||||
(Shrink.keepIf (\i -> i >= lo && i <= hi) Shrink.int)
|
||||
|
||||
|
||||
{-| A fuzzer for float values. It will never produce `NaN`, `Infinity`, or `-Infinity`.
|
||||
|
||||
|
||||
It's possible for this fuzzer to generate any other floating-point value, but it
|
||||
favors numbers between -50 and 50, numbers between -1 and 1, and especially zero.
|
||||
-}
|
||||
float : Fuzzer Float
|
||||
float =
|
||||
let
|
||||
generator =
|
||||
Random.frequency
|
||||
[ ( 3, Random.float -50 50 )
|
||||
, ( 0.5, Random.constant 0 )
|
||||
, ( 1, Random.float -1 1 )
|
||||
, ( 1, Random.float 0 (toFloat <| Random.maxInt - Random.minInt) )
|
||||
, ( 1, Random.float (toFloat <| Random.minInt - Random.maxInt) 0 )
|
||||
]
|
||||
in
|
||||
custom generator Shrink.float
|
||||
|
||||
|
||||
{-| A fuzzer for float values within between a given minimum and maximum
|
||||
value, inclusive. Shrunken values will also be within the range.
|
||||
-}
|
||||
floatRange : Float -> Float -> Fuzzer Float
|
||||
floatRange lo hi =
|
||||
custom
|
||||
(Random.frequency
|
||||
[ ( 8, Random.float lo hi )
|
||||
, ( 1, Random.constant lo )
|
||||
, ( 1, Random.constant hi )
|
||||
]
|
||||
)
|
||||
(Shrink.keepIf (\i -> i >= lo && i <= hi) Shrink.float)
|
||||
|
||||
|
||||
{-| A fuzzer for percentage values. Generates random floats between `0.0` and
|
||||
`1.0`. It will test zero and one about 10% of the time each.
|
||||
-}
|
||||
percentage : Fuzzer Float
|
||||
percentage =
|
||||
let
|
||||
generator =
|
||||
Random.frequency
|
||||
[ ( 8, Random.float 0 1 )
|
||||
, ( 1, Random.constant 0 )
|
||||
, ( 1, Random.constant 1 )
|
||||
]
|
||||
in
|
||||
custom generator Shrink.float
|
||||
|
||||
|
||||
{-| A fuzzer for char values. Generates random ascii chars disregarding the control
|
||||
characters.
|
||||
-}
|
||||
char : Fuzzer Char
|
||||
char =
|
||||
custom charGenerator Shrink.character
|
||||
|
||||
|
||||
charGenerator : Generator Char
|
||||
charGenerator =
|
||||
(Random.map Char.fromCode (Random.int 32 126))
|
||||
|
||||
|
||||
{-| Generates random printable ASCII strings of up to 1000 characters.
|
||||
|
||||
Shorter strings are more common, especially the empty string.
|
||||
-}
|
||||
string : Fuzzer String
|
||||
string =
|
||||
let
|
||||
generator : Generator String
|
||||
generator =
|
||||
Random.frequency
|
||||
[ ( 3, Random.int 1 10 )
|
||||
, ( 0.2, Random.constant 0 )
|
||||
, ( 1, Random.int 11 50 )
|
||||
, ( 1, Random.int 50 1000 )
|
||||
]
|
||||
|> Random.andThen (lengthString charGenerator)
|
||||
in
|
||||
custom generator Shrink.string
|
||||
|
||||
|
||||
{-| Given a fuzzer of a type, create a fuzzer of a maybe for that type.
|
||||
-}
|
||||
maybe : Fuzzer a -> Fuzzer (Maybe a)
|
||||
maybe (Internal.Fuzzer baseFuzzer) =
|
||||
Internal.Fuzzer <|
|
||||
\noShrink ->
|
||||
case baseFuzzer noShrink of
|
||||
Gen gen ->
|
||||
Gen <|
|
||||
Random.map2
|
||||
(\useNothing val ->
|
||||
if useNothing then
|
||||
Nothing
|
||||
else
|
||||
Just val
|
||||
)
|
||||
(Random.oneIn 4)
|
||||
gen
|
||||
|
||||
Shrink genTree ->
|
||||
Shrink <|
|
||||
Random.map2
|
||||
(\useNothing tree ->
|
||||
if useNothing then
|
||||
RoseTree.singleton Nothing
|
||||
else
|
||||
RoseTree.map Just tree |> RoseTree.addChild (RoseTree.singleton Nothing)
|
||||
)
|
||||
(Random.oneIn 4)
|
||||
genTree
|
||||
|
||||
|
||||
{-| Given fuzzers for an error type and a success type, create a fuzzer for
|
||||
a result.
|
||||
-}
|
||||
result : Fuzzer error -> Fuzzer value -> Fuzzer (Result error value)
|
||||
result (Internal.Fuzzer baseFuzzerError) (Internal.Fuzzer baseFuzzerValue) =
|
||||
Internal.Fuzzer <|
|
||||
\noShrink ->
|
||||
case ( baseFuzzerError noShrink, baseFuzzerValue noShrink ) of
|
||||
( Gen genErr, Gen genVal ) ->
|
||||
Gen <|
|
||||
Random.map3
|
||||
(\useError err val ->
|
||||
if useError then
|
||||
Err err
|
||||
else
|
||||
Ok val
|
||||
)
|
||||
(Random.oneIn 4)
|
||||
genErr
|
||||
genVal
|
||||
|
||||
( Shrink genTreeErr, Shrink genTreeVal ) ->
|
||||
Shrink <|
|
||||
Random.map3
|
||||
(\useError errorTree valueTree ->
|
||||
if useError then
|
||||
RoseTree.map Err errorTree
|
||||
else
|
||||
RoseTree.map Ok valueTree
|
||||
)
|
||||
(Random.oneIn 4)
|
||||
genTreeErr
|
||||
genTreeVal
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.result" err
|
||||
|
||||
|
||||
{-| Given a fuzzer of a type, create a fuzzer of a list of that type.
|
||||
Generates random lists of varying length, favoring shorter lists.
|
||||
-}
|
||||
list : Fuzzer a -> Fuzzer (List a)
|
||||
list (Internal.Fuzzer baseFuzzer) =
|
||||
let
|
||||
genLength =
|
||||
Random.frequency
|
||||
[ ( 1, Random.constant 0 )
|
||||
, ( 1, Random.constant 1 )
|
||||
, ( 3, Random.int 2 10 )
|
||||
, ( 2, Random.int 10 100 )
|
||||
, ( 0.5, Random.int 100 400 )
|
||||
]
|
||||
in
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case baseFuzzer noShrink of
|
||||
Gen genVal ->
|
||||
genLength
|
||||
|> Random.andThen (\i -> (Random.list i genVal))
|
||||
|> Gen
|
||||
|
||||
Shrink genTree ->
|
||||
genLength
|
||||
|> Random.andThen (\i -> (Random.list i genTree))
|
||||
|> Random.map listShrinkHelp
|
||||
|> Shrink
|
||||
)
|
||||
|
||||
|
||||
listShrinkHelp : List (RoseTree a) -> RoseTree (List a)
|
||||
listShrinkHelp listOfTrees =
|
||||
{- Shrinking a list of RoseTrees
|
||||
We need to do two things. First, shrink individual values. Second, shorten the list.
|
||||
To shrink individual values, we create every list copy of the input list where any
|
||||
one value is replaced by a shrunken form.
|
||||
To shorten the length of the list, slide windows of various lengths over it.
|
||||
In all cases, recurse! The goal is to make a little forward progress and then recurse.
|
||||
-}
|
||||
let
|
||||
n =
|
||||
List.length listOfTrees
|
||||
|
||||
root =
|
||||
List.map RoseTree.root listOfTrees
|
||||
|
||||
shrinkOne prefix list =
|
||||
case list of
|
||||
[] ->
|
||||
Lazy.List.empty
|
||||
|
||||
(Rose x shrunkenXs) :: more ->
|
||||
Lazy.List.map (\childTree -> prefix ++ (childTree :: more) |> listShrinkHelp) shrunkenXs
|
||||
|
||||
shrunkenVals =
|
||||
Lazy.List.numbers
|
||||
|> Lazy.List.map (\i -> i - 1)
|
||||
|> Lazy.List.take n
|
||||
|> Lazy.List.andThen
|
||||
(\i -> shrinkOne (List.take i listOfTrees) (List.drop i listOfTrees))
|
||||
|
||||
shortened =
|
||||
(if n > 6 then
|
||||
Lazy.List.iterate (\n -> n // 2) n
|
||||
|> Lazy.List.takeWhile (\x -> x > 0)
|
||||
else
|
||||
Lazy.List.fromList (List.range 1 n)
|
||||
)
|
||||
|> Lazy.List.andThen (\len -> shorter len listOfTrees False)
|
||||
|> Lazy.List.map listShrinkHelp
|
||||
|
||||
shorter windowSize aList recursing =
|
||||
-- Tricky: take the whole list if we've recursed down here, but don't let a list shrink to itself
|
||||
if windowSize > List.length aList || (windowSize == List.length aList && not recursing) then
|
||||
Lazy.List.empty
|
||||
else
|
||||
case aList of
|
||||
[] ->
|
||||
Lazy.List.empty
|
||||
|
||||
head :: tail ->
|
||||
Lazy.List.cons (List.take windowSize aList) (shorter windowSize tail True)
|
||||
in
|
||||
Lazy.List.append shortened shrunkenVals
|
||||
|> Lazy.List.cons (RoseTree.singleton [])
|
||||
|> Rose root
|
||||
|
||||
|
||||
{-| Given a fuzzer of a type, create a fuzzer of an array of that type.
|
||||
Generates random arrays of varying length, favoring shorter arrays.
|
||||
-}
|
||||
array : Fuzzer a -> Fuzzer (Array a)
|
||||
array fuzzer =
|
||||
map Array.fromList (list fuzzer)
|
||||
|
||||
|
||||
{-| Turn a tuple of fuzzers into a fuzzer of tuples.
|
||||
-}
|
||||
tuple : ( Fuzzer a, Fuzzer b ) -> Fuzzer ( a, b )
|
||||
tuple ( Internal.Fuzzer baseFuzzerA, Internal.Fuzzer baseFuzzerB ) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case ( baseFuzzerA noShrink, baseFuzzerB noShrink ) of
|
||||
( Gen genA, Gen genB ) ->
|
||||
Gen <| Random.map2 (,) genA genB
|
||||
|
||||
( Shrink genTreeA, Shrink genTreeB ) ->
|
||||
Shrink <| Random.map2 tupleShrinkHelp genTreeA genTreeB
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.tuple" err
|
||||
)
|
||||
|
||||
|
||||
tupleShrinkHelp : RoseTree a -> RoseTree b -> RoseTree ( a, b )
|
||||
tupleShrinkHelp ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) =
|
||||
{- Shrinking a tuple of RoseTrees
|
||||
Recurse on all tuples created by substituting one element for any of its shrunken values.
|
||||
|
||||
A weakness of this algorithm is that it expects that values can be shrunken independently.
|
||||
That is, to shrink from (a,b) to (a',b'), we must go through (a',b) or (a,b').
|
||||
"No pairs sum to zero" is a pathological predicate that cannot be shrunken this way.
|
||||
-}
|
||||
let
|
||||
root =
|
||||
( root1, root2 )
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp subtree rose2) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp rose1 subtree) children2
|
||||
in
|
||||
shrink2
|
||||
|> Lazy.List.append shrink1
|
||||
|> Rose root
|
||||
|
||||
|
||||
{-| Turn a 3-tuple of fuzzers into a fuzzer of 3-tuples.
|
||||
-}
|
||||
tuple3 : ( Fuzzer a, Fuzzer b, Fuzzer c ) -> Fuzzer ( a, b, c )
|
||||
tuple3 ( Internal.Fuzzer baseFuzzerA, Internal.Fuzzer baseFuzzerB, Internal.Fuzzer baseFuzzerC ) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case ( baseFuzzerA noShrink, baseFuzzerB noShrink, baseFuzzerC noShrink ) of
|
||||
( Gen genA, Gen genB, Gen genC ) ->
|
||||
Gen <| Random.map3 (,,) genA genB genC
|
||||
|
||||
( Shrink genTreeA, Shrink genTreeB, Shrink genTreeC ) ->
|
||||
Shrink <| Random.map3 tupleShrinkHelp3 genTreeA genTreeB genTreeC
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.tuple3" err
|
||||
)
|
||||
|
||||
|
||||
tupleShrinkHelp3 : RoseTree a -> RoseTree b -> RoseTree c -> RoseTree ( a, b, c )
|
||||
tupleShrinkHelp3 ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) ((Rose root3 children3) as rose3) =
|
||||
let
|
||||
root =
|
||||
( root1, root2, root3 )
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp3 subtree rose2 rose3) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp3 rose1 subtree rose3) children2
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp3 rose1 rose2 subtree) children3
|
||||
in
|
||||
shrink3
|
||||
|> Lazy.List.append shrink2
|
||||
|> Lazy.List.append shrink1
|
||||
|> Rose root
|
||||
|
||||
|
||||
{-| Turn a 4-tuple of fuzzers into a fuzzer of 4-tuples.
|
||||
-}
|
||||
tuple4 : ( Fuzzer a, Fuzzer b, Fuzzer c, Fuzzer d ) -> Fuzzer ( a, b, c, d )
|
||||
tuple4 ( Internal.Fuzzer baseFuzzerA, Internal.Fuzzer baseFuzzerB, Internal.Fuzzer baseFuzzerC, Internal.Fuzzer baseFuzzerD ) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case ( baseFuzzerA noShrink, baseFuzzerB noShrink, baseFuzzerC noShrink, baseFuzzerD noShrink ) of
|
||||
( Gen genA, Gen genB, Gen genC, Gen genD ) ->
|
||||
Gen <| Random.map4 (,,,) genA genB genC genD
|
||||
|
||||
( Shrink genTreeA, Shrink genTreeB, Shrink genTreeC, Shrink genTreeD ) ->
|
||||
Shrink <| Random.map4 tupleShrinkHelp4 genTreeA genTreeB genTreeC genTreeD
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.tuple4" err
|
||||
)
|
||||
|
||||
|
||||
tupleShrinkHelp4 : RoseTree a -> RoseTree b -> RoseTree c -> RoseTree d -> RoseTree ( a, b, c, d )
|
||||
tupleShrinkHelp4 rose1 rose2 rose3 rose4 =
|
||||
let
|
||||
root =
|
||||
( RoseTree.root rose1, RoseTree.root rose2, RoseTree.root rose3, RoseTree.root rose4 )
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp4 subtree rose2 rose3 rose4) (RoseTree.children rose1)
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp4 rose1 subtree rose3 rose4) (RoseTree.children rose2)
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp4 rose1 rose2 subtree rose4) (RoseTree.children rose3)
|
||||
|
||||
shrink4 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp4 rose1 rose2 rose3 subtree) (RoseTree.children rose4)
|
||||
in
|
||||
shrink4
|
||||
|> Lazy.List.append shrink3
|
||||
|> Lazy.List.append shrink2
|
||||
|> Lazy.List.append shrink1
|
||||
|> Rose root
|
||||
|
||||
|
||||
{-| Turn a 5-tuple of fuzzers into a fuzzer of 5-tuples.
|
||||
-}
|
||||
tuple5 : ( Fuzzer a, Fuzzer b, Fuzzer c, Fuzzer d, Fuzzer e ) -> Fuzzer ( a, b, c, d, e )
|
||||
tuple5 ( Internal.Fuzzer baseFuzzerA, Internal.Fuzzer baseFuzzerB, Internal.Fuzzer baseFuzzerC, Internal.Fuzzer baseFuzzerD, Internal.Fuzzer baseFuzzerE ) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case ( baseFuzzerA noShrink, baseFuzzerB noShrink, baseFuzzerC noShrink, baseFuzzerD noShrink, baseFuzzerE noShrink ) of
|
||||
( Gen genA, Gen genB, Gen genC, Gen genD, Gen genE ) ->
|
||||
Gen <| Random.map5 (,,,,) genA genB genC genD genE
|
||||
|
||||
( Shrink genTreeA, Shrink genTreeB, Shrink genTreeC, Shrink genTreeD, Shrink genTreeE ) ->
|
||||
Shrink <| Random.map5 tupleShrinkHelp5 genTreeA genTreeB genTreeC genTreeD genTreeE
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.tuple5" err
|
||||
)
|
||||
|
||||
|
||||
tupleShrinkHelp5 : RoseTree a -> RoseTree b -> RoseTree c -> RoseTree d -> RoseTree e -> RoseTree ( a, b, c, d, e )
|
||||
tupleShrinkHelp5 rose1 rose2 rose3 rose4 rose5 =
|
||||
let
|
||||
root =
|
||||
( RoseTree.root rose1, RoseTree.root rose2, RoseTree.root rose3, RoseTree.root rose4, RoseTree.root rose5 )
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp5 subtree rose2 rose3 rose4 rose5) (RoseTree.children rose1)
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp5 rose1 subtree rose3 rose4 rose5) (RoseTree.children rose2)
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp5 rose1 rose2 subtree rose4 rose5) (RoseTree.children rose3)
|
||||
|
||||
shrink4 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp5 rose1 rose2 rose3 subtree rose5) (RoseTree.children rose4)
|
||||
|
||||
shrink5 =
|
||||
Lazy.List.map (\subtree -> tupleShrinkHelp5 rose1 rose2 rose3 rose4 subtree) (RoseTree.children rose5)
|
||||
in
|
||||
shrink5
|
||||
|> Lazy.List.append shrink4
|
||||
|> Lazy.List.append shrink3
|
||||
|> Lazy.List.append shrink2
|
||||
|> Lazy.List.append shrink1
|
||||
|> Rose root
|
||||
|
||||
|
||||
{-| Create a fuzzer that only and always returns the value provided, and performs no shrinking. This is hardly random,
|
||||
and so this function is best used as a helper when creating more complicated fuzzers.
|
||||
-}
|
||||
constant : a -> Fuzzer a
|
||||
constant x =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
if noShrink then
|
||||
Gen (Random.constant x)
|
||||
else
|
||||
Shrink (Random.constant (RoseTree.singleton x))
|
||||
)
|
||||
|
||||
|
||||
{-| Map a function over a fuzzer. This applies to both the generated and the shruken values.
|
||||
-}
|
||||
map : (a -> b) -> Fuzzer a -> Fuzzer b
|
||||
map transform (Internal.Fuzzer baseFuzzer) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case baseFuzzer noShrink of
|
||||
Gen genVal ->
|
||||
Gen <| Random.map transform genVal
|
||||
|
||||
Shrink genTree ->
|
||||
Shrink <| Random.map (RoseTree.map transform) genTree
|
||||
)
|
||||
|
||||
|
||||
{-| Map over two fuzzers.
|
||||
-}
|
||||
map2 : (a -> b -> c) -> Fuzzer a -> Fuzzer b -> Fuzzer c
|
||||
map2 transform fuzzA fuzzB =
|
||||
map (\( a, b ) -> transform a b) (tuple ( fuzzA, fuzzB ))
|
||||
|
||||
|
||||
{-| Map over three fuzzers.
|
||||
-}
|
||||
map3 : (a -> b -> c -> d) -> Fuzzer a -> Fuzzer b -> Fuzzer c -> Fuzzer d
|
||||
map3 transform fuzzA fuzzB fuzzC =
|
||||
map (\( a, b, c ) -> transform a b c) (tuple3 ( fuzzA, fuzzB, fuzzC ))
|
||||
|
||||
|
||||
{-| Map over four fuzzers.
|
||||
-}
|
||||
map4 : (a -> b -> c -> d -> e) -> Fuzzer a -> Fuzzer b -> Fuzzer c -> Fuzzer d -> Fuzzer e
|
||||
map4 transform fuzzA fuzzB fuzzC fuzzD =
|
||||
map (\( a, b, c, d ) -> transform a b c d) (tuple4 ( fuzzA, fuzzB, fuzzC, fuzzD ))
|
||||
|
||||
|
||||
{-| Map over five fuzzers.
|
||||
-}
|
||||
map5 : (a -> b -> c -> d -> e -> f) -> Fuzzer a -> Fuzzer b -> Fuzzer c -> Fuzzer d -> Fuzzer e -> Fuzzer f
|
||||
map5 transform fuzzA fuzzB fuzzC fuzzD fuzzE =
|
||||
map (\( a, b, c, d, e ) -> transform a b c d e) (tuple5 ( fuzzA, fuzzB, fuzzC, fuzzD, fuzzE ))
|
||||
|
||||
|
||||
{-| Map over many fuzzers. This can act as mapN for N > 5.
|
||||
|
||||
The argument order is meant to accomodate chaining:
|
||||
|
||||
map f aFuzzer
|
||||
|> andMap anotherFuzzer
|
||||
|> andMap aThirdFuzzer
|
||||
|
||||
Note that shrinking may be better using mapN.
|
||||
-}
|
||||
andMap : Fuzzer a -> Fuzzer (a -> b) -> Fuzzer b
|
||||
andMap =
|
||||
map2 (|>)
|
||||
|
||||
|
||||
{-| Create a fuzzer based on the result of another fuzzer.
|
||||
-}
|
||||
andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b
|
||||
andThen transform (Internal.Fuzzer baseFuzzer) =
|
||||
Internal.Fuzzer
|
||||
(\noShrink ->
|
||||
case baseFuzzer noShrink of
|
||||
Gen genVal ->
|
||||
Gen <| Random.andThen (transform >> Internal.unpackGenVal) genVal
|
||||
|
||||
Shrink genTree ->
|
||||
Shrink <| andThenRoseTrees transform genTree
|
||||
)
|
||||
|
||||
|
||||
andThenRoseTrees : (a -> Fuzzer b) -> Generator (RoseTree a) -> Generator (RoseTree b)
|
||||
andThenRoseTrees transform genTree =
|
||||
genTree
|
||||
|> Random.andThen
|
||||
(\(Rose root branches) ->
|
||||
let
|
||||
genOtherChildren : Generator (LazyList (RoseTree b))
|
||||
genOtherChildren =
|
||||
branches
|
||||
|> Lazy.List.map (\rt -> RoseTree.map (transform >> Internal.unpackGenTree) rt |> unwindRoseTree)
|
||||
|> unwindLazyList
|
||||
|> Random.map (Lazy.List.map RoseTree.flatten)
|
||||
in
|
||||
Random.map2
|
||||
(\(Rose trueRoot rootsChildren) otherChildren ->
|
||||
Rose trueRoot (Lazy.List.append rootsChildren otherChildren)
|
||||
)
|
||||
(Internal.unpackGenTree (transform root))
|
||||
genOtherChildren
|
||||
)
|
||||
|
||||
|
||||
unwindRoseTree : RoseTree (Generator a) -> Generator (RoseTree a)
|
||||
unwindRoseTree (Rose genRoot lazyListOfRoseTreesOfGenerators) =
|
||||
case Lazy.List.headAndTail lazyListOfRoseTreesOfGenerators of
|
||||
Nothing ->
|
||||
Random.map RoseTree.singleton genRoot
|
||||
|
||||
Just ( Rose gen children, moreList ) ->
|
||||
Random.map4 (\a b c d -> Rose a (Lazy.List.cons (Rose b c) d))
|
||||
genRoot
|
||||
gen
|
||||
(Lazy.List.map unwindRoseTree children |> unwindLazyList)
|
||||
(Lazy.List.map unwindRoseTree moreList |> unwindLazyList)
|
||||
|
||||
|
||||
unwindLazyList : LazyList (Generator a) -> Generator (LazyList a)
|
||||
unwindLazyList lazyListOfGenerators =
|
||||
case Lazy.List.headAndTail lazyListOfGenerators of
|
||||
Nothing ->
|
||||
Random.constant Lazy.List.empty
|
||||
|
||||
Just ( head, tail ) ->
|
||||
Random.map2 Lazy.List.cons head (unwindLazyList tail)
|
||||
|
||||
|
||||
{-| Create a new `Fuzzer` by providing a list of probabilistic weights to use
|
||||
with other fuzzers.
|
||||
|
||||
For example, to create a `Fuzzer` that has a 1/4 chance of generating an int
|
||||
between -1 and -100, and a 3/4 chance of generating one between 1 and 100,
|
||||
you could do this:
|
||||
|
||||
Fuzz.frequency
|
||||
[ ( 1, Fuzz.intRange -100 -1 )
|
||||
, ( 3, Fuzz.intRange 1 100 )
|
||||
]
|
||||
|
||||
This returns a `Result` because it can fail in a few ways:
|
||||
|
||||
* If you provide an empy list of frequencies
|
||||
* If any of the weights are less than 0
|
||||
* If the weights sum to 0
|
||||
|
||||
Any of these will lead to a result of `Err`, with a `String` explaining what
|
||||
went wrong.
|
||||
-}
|
||||
frequency : List ( Float, Fuzzer a ) -> Result String (Fuzzer a)
|
||||
frequency list =
|
||||
if List.isEmpty list then
|
||||
Err "You must provide at least one frequency pair."
|
||||
else if List.any (\( weight, _ ) -> weight < 0) list then
|
||||
Err "No frequency weights can be less than 0."
|
||||
else if List.sum (List.map Tuple.first list) <= 0 then
|
||||
Err "Frequency weights must sum to more than 0."
|
||||
else
|
||||
Ok <|
|
||||
Internal.Fuzzer <|
|
||||
\noShrink ->
|
||||
if noShrink then
|
||||
list
|
||||
|> List.map (\( weight, fuzzer ) -> ( weight, Internal.unpackGenVal fuzzer ))
|
||||
|> Random.frequency
|
||||
|> Gen
|
||||
else
|
||||
list
|
||||
|> List.map (\( weight, fuzzer ) -> ( weight, Internal.unpackGenTree fuzzer ))
|
||||
|> Random.frequency
|
||||
|> Shrink
|
||||
|
||||
|
||||
{-| Calls `frequency` and handles `Err` results by crashing with the given
|
||||
error message.
|
||||
|
||||
This is useful in tests, where a crash will simply cause the test run to fail.
|
||||
There is no danger to a production system there.
|
||||
-}
|
||||
frequencyOrCrash : List ( Float, Fuzzer a ) -> Fuzzer a
|
||||
frequencyOrCrash =
|
||||
frequency >> okOrCrash
|
||||
|
||||
|
||||
okOrCrash : Result String a -> a
|
||||
okOrCrash result =
|
||||
case result of
|
||||
Ok a ->
|
||||
a
|
||||
|
||||
Err str ->
|
||||
Debug.crash str
|
||||
58
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Fuzz/Internal.elm
vendored
Normal file
58
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Fuzz/Internal.elm
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
module Fuzz.Internal exposing (Fuzzer(Fuzzer), Fuzz(..), unpackGenVal, unpackGenTree)
|
||||
|
||||
import RoseTree exposing (RoseTree)
|
||||
import Random.Pcg exposing (Generator)
|
||||
|
||||
|
||||
{- Fuzzers as opt-in RoseTrees
|
||||
|
||||
In the beginning, a Fuzzer was a record of a random generator and a shrinker.
|
||||
And it was bad, because that makes it impossible to shrink any value created by
|
||||
mapping over other values. But at least it was fast, and shrinking worked well.
|
||||
|
||||
On the second branch, we created RoseTrees, where every randomly-generated value
|
||||
also kept a lazy list of shrunken values, which also keep shrunken forms of
|
||||
themselves. This allows for advanced maps to be implemented, but it was slow.
|
||||
|
||||
On the third branch, we realized that we shouldn't have to pay for shrinking in
|
||||
the common case of a passing test. So Fuzzers became a function from a boolean
|
||||
to either another union type. If the function is passed True, it returns a
|
||||
Generator of a single value; if False, a Generator of a RoseTree of values.
|
||||
(This is almost certainly dependent types leaning on Debug.crash.) The root of
|
||||
the RoseTree must equal the single value. Thus the testing harness "opts-in" to
|
||||
producing a rosetree, doing so only after the single-value generator has caused
|
||||
a test to fail.
|
||||
|
||||
These two optimizations make the Fuzzer code rather hard to understand, but
|
||||
allow it to offer a full mapping API, be fast for passing tests, and provide
|
||||
shrunken values for failing tests.
|
||||
-}
|
||||
|
||||
|
||||
type Fuzzer a
|
||||
= Fuzzer (Bool -> Fuzz a)
|
||||
|
||||
|
||||
type Fuzz a
|
||||
= Gen (Generator a)
|
||||
| Shrink (Generator (RoseTree a))
|
||||
|
||||
|
||||
unpackGenVal : Fuzzer a -> Generator a
|
||||
unpackGenVal (Fuzzer g) =
|
||||
case g True of
|
||||
Gen genVal ->
|
||||
genVal
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.Internal.unpackGenVal" err
|
||||
|
||||
|
||||
unpackGenTree : Fuzzer a -> Generator (RoseTree a)
|
||||
unpackGenTree (Fuzzer g) =
|
||||
case g False of
|
||||
Shrink genTree ->
|
||||
genTree
|
||||
|
||||
err ->
|
||||
Debug.crash "This shouldn't happen: Fuzz.Internal.unpackGenTree" err
|
||||
59
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/RoseTree.elm
vendored
Normal file
59
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/RoseTree.elm
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
module RoseTree exposing (..)
|
||||
|
||||
{-| RoseTree implementation in Elm using Lazy Lists.
|
||||
|
||||
This implementation is private to elm-test and has non-essential functions removed.
|
||||
If you need a complete RoseTree implementation, one can be found on elm-package.
|
||||
-}
|
||||
|
||||
import Lazy.List as LazyList exposing (LazyList, (:::), (+++))
|
||||
|
||||
|
||||
{-| RoseTree type.
|
||||
A rosetree is a tree with a root whose children are themselves
|
||||
rosetrees.
|
||||
-}
|
||||
type RoseTree a
|
||||
= Rose a (LazyList (RoseTree a))
|
||||
|
||||
|
||||
{-| Make a singleton rosetree
|
||||
-}
|
||||
singleton : a -> RoseTree a
|
||||
singleton a =
|
||||
Rose a LazyList.empty
|
||||
|
||||
|
||||
{-| Get the root of a rosetree
|
||||
-}
|
||||
root : RoseTree a -> a
|
||||
root (Rose a _) =
|
||||
a
|
||||
|
||||
|
||||
{-| Get the children of a rosetree
|
||||
-}
|
||||
children : RoseTree a -> LazyList (RoseTree a)
|
||||
children (Rose _ c) =
|
||||
c
|
||||
|
||||
|
||||
{-| Add a child to the rosetree.
|
||||
-}
|
||||
addChild : RoseTree a -> RoseTree a -> RoseTree a
|
||||
addChild child (Rose a c) =
|
||||
Rose a (child ::: c)
|
||||
|
||||
|
||||
{-| Map a function over a rosetree
|
||||
-}
|
||||
map : (a -> b) -> RoseTree a -> RoseTree b
|
||||
map f (Rose a c) =
|
||||
Rose (f a) (LazyList.map (map f) c)
|
||||
|
||||
|
||||
{-| Flatten a rosetree of rosetrees.
|
||||
-}
|
||||
flatten : RoseTree (RoseTree a) -> RoseTree a
|
||||
flatten (Rose (Rose a c) cs) =
|
||||
Rose a (c +++ LazyList.map flatten cs)
|
||||
307
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test.elm
vendored
Normal file
307
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test.elm
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
module Test exposing (Test, FuzzOptions, describe, test, filter, concat, fuzz, fuzz2, fuzz3, fuzz4, fuzz5, fuzzWith)
|
||||
|
||||
{-| A module containing functions for creating and managing tests.
|
||||
|
||||
@docs Test, test
|
||||
|
||||
## Organizing Tests
|
||||
|
||||
@docs describe, concat, filter
|
||||
|
||||
## Fuzz Testing
|
||||
|
||||
@docs fuzz, fuzz2, fuzz3, fuzz4, fuzz5, fuzzWith, FuzzOptions
|
||||
-}
|
||||
|
||||
import Test.Internal as Internal
|
||||
import Expect exposing (Expectation)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
|
||||
|
||||
{-| A test which has yet to be evaluated. When evaluated, it produces one
|
||||
or more [`Expectation`](../Expect#Expectation)s.
|
||||
|
||||
See [`test`](#test) and [`fuzz`](#fuzz) for some ways to create a `Test`.
|
||||
-}
|
||||
type alias Test =
|
||||
Internal.Test
|
||||
|
||||
|
||||
{-| Run each of the given tests.
|
||||
|
||||
concat [ testDecoder, testSorting ]
|
||||
-}
|
||||
concat : List Test -> Test
|
||||
concat =
|
||||
Internal.Batch
|
||||
|
||||
|
||||
{-| Remove any test unless its description satisfies the given predicate
|
||||
function. Nested descriptions added with [`describe`](#describe) are not considered.
|
||||
|
||||
describe "String.reverse"
|
||||
[ test "has no effect on a palindrome" testGoesHere
|
||||
, test "reverses a known string" anotherTest
|
||||
, fuzz string "restores the original string if you run it again" oneMore
|
||||
]
|
||||
|> Test.filter (String.contains "original")
|
||||
|
||||
-- only runs the final test
|
||||
|
||||
You can use this to focus on a specific test or two, silencing the failures of
|
||||
tests you don't want to work on yet, and then remove the call to `Test.filter`
|
||||
after you're done working on the tests.
|
||||
-}
|
||||
filter : (String -> Bool) -> Test -> Test
|
||||
filter =
|
||||
Internal.filter
|
||||
|
||||
|
||||
{-| Apply a description to a list of tests.
|
||||
|
||||
import Test exposing (describe, test, fuzz)
|
||||
import Fuzz exposing (int)
|
||||
import Expect
|
||||
|
||||
|
||||
describe "List"
|
||||
[ describe "reverse"
|
||||
[ test "has no effect on an empty list" <|
|
||||
\() ->
|
||||
List.reverse []
|
||||
|> Expect.toEqual []
|
||||
, fuzz int "has no effect on a one-item list" <|
|
||||
\num ->
|
||||
List.reverse [ num ]
|
||||
|> Expect.toEqual [ num ]
|
||||
]
|
||||
]
|
||||
-}
|
||||
describe : String -> List Test -> Test
|
||||
describe desc =
|
||||
Internal.Batch >> Internal.Labeled desc
|
||||
|
||||
|
||||
{-| Return a [`Test`](#Test) that evaluates a single
|
||||
[`Expectation`](../Expect#Expectation).
|
||||
|
||||
import Test exposing (fuzz)
|
||||
import Expect
|
||||
|
||||
|
||||
test "the empty list has 0 length" <|
|
||||
\() ->
|
||||
List.length []
|
||||
|> Expect.toEqual 0
|
||||
-}
|
||||
test : String -> (() -> Expectation) -> Test
|
||||
test desc thunk =
|
||||
Internal.Labeled desc (Internal.Test (\_ _ -> [ thunk () ]))
|
||||
|
||||
|
||||
{-| Options [`fuzzWith`](#fuzzWith) accepts. Currently there is only one but this
|
||||
API is designed so that it can accept more in the future.
|
||||
|
||||
### `runs`
|
||||
|
||||
The number of times to run each fuzz test. (Default is 100.)
|
||||
|
||||
import Test exposing (fuzzWith)
|
||||
import Fuzz exposing (list, int)
|
||||
import Expect
|
||||
|
||||
|
||||
fuzzWith { runs = 350 } (list int) "List.length should always be positive" <|
|
||||
-- This anonymous function will be run 350 times, each time with a
|
||||
-- randomly-generated fuzzList value. (It will always be a list of ints
|
||||
-- because of (list int) above.)
|
||||
\fuzzList ->
|
||||
fuzzList
|
||||
|> List.length
|
||||
|> Expect.atLeast 0
|
||||
-}
|
||||
type alias FuzzOptions =
|
||||
{ runs : Int }
|
||||
|
||||
|
||||
{-| Run a [`fuzz`](#fuzz) test with the given [`FuzzOptions`](#FuzzOptions).
|
||||
|
||||
Note that there is no `fuzzWith2`, but you can always pass more fuzz values in
|
||||
using [`Fuzz.tuple`](../Fuzz#tuple), [`Fuzz.tuple3`](../Fuzz#tuple3),
|
||||
for example like this:
|
||||
|
||||
import Test exposing (fuzzWith)
|
||||
import Fuzz exposing (tuple, list, int)
|
||||
import Expect
|
||||
|
||||
|
||||
fuzzWith { runs = 4200 }
|
||||
(tuple ( list int, int ))
|
||||
"List.reverse never influences List.member" <|
|
||||
\(nums, target) ->
|
||||
List.member target (List.reverse nums)
|
||||
|> Expect.toEqual (List.member target nums)
|
||||
-}
|
||||
fuzzWith : FuzzOptions -> Fuzzer a -> String -> (a -> Expectation) -> Test
|
||||
fuzzWith options fuzzer desc getTest =
|
||||
if options.runs < 1 then
|
||||
test desc <|
|
||||
\() ->
|
||||
Expect.fail ("Fuzz test run count must be at least 1, not " ++ toString options.runs)
|
||||
else
|
||||
fuzzWithHelp options (fuzz fuzzer desc getTest)
|
||||
|
||||
|
||||
fuzzWithHelp : FuzzOptions -> Test -> Test
|
||||
fuzzWithHelp options test =
|
||||
case test of
|
||||
Internal.Test run ->
|
||||
Internal.Test (\seed _ -> run seed options.runs)
|
||||
|
||||
Internal.Labeled label subTest ->
|
||||
Internal.Labeled label (fuzzWithHelp options subTest)
|
||||
|
||||
Internal.Batch tests ->
|
||||
tests
|
||||
|> List.map (fuzzWithHelp options)
|
||||
|> Internal.Batch
|
||||
|
||||
|
||||
{-| Take a function that produces a test, and calls it several (usually 100) times, using a randomly-generated input
|
||||
from a [`Fuzzer`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Fuzz) each time. This allows you to
|
||||
test that a property that should always be true is indeed true under a wide variety of conditions. The function also
|
||||
takes a string describing the test.
|
||||
|
||||
These are called "[fuzz tests](https://en.wikipedia.org/wiki/Fuzz_testing)" because of the randomness.
|
||||
You may find them elsewhere called [property-based tests](http://blog.jessitron.com/2013/04/property-based-testing-what-is-it.html),
|
||||
[generative tests](http://www.pivotaltracker.com/community/tracker-blog/generative-testing), or
|
||||
[QuickCheck-style tests](https://en.wikipedia.org/wiki/QuickCheck).
|
||||
|
||||
import Test exposing (fuzz)
|
||||
import Fuzz exposing (list, int)
|
||||
import Expect
|
||||
|
||||
|
||||
fuzz (list int) "List.length should always be positive" <|
|
||||
-- This anonymous function will be run 100 times, each time with a
|
||||
-- randomly-generated fuzzList value.
|
||||
\fuzzList ->
|
||||
fuzzList
|
||||
|> List.length
|
||||
|> Expect.atLeast 0
|
||||
-}
|
||||
fuzz :
|
||||
Fuzzer a
|
||||
-> String
|
||||
-> (a -> Expectation)
|
||||
-> Test
|
||||
fuzz =
|
||||
Internal.fuzzTest
|
||||
|
||||
|
||||
{-| Run a [fuzz test](#fuzz) using two random inputs.
|
||||
|
||||
This is a convenience function that lets you skip calling [`Fuzz.tuple`](../Fuzz#tuple).
|
||||
|
||||
See [`fuzzWith`](#fuzzWith) for an example of writing this in tuple style.
|
||||
|
||||
import Test exposing (fuzz2)
|
||||
import Fuzz exposing (list, int)
|
||||
|
||||
|
||||
fuzz2 (list int) int "List.reverse never influences List.member" <|
|
||||
\nums target ->
|
||||
List.member target (List.reverse nums)
|
||||
|> Expect.toEqual (List.member target nums)
|
||||
-}
|
||||
fuzz2 :
|
||||
Fuzzer a
|
||||
-> Fuzzer b
|
||||
-> String
|
||||
-> (a -> b -> Expectation)
|
||||
-> Test
|
||||
fuzz2 fuzzA fuzzB desc =
|
||||
let
|
||||
fuzzer =
|
||||
Fuzz.tuple ( fuzzA, fuzzB )
|
||||
in
|
||||
uncurry >> fuzz fuzzer desc
|
||||
|
||||
|
||||
{-| Run a [fuzz test](#fuzz) using three random inputs.
|
||||
|
||||
This is a convenience function that lets you skip calling [`Fuzz.tuple3`](../Fuzz#tuple3).
|
||||
-}
|
||||
fuzz3 :
|
||||
Fuzzer a
|
||||
-> Fuzzer b
|
||||
-> Fuzzer c
|
||||
-> String
|
||||
-> (a -> b -> c -> Expectation)
|
||||
-> Test
|
||||
fuzz3 fuzzA fuzzB fuzzC desc =
|
||||
let
|
||||
fuzzer =
|
||||
Fuzz.tuple3 ( fuzzA, fuzzB, fuzzC )
|
||||
in
|
||||
uncurry3 >> fuzz fuzzer desc
|
||||
|
||||
|
||||
{-| Run a [fuzz test](#fuzz) using four random inputs.
|
||||
|
||||
This is a convenience function that lets you skip calling [`Fuzz.tuple4`](../Fuzz#tuple4).
|
||||
-}
|
||||
fuzz4 :
|
||||
Fuzzer a
|
||||
-> Fuzzer b
|
||||
-> Fuzzer c
|
||||
-> Fuzzer d
|
||||
-> String
|
||||
-> (a -> b -> c -> d -> Expectation)
|
||||
-> Test
|
||||
fuzz4 fuzzA fuzzB fuzzC fuzzD desc =
|
||||
let
|
||||
fuzzer =
|
||||
Fuzz.tuple4 ( fuzzA, fuzzB, fuzzC, fuzzD )
|
||||
in
|
||||
uncurry4 >> fuzz fuzzer desc
|
||||
|
||||
|
||||
{-| Run a [fuzz test](#fuzz) using five random inputs.
|
||||
|
||||
This is a convenience function that lets you skip calling [`Fuzz.tuple5`](../Fuzz#tuple5).
|
||||
-}
|
||||
fuzz5 :
|
||||
Fuzzer a
|
||||
-> Fuzzer b
|
||||
-> Fuzzer c
|
||||
-> Fuzzer d
|
||||
-> Fuzzer e
|
||||
-> String
|
||||
-> (a -> b -> c -> d -> e -> Expectation)
|
||||
-> Test
|
||||
fuzz5 fuzzA fuzzB fuzzC fuzzD fuzzE desc =
|
||||
let
|
||||
fuzzer =
|
||||
Fuzz.tuple5 ( fuzzA, fuzzB, fuzzC, fuzzD, fuzzE )
|
||||
in
|
||||
uncurry5 >> fuzz fuzzer desc
|
||||
|
||||
|
||||
|
||||
-- INTERNAL HELPERS --
|
||||
|
||||
|
||||
uncurry3 : (a -> b -> c -> d) -> ( a, b, c ) -> d
|
||||
uncurry3 fn ( a, b, c ) =
|
||||
fn a b c
|
||||
|
||||
|
||||
uncurry4 : (a -> b -> c -> d -> e) -> ( a, b, c, d ) -> e
|
||||
uncurry4 fn ( a, b, c, d ) =
|
||||
fn a b c d
|
||||
|
||||
|
||||
uncurry5 : (a -> b -> c -> d -> e -> f) -> ( a, b, c, d, e ) -> f
|
||||
uncurry5 fn ( a, b, c, d, e ) =
|
||||
fn a b c d e
|
||||
16
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Expectation.elm
vendored
Normal file
16
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Expectation.elm
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
module Test.Expectation exposing (Expectation(..), withGiven)
|
||||
|
||||
|
||||
type Expectation
|
||||
= Pass
|
||||
| Fail String String
|
||||
|
||||
|
||||
withGiven : String -> Expectation -> Expectation
|
||||
withGiven given outcome =
|
||||
case outcome of
|
||||
Fail _ message ->
|
||||
Fail given message
|
||||
|
||||
Pass ->
|
||||
outcome
|
||||
133
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Internal.elm
vendored
Normal file
133
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Internal.elm
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
module Test.Internal exposing (Test(..), fuzzTest, filter)
|
||||
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Dict exposing (Dict)
|
||||
import Shrink exposing (Shrinker)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Fuzz.Internal exposing (unpackGenVal, unpackGenTree)
|
||||
import RoseTree exposing (RoseTree(..))
|
||||
import Lazy.List
|
||||
|
||||
|
||||
type Test
|
||||
= Test (Random.Seed -> Int -> List Expectation)
|
||||
| Labeled String Test
|
||||
| Batch (List Test)
|
||||
|
||||
|
||||
filter : (String -> Bool) -> Test -> Test
|
||||
filter =
|
||||
filterHelp False
|
||||
|
||||
|
||||
filterHelp : Bool -> (String -> Bool) -> Test -> Test
|
||||
filterHelp lastCheckPassed isKeepable test =
|
||||
case test of
|
||||
Test _ ->
|
||||
if lastCheckPassed then
|
||||
test
|
||||
else
|
||||
Batch []
|
||||
|
||||
Labeled desc labeledTest ->
|
||||
labeledTest
|
||||
|> filterHelp (isKeepable desc) isKeepable
|
||||
|> Labeled desc
|
||||
|
||||
Batch tests ->
|
||||
tests
|
||||
|> List.map (filterHelp lastCheckPassed isKeepable)
|
||||
|> Batch
|
||||
|
||||
|
||||
fuzzTest : Fuzzer a -> String -> (a -> Expectation) -> Test
|
||||
fuzzTest fuzzer desc getExpectation =
|
||||
{- Fuzz test algorithm with opt-in RoseTrees:
|
||||
Generate a single value by passing the fuzzer True (indicates skip shrinking)
|
||||
Run the test on that value. If it fails:
|
||||
Generate the rosetree by passing the fuzzer False *and the same random seed*
|
||||
Find the new failure by looking at the children for any shrunken values:
|
||||
If a shrunken value causes a failure, recurse on its children
|
||||
If no shrunken value replicates the failure, use the root
|
||||
Whether it passes or fails, do this n times
|
||||
-}
|
||||
let
|
||||
getFailures failures currentSeed remainingRuns =
|
||||
let
|
||||
genVal =
|
||||
unpackGenVal fuzzer
|
||||
|
||||
( value, nextSeed ) =
|
||||
Random.step genVal currentSeed
|
||||
|
||||
newFailures =
|
||||
case getExpectation value of
|
||||
Pass ->
|
||||
failures
|
||||
|
||||
failedExpectation ->
|
||||
let
|
||||
genTree =
|
||||
unpackGenTree fuzzer
|
||||
|
||||
( rosetree, nextSeedAgain ) =
|
||||
Random.step genTree currentSeed
|
||||
in
|
||||
shrinkAndAdd rosetree getExpectation failedExpectation failures
|
||||
in
|
||||
if remainingRuns == 1 then
|
||||
newFailures
|
||||
else
|
||||
getFailures newFailures nextSeed (remainingRuns - 1)
|
||||
|
||||
run seed runs =
|
||||
let
|
||||
-- Use a Dict so we don't report duplicate inputs.
|
||||
failures : Dict String Expectation
|
||||
failures =
|
||||
getFailures Dict.empty seed runs
|
||||
in
|
||||
-- Make sure if we passed, we don't do any more work.
|
||||
if Dict.isEmpty failures then
|
||||
[ Pass ]
|
||||
else
|
||||
failures
|
||||
|> Dict.toList
|
||||
|> List.map formatExpectation
|
||||
in
|
||||
Labeled desc (Test run)
|
||||
|
||||
|
||||
shrinkAndAdd : RoseTree a -> (a -> Expectation) -> Expectation -> Dict String Expectation -> Dict String Expectation
|
||||
shrinkAndAdd rootTree getExpectation rootsExpectation dict =
|
||||
-- Knowing that the root already failed, adds the shrunken failure to the dictionary
|
||||
let
|
||||
shrink oldExpectation (Rose root branches) =
|
||||
case Lazy.List.headAndTail branches of
|
||||
Just ( (Rose branch _) as rosetree, moreLazyRoseTrees ) ->
|
||||
-- either way, recurse with the most recent failing expectation, and failing input with its list of shrunken values
|
||||
case getExpectation branch of
|
||||
Pass ->
|
||||
shrink oldExpectation (Rose root moreLazyRoseTrees)
|
||||
|
||||
newExpectation ->
|
||||
shrink newExpectation rosetree
|
||||
|
||||
Nothing ->
|
||||
( root, oldExpectation )
|
||||
|
||||
( result, finalExpectation ) =
|
||||
shrink rootsExpectation rootTree
|
||||
in
|
||||
Dict.insert (toString result) finalExpectation dict
|
||||
|
||||
|
||||
formatExpectation : ( String, Expectation ) -> Expectation
|
||||
formatExpectation ( given, expectation ) =
|
||||
Test.Expectation.withGiven given expectation
|
||||
|
||||
|
||||
isFail : Expectation -> Bool
|
||||
isFail =
|
||||
(/=) Pass
|
||||
149
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Runner.elm
vendored
Normal file
149
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Test/Runner.elm
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
module Test.Runner exposing (Runnable, Runner(..), run, fromTest, formatLabels)
|
||||
|
||||
{-| A collection of functions used by authors of test runners. To run your
|
||||
own tests, you should use these runners; see the `README` for more information.
|
||||
|
||||
## Runner
|
||||
|
||||
@docs Runner, fromTest
|
||||
|
||||
## Runnable
|
||||
|
||||
@docs Runnable, run
|
||||
|
||||
## Formatting
|
||||
|
||||
@docs formatLabels
|
||||
-}
|
||||
|
||||
import Test exposing (Test)
|
||||
import Test.Internal as Internal
|
||||
import Expect exposing (Expectation)
|
||||
import Random.Pcg
|
||||
import String
|
||||
|
||||
|
||||
{-| An unevaluated test. Run it with [`run`](#run) to evaluate it into a
|
||||
list of `Expectation`s.
|
||||
-}
|
||||
type Runnable
|
||||
= Thunk (() -> List Expectation)
|
||||
|
||||
|
||||
{-| A structured test runner, incorporating:
|
||||
|
||||
* The expectations to run
|
||||
* The hierarchy of description strings that describe the results
|
||||
-}
|
||||
type Runner
|
||||
= Runnable Runnable
|
||||
| Labeled String Runner
|
||||
| Batch (List Runner)
|
||||
|
||||
|
||||
{-| Evaluate a [`Runnable`](#Runnable) to get a list of `Expectation`s.
|
||||
-}
|
||||
run : Runnable -> List Expectation
|
||||
run (Thunk fn) =
|
||||
fn ()
|
||||
|
||||
|
||||
{-| Convert a `Test` into a `Runner`.
|
||||
|
||||
In order to run any fuzz tests that the `Test` may have, it requires a default run count as well
|
||||
as an initial `Random.Pcg.Seed`. `100` is a good run count. To obtain a good random seed, pass a
|
||||
random 32-bit integer to `Random.Pcg.initialSeed`. You can obtain such an integer by running
|
||||
`Math.floor(Math.random()*0xFFFFFFFF)` in Node. It's typically fine to hard-code this value into
|
||||
your Elm code; it's easy and makes your tests reproducible.
|
||||
-}
|
||||
fromTest : Int -> Random.Pcg.Seed -> Test -> Runner
|
||||
fromTest runs seed test =
|
||||
if runs < 1 then
|
||||
Thunk (\() -> [ Expect.fail ("Test runner run count must be at least 1, not " ++ toString runs) ])
|
||||
|> Runnable
|
||||
else
|
||||
case test of
|
||||
Internal.Test run ->
|
||||
Thunk (\() -> run seed runs)
|
||||
|> Runnable
|
||||
|
||||
Internal.Labeled label subTest ->
|
||||
subTest
|
||||
|> fromTest runs seed
|
||||
|> Labeled label
|
||||
|
||||
Internal.Batch subTests ->
|
||||
subTests
|
||||
|> List.foldl (distributeSeeds runs) ( seed, [] )
|
||||
|> Tuple.second
|
||||
|> Batch
|
||||
|
||||
|
||||
distributeSeeds : Int -> Test -> ( Random.Pcg.Seed, List Runner ) -> ( Random.Pcg.Seed, List Runner )
|
||||
distributeSeeds runs test ( startingSeed, runners ) =
|
||||
case test of
|
||||
Internal.Test run ->
|
||||
let
|
||||
( seed, nextSeed ) =
|
||||
Random.Pcg.step Random.Pcg.independentSeed startingSeed
|
||||
in
|
||||
( nextSeed, runners ++ [ Runnable (Thunk (\() -> run seed runs)) ] )
|
||||
|
||||
Internal.Labeled label subTest ->
|
||||
let
|
||||
( nextSeed, nextRunners ) =
|
||||
distributeSeeds runs subTest ( startingSeed, [] )
|
||||
|
||||
finalRunners =
|
||||
List.map (Labeled label) nextRunners
|
||||
in
|
||||
( nextSeed, runners ++ finalRunners )
|
||||
|
||||
Internal.Batch tests ->
|
||||
let
|
||||
( nextSeed, nextRunners ) =
|
||||
List.foldl (distributeSeeds runs) ( startingSeed, [] ) tests
|
||||
in
|
||||
( nextSeed, [ Batch (runners ++ nextRunners) ] )
|
||||
|
||||
|
||||
{-| A standard way to format descriptiona and test labels, to keep things
|
||||
consistent across test runner implementations.
|
||||
|
||||
The HTML, Node, String, and Log runners all use this.
|
||||
|
||||
What it does:
|
||||
|
||||
* drop any labels that are empty strings
|
||||
* format the first label differently from the others
|
||||
* reverse the resulting list
|
||||
|
||||
[ "the actual test that failed"
|
||||
, "nested description failure"
|
||||
, "top-level description failure"
|
||||
]
|
||||
|> formatLabels ((++) "↓ ") ((++) "✗ ")
|
||||
|
||||
{-
|
||||
[ "↓ top-level description failure"
|
||||
, "↓ nested description failure"
|
||||
, "✗ the actual test that failed"
|
||||
]
|
||||
-}
|
||||
|
||||
-}
|
||||
formatLabels :
|
||||
(String -> format)
|
||||
-> (String -> format)
|
||||
-> List String
|
||||
-> List format
|
||||
formatLabels formatDescription formatTest labels =
|
||||
case List.filter (not << String.isEmpty) labels of
|
||||
[] ->
|
||||
[]
|
||||
|
||||
test :: descriptions ->
|
||||
descriptions
|
||||
|> List.map formatDescription
|
||||
|> (::) (formatTest test)
|
||||
|> List.reverse
|
||||
32
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Util.elm
vendored
Normal file
32
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/src/Util.elm
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
module Util exposing (..)
|
||||
|
||||
{-| This is where I'm sticking Random helper functions I don't want to add to Pcg.
|
||||
-}
|
||||
|
||||
import Random.Pcg exposing (..)
|
||||
import Array exposing (Array)
|
||||
import String
|
||||
|
||||
|
||||
rangeLengthList : Int -> Int -> Generator a -> Generator (List a)
|
||||
rangeLengthList minLength maxLength generator =
|
||||
(int minLength maxLength)
|
||||
|> andThen (\len -> list len generator)
|
||||
|
||||
|
||||
rangeLengthArray : Int -> Int -> Generator a -> Generator (Array a)
|
||||
rangeLengthArray minLength maxLength generator =
|
||||
rangeLengthList minLength maxLength generator
|
||||
|> map Array.fromList
|
||||
|
||||
|
||||
rangeLengthString : Int -> Int -> Generator Char -> Generator String
|
||||
rangeLengthString minLength maxLength charGenerator =
|
||||
(int minLength maxLength)
|
||||
|> andThen (lengthString charGenerator)
|
||||
|
||||
|
||||
lengthString : Generator Char -> Int -> Generator String
|
||||
lengthString charGenerator stringLength =
|
||||
list stringLength charGenerator
|
||||
|> map String.fromList
|
||||
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Main.elm
vendored
Normal file
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Main.elm
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
module Main exposing (..)
|
||||
|
||||
{-| HOW TO RUN THESE TESTS
|
||||
|
||||
$ npm test
|
||||
|
||||
Note that this always uses an initial seed of 902101337, since it can't do effects.
|
||||
-}
|
||||
|
||||
import Runner.Log
|
||||
import Html
|
||||
import Tests
|
||||
|
||||
|
||||
main : Program Never () msg
|
||||
main =
|
||||
Html.beginnerProgram
|
||||
{ model = ()
|
||||
, update = \_ _ -> ()
|
||||
, view = \() -> Html.text "Check the console for useful output!"
|
||||
}
|
||||
|> Runner.Log.run Tests.all
|
||||
6
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/README.md
vendored
Normal file
6
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/README.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
## Running the tests for elm-test itself
|
||||
|
||||
1. `cd` into this directory
|
||||
2. `npm install`
|
||||
3. `elm package install --yes`
|
||||
4. `npm test`
|
||||
76
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Runner/Log.elm
vendored
Normal file
76
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Runner/Log.elm
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
module Runner.Log exposing (run, runWithOptions)
|
||||
|
||||
{-| # Log Runner
|
||||
|
||||
Runs a test and outputs its results using `Debug.log`, then calls `Debug.crash`
|
||||
if there are any failures.
|
||||
|
||||
This is not the prettiest runner, but it is simple and cross-platform. For
|
||||
example, you can use it as a crude Node runner like so:
|
||||
|
||||
$ elm-make LogRunnerExample.elm --output=elm.js
|
||||
$ node elm.js
|
||||
|
||||
This will log the test results to the console, then exit with exit code 0
|
||||
if the tests all passed, and 1 if any failed.
|
||||
|
||||
@docs run, runWithOptions
|
||||
-}
|
||||
|
||||
import Random.Pcg as Random
|
||||
import Test exposing (Test)
|
||||
import Runner.String exposing (Summary)
|
||||
import String
|
||||
|
||||
|
||||
{-| Run the test using the default `Test.Runner.String` options.
|
||||
-}
|
||||
run : Test -> a -> a
|
||||
run test =
|
||||
Runner.String.run test
|
||||
|> logOutput
|
||||
|
||||
|
||||
{-| Run the test using the provided options.
|
||||
-}
|
||||
runWithOptions : Int -> Random.Seed -> Test -> a -> a
|
||||
runWithOptions runs seed test =
|
||||
Runner.String.runWithOptions runs seed test
|
||||
|> logOutput
|
||||
|
||||
|
||||
summarize : Summary -> String
|
||||
summarize { output, passed, failed } =
|
||||
let
|
||||
headline =
|
||||
if failed > 0 then
|
||||
output ++ "\n\nTEST RUN FAILED"
|
||||
else
|
||||
"TEST RUN PASSED"
|
||||
in
|
||||
String.join "\n"
|
||||
[ output
|
||||
, headline ++ "\n"
|
||||
, "Passed: " ++ toString passed
|
||||
, "Failed: " ++ toString failed
|
||||
]
|
||||
|
||||
|
||||
logOutput : Summary -> a -> a
|
||||
logOutput summary arg =
|
||||
let
|
||||
output =
|
||||
summarize summary ++ "\n\nExit code"
|
||||
|
||||
_ =
|
||||
if summary.failed > 0 then
|
||||
output
|
||||
|> (flip Debug.log 1)
|
||||
|> (\_ -> Debug.crash "FAILED TEST RUN")
|
||||
|> (\_ -> ())
|
||||
else
|
||||
output
|
||||
|> (flip Debug.log 0)
|
||||
|> (\_ -> ())
|
||||
in
|
||||
arg
|
||||
111
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Runner/String.elm
vendored
Normal file
111
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Runner/String.elm
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
module Runner.String exposing (Summary, run, runWithOptions)
|
||||
|
||||
{-| # String Runner
|
||||
|
||||
Run a test and present its results as a nicely-formatted String, along with
|
||||
a count of how many tests passed and failed.
|
||||
|
||||
Note that this always uses an initial seed of 902101337, since it can't do effects.
|
||||
|
||||
@docs Summary, run, runWithOptions
|
||||
-}
|
||||
|
||||
import Random.Pcg as Random
|
||||
import Test exposing (Test)
|
||||
import Expect exposing (Expectation)
|
||||
import String
|
||||
import Test.Runner exposing (Runner(..))
|
||||
|
||||
|
||||
{-| The output string, the number of passed tests,
|
||||
and the number of failed tests.
|
||||
-}
|
||||
type alias Summary =
|
||||
{ output : String, passed : Int, failed : Int }
|
||||
|
||||
|
||||
toOutput : Summary -> Runner -> Summary
|
||||
toOutput =
|
||||
flip (toOutputHelp [])
|
||||
|
||||
|
||||
toOutputHelp : List String -> Runner -> Summary -> Summary
|
||||
toOutputHelp labels runner summary =
|
||||
case runner of
|
||||
Runnable runnable ->
|
||||
Test.Runner.run runnable
|
||||
|> List.foldl fromExpectation summary
|
||||
|
||||
Labeled label subRunner ->
|
||||
toOutputHelp (label :: labels) subRunner summary
|
||||
|
||||
Batch runners ->
|
||||
List.foldl (toOutputHelp labels) summary runners
|
||||
|
||||
|
||||
fromExpectation : Expectation -> Summary -> Summary
|
||||
fromExpectation expectation summary =
|
||||
case Expect.getFailure expectation of
|
||||
Nothing ->
|
||||
{ summary | passed = summary.passed + 1 }
|
||||
|
||||
Just { given, message } ->
|
||||
let
|
||||
prefix =
|
||||
if String.isEmpty given then
|
||||
""
|
||||
else
|
||||
"Given " ++ given ++ "\n\n"
|
||||
|
||||
newOutput =
|
||||
"\n\n" ++ (prefix ++ indentLines message) ++ "\n"
|
||||
in
|
||||
{ output = summary.output ++ newOutput
|
||||
, failed = summary.failed + 1
|
||||
, passed = summary.passed
|
||||
}
|
||||
|
||||
|
||||
outputLabels : List String -> String
|
||||
outputLabels labels =
|
||||
labels
|
||||
|> Test.Runner.formatLabels ((++) "↓ ") ((++) "✗ ")
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
defaultSeed : Random.Seed
|
||||
defaultSeed =
|
||||
Random.initialSeed 902101337
|
||||
|
||||
|
||||
defaultRuns : Int
|
||||
defaultRuns =
|
||||
100
|
||||
|
||||
|
||||
indentLines : String -> String
|
||||
indentLines str =
|
||||
str
|
||||
|> String.split "\n"
|
||||
|> List.map ((++) " ")
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
{-| Run a test and return a tuple of the output message and the number of
|
||||
tests that failed.
|
||||
|
||||
Fuzz tests use a default run count of 100, and a fixed initial seed.
|
||||
-}
|
||||
run : Test -> Summary
|
||||
run =
|
||||
runWithOptions defaultRuns defaultSeed
|
||||
|
||||
|
||||
{-| Run a test and return a tuple of the output message and the number of
|
||||
tests that failed.
|
||||
-}
|
||||
runWithOptions : Int -> Random.Seed -> Test -> Summary
|
||||
runWithOptions runs seed test =
|
||||
test
|
||||
|> Test.Runner.fromTest runs seed
|
||||
|> toOutput { output = "", passed = 0, failed = 0 }
|
||||
229
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Tests.elm
vendored
Normal file
229
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/Tests.elm
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
module Tests exposing (all)
|
||||
|
||||
import Test exposing (..)
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Test.Internal as TI
|
||||
import Fuzz exposing (..)
|
||||
import Dict
|
||||
import Set
|
||||
import String
|
||||
import Expect
|
||||
import Fuzz.Internal
|
||||
import RoseTree
|
||||
import Random.Pcg as Random
|
||||
|
||||
|
||||
all : Test
|
||||
all =
|
||||
Test.concat
|
||||
[ readmeExample, bug39, fuzzerTests, shrinkingTests ]
|
||||
|
||||
|
||||
{-| Regression test for https://github.com/elm-community/elm-test/issues/39
|
||||
-}
|
||||
bug39 : Test
|
||||
bug39 =
|
||||
fuzz (intRange 1 32) "small slice end" <|
|
||||
\positiveInt ->
|
||||
positiveInt
|
||||
|> Expect.greaterThan 0
|
||||
|
||||
|
||||
readmeExample : Test
|
||||
readmeExample =
|
||||
describe "The String module"
|
||||
[ describe "String.reverse"
|
||||
[ test "has no effect on a palindrome" <|
|
||||
\() ->
|
||||
let
|
||||
palindrome =
|
||||
"hannah"
|
||||
in
|
||||
Expect.equal palindrome (String.reverse palindrome)
|
||||
, test "reverses a known string" <|
|
||||
\() ->
|
||||
"ABCDEFG"
|
||||
|> String.reverse
|
||||
|> Expect.equal "GFEDCBA"
|
||||
, test "equal lists" <|
|
||||
\() ->
|
||||
[ 1, 2, 3 ]
|
||||
|> Expect.equalLists [ 1, 2, 3 ]
|
||||
, test "equal dicts" <|
|
||||
\() ->
|
||||
(Dict.fromList [ ( 1, "one" ), ( 2, "two" ) ])
|
||||
|> Expect.equalDicts (Dict.fromList [ ( 1, "one" ), ( 2, "two" ) ])
|
||||
, test "equal sets" <|
|
||||
\() ->
|
||||
(Set.fromList [ 1, 2, 3 ])
|
||||
|> Expect.equalSets (Set.fromList [ 1, 2, 3 ])
|
||||
, fuzz string "restores the original string if you run it again" <|
|
||||
\randomlyGeneratedString ->
|
||||
randomlyGeneratedString
|
||||
|> String.reverse
|
||||
|> String.reverse
|
||||
|> Expect.equal randomlyGeneratedString
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
testStringLengthIsPreserved : List String -> Expectation
|
||||
testStringLengthIsPreserved strings =
|
||||
strings
|
||||
|> List.map String.length
|
||||
|> List.sum
|
||||
|> Expect.equal (String.length (List.foldl (++) "" strings))
|
||||
|
||||
|
||||
fuzzerTests : Test
|
||||
fuzzerTests =
|
||||
describe "Fuzzer methods that use Debug.crash don't call it"
|
||||
[ describe "FuzzN (uses tupleN) testing string length properties"
|
||||
[ fuzz2 string string "fuzz2" <|
|
||||
\a b ->
|
||||
testStringLengthIsPreserved [ a, b ]
|
||||
, fuzz3 string string string "fuzz3" <|
|
||||
\a b c ->
|
||||
testStringLengthIsPreserved [ a, b, c ]
|
||||
, fuzz4 string string string string "fuzz4" <|
|
||||
\a b c d ->
|
||||
testStringLengthIsPreserved [ a, b, c, d ]
|
||||
, fuzz5 string string string string string "fuzz5" <|
|
||||
\a b c d e ->
|
||||
testStringLengthIsPreserved [ a, b, c, d, e ]
|
||||
]
|
||||
, fuzz
|
||||
(intRange 1 6)
|
||||
"intRange"
|
||||
(Expect.greaterThan 0)
|
||||
, fuzz
|
||||
(frequencyOrCrash [ ( 1, intRange 1 6 ), ( 1, intRange 1 20 ) ])
|
||||
"Fuzz.frequency(OrCrash)"
|
||||
(Expect.greaterThan 0)
|
||||
, fuzz (result string int) "Fuzz.result" <| \r -> Expect.pass
|
||||
, fuzz (andThen (\i -> intRange 0 (2 ^ i)) (intRange 1 8))
|
||||
"Fuzz.andThen"
|
||||
(Expect.atMost 256)
|
||||
, describe "Whitebox testing using Fuzz.Internal"
|
||||
[ fuzz (intRange 0 0xFFFFFFFF) "the same value is generated with and without shrinking" <|
|
||||
\i ->
|
||||
let
|
||||
seed =
|
||||
Random.initialSeed i
|
||||
|
||||
step gen =
|
||||
Random.step gen seed
|
||||
|
||||
aFuzzer =
|
||||
tuple5
|
||||
( tuple ( list int, array float )
|
||||
, maybe bool
|
||||
, result unit char
|
||||
, tuple3
|
||||
( percentage
|
||||
, map2 (+) int int
|
||||
, frequencyOrCrash [ ( 1, constant True ), ( 3, constant False ) ]
|
||||
)
|
||||
, tuple3 ( intRange 0 100, floatRange -51 pi, map abs int )
|
||||
)
|
||||
|
||||
valNoShrink =
|
||||
aFuzzer |> Fuzz.Internal.unpackGenVal |> step |> Tuple.first
|
||||
|
||||
valWithShrink =
|
||||
aFuzzer |> Fuzz.Internal.unpackGenTree |> step |> Tuple.first |> RoseTree.root
|
||||
in
|
||||
Expect.equal valNoShrink valWithShrink
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
testShrinking : Test -> Test
|
||||
testShrinking test =
|
||||
case test of
|
||||
TI.Test runTest ->
|
||||
TI.Test
|
||||
(\seed runs ->
|
||||
let
|
||||
expectations =
|
||||
runTest seed runs
|
||||
|
||||
goodShrink expectation =
|
||||
case expectation of
|
||||
Pass ->
|
||||
Just "Expected this test to fail, but it passed!"
|
||||
|
||||
Fail given outcome ->
|
||||
let
|
||||
acceptable =
|
||||
String.split "|" outcome
|
||||
in
|
||||
if List.member given acceptable then
|
||||
Nothing
|
||||
else
|
||||
Just <| "Got shrunken value " ++ given ++ " but expected " ++ String.join " or " acceptable
|
||||
in
|
||||
expectations
|
||||
|> List.filterMap goodShrink
|
||||
|> List.map Expect.fail
|
||||
|> (\list ->
|
||||
if List.isEmpty list then
|
||||
[ Expect.pass ]
|
||||
else
|
||||
list
|
||||
)
|
||||
)
|
||||
|
||||
TI.Labeled desc labeledTest ->
|
||||
TI.Labeled desc (testShrinking labeledTest)
|
||||
|
||||
TI.Batch tests ->
|
||||
TI.Batch (List.map testShrinking tests)
|
||||
|
||||
|
||||
shrinkingTests : Test
|
||||
shrinkingTests =
|
||||
testShrinking <|
|
||||
describe "Tests that fail intentionally to test shrinking"
|
||||
[ fuzz2 int int "Every pair of ints has a zero" <|
|
||||
\i j ->
|
||||
(i == 0)
|
||||
|| (j == 0)
|
||||
|> Expect.true "(1,1)"
|
||||
, fuzz3 int int int "Every triple of ints has a zero" <|
|
||||
\i j k ->
|
||||
(i == 0)
|
||||
|| (j == 0)
|
||||
|| (k == 0)
|
||||
|> Expect.true "(1,1,1)"
|
||||
, fuzz4 int int int int "Every 4-tuple of ints has a zero" <|
|
||||
\i j k l ->
|
||||
(i == 0)
|
||||
|| (j == 0)
|
||||
|| (k == 0)
|
||||
|| (l == 0)
|
||||
|> Expect.true "(1,1,1,1)"
|
||||
, fuzz5 int int int int int "Every 5-tuple of ints has a zero" <|
|
||||
\i j k l m ->
|
||||
(i == 0)
|
||||
|| (j == 0)
|
||||
|| (k == 0)
|
||||
|| (l == 0)
|
||||
|| (m == 0)
|
||||
|> Expect.true "(1,1,1,1,1)"
|
||||
, fuzz (list int) "All lists are sorted" <|
|
||||
\aList ->
|
||||
let
|
||||
checkPair l =
|
||||
case l of
|
||||
a :: b :: more ->
|
||||
if a > b then
|
||||
False
|
||||
else
|
||||
checkPair (b :: more)
|
||||
|
||||
_ ->
|
||||
True
|
||||
in
|
||||
checkPair aList |> Expect.true "[1,0]|[0,-1]"
|
||||
]
|
||||
19
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/elm-package.json
vendored
Normal file
19
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/elm-package.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "2.0.1",
|
||||
"summary": "tests for elm-test, so you can elm-test while you elm-test",
|
||||
"repository": "https://github.com/elm-community/elm-test.git",
|
||||
"license": "BSD-3-Clause",
|
||||
"source-directories": [
|
||||
".",
|
||||
"../src"
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"dependencies": {
|
||||
"elm-community/lazy-list": "1.0.0 <= v < 2.0.0",
|
||||
"elm-community/shrink": "2.0.0 <= v < 3.0.0",
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"elm-lang/html": "2.0.0 <= v < 3.0.0",
|
||||
"mgold/elm-random-pcg": "4.0.2 <= v < 5.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/package.json
vendored
Normal file
22
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/package.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "elm-test-tests",
|
||||
"version": "0.0.0",
|
||||
"description": "tests for elm-test, so you can elm-test while you elm-test",
|
||||
"main": "elm.js",
|
||||
"scripts": {
|
||||
"test": "node run-tests.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/elm-community/elm-test.git"
|
||||
},
|
||||
"author": "Richard Feldman",
|
||||
"license": "BSD-3-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/elm-community/elm-test/issues"
|
||||
},
|
||||
"homepage": "https://github.com/elm-community/elm-test#readme",
|
||||
"devDependencies": {
|
||||
"node-elm-compiler": "4.1.3"
|
||||
}
|
||||
}
|
||||
19
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/run-tests.js
vendored
Normal file
19
part9/tests/elm-stuff/packages/elm-community/elm-test/3.1.0/tests/run-tests.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
var compiler = require("node-elm-compiler")
|
||||
|
||||
testFile = "Main.elm"
|
||||
|
||||
compiler.compileToString([testFile], {}).then(function(str) {
|
||||
try {
|
||||
eval(str);
|
||||
|
||||
process.exit(0)
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
}).catch(function(err) {
|
||||
console.error(err);
|
||||
|
||||
process.exit(1)
|
||||
});
|
||||
Reference in New Issue
Block a user