Add part5
This commit is contained in:
5
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/.gitignore
vendored
Normal file
5
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*~
|
||||
node_modules/
|
||||
elm-stuff/
|
||||
docs/
|
||||
*.html
|
||||
46
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/.travis.yml
vendored
Normal file
46
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.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 TARGET_NODE_VERSION=node
|
||||
- ELM_VERSION=0.18.0 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
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/LICENSE
vendored
Normal file
27
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/LICENSE
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2016-2017 the Elm-test contributors
|
||||
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.
|
||||
152
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/README.md
vendored
Normal file
152
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/README.md
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
# 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/elm-community/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/Example.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/master/.travis.yml)
|
||||
* [`appveyor.yml`](https://github.com/rtfeldman/elm-css/blob/master/appveyor.yml)
|
||||
|
||||
### Not running tests
|
||||
|
||||
During development, you'll often want to focus on specific tests, silence failing tests, or jot down many ideas for tests that you can't implement all at once. We've got you covered with `skip`, `only`, and `todo`:
|
||||
|
||||
```elm
|
||||
wipSuite : Test
|
||||
wipSuite =
|
||||
describe "skip, only, and todo"
|
||||
[ only <| describe "Marking this test as `only` means no other tests will be run!"
|
||||
[ test "This test will be run" <|
|
||||
\_ -> 1 + 1 |> Expect.equal 2
|
||||
, skip <| test "This test will be skipped, even though it's in an only!" <|
|
||||
\_ -> 2 + 3 |> Expect.equal 4
|
||||
]
|
||||
, test "This test will be skipped because it has no only" <|
|
||||
\_ -> "left" |> Expect.equal "right"
|
||||
, todo "Make sure all splines are reticulated"
|
||||
]
|
||||
```
|
||||
|
||||
If you run this example, or any suite that uses one of these three functions, it will result in an _incomplete_ test run. No tests failed, but you also didn't run your entire suite, so we can't call it a success either. Incomplete test runs are reported to CI systems as indistinguishable from failed test runs, to safeguard against accidentally committing a gutted test suite!
|
||||
|
||||
## Strategies for effective testing
|
||||
|
||||
1. [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.
|
||||
1. 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!
|
||||
1. If your API is difficult for you to test, it will be difficult for someone else to use. You are your API's first client.
|
||||
1. Prefer fuzz tests to unit tests, where possible. If you have a union type with a small number of values, list them all and map over the list with a unit test for each. Unit tests are also great for when you know the edge cases, and for regression tests.
|
||||
1. If you're writing a library that wraps an existing standard or protocol, use examples from the specification or docs as unit tests.
|
||||
1. 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.
|
||||
1. Tests should be small and focused: call the code under test and set an expectation about the result. Setup code should be moved into reusable functions, or custom fuzzers. For example, a test to remove an element from a data structure should be given a nonempty data structure; it should not have to create one itself.
|
||||
1. If you find yourself inspecting the fuzzed input and making different expectations based on it, split each code path into its own test with a fuzzer that makes only the right kind of values.
|
||||
1. Consider using [elm-verify-examples](https://github.com/stoeffel/elm-verify-examples) to extract examples in your docs into unit tests.
|
||||
1. 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!)
|
||||
1. 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.
|
||||
|
||||
### Application-specific techniques
|
||||
There are a few extra ideas that apply to testing webapps and reusable view packages:
|
||||
|
||||
1. Avoid importing your `Main` module. Most of your code belongs in other modules, so import those instead.
|
||||
1. Test your views using [elm-html-test](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest).
|
||||
1. To test effects, consider using [elm-testable](http://package.elm-lang.org/packages/rogeriochaves/elm-testable/latest).
|
||||
1. There is currently no Elm solution for integration or end-to-end testing. Use your favorite PhantomJS or Selenium webdriver, such as Capybara.
|
||||
|
||||
## Upgrading
|
||||
### From 3.1.0
|
||||
Make sure you grab the latest versions of the test runner that you are using:
|
||||
* `npm update -g elm-test`
|
||||
* `elm package install rtfeldman/html-test-runner`
|
||||
|
||||
`Fuzz.frequency` now fails the test if the frequency is invalid, rather than return a `Result`. If you are using this function, you can remove your `Err` handling code. More likely you are using `Fuzz.frequencyOrCrash`, which you can replace with `Fuzz.frequency`.
|
||||
|
||||
Instead of using `Test.filter` to avoid running tests, use `skip` and `only` (see above for documentation).
|
||||
|
||||
We now forbid tests and suites to have descriptions that are blank, or that are identical across siblings or parents and children. If you get failures from this, rename your tests to be clearer about what they're testing.
|
||||
|
||||
### 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 install the latest version (`npm update -g elm-test`) and pull down the new `Main.elm`: `curl -o tests/Main.elm https://raw.githubusercontent.com/rtfeldman/node-test-runner/3.0.1/templates/Main.elm`
|
||||
|
||||
### From 1.x and elm-check
|
||||
[`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 |
|
||||
| ------- | ----- |
|
||||
| [**4.0.0**](https://github.com/elm-community/elm-test/tree/4.0.0) | Add `only`, `skip`, `todo`; change `Fuzz.frequency` to fail rather than crash on bad input, disallow tests with blank or duplicate descriptions.
|
||||
| [**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
|
||||
88
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/Main.elm
vendored
Normal file
88
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/Main.elm
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
module Main exposing (..)
|
||||
|
||||
import Benchmark exposing (..)
|
||||
import Benchmark.Runner as Runner
|
||||
import Expect exposing (Expectation)
|
||||
import Random.Pcg
|
||||
import Snippets
|
||||
import Test.Internal exposing (Test(Labeled, Test))
|
||||
|
||||
|
||||
main : Runner.BenchmarkProgram
|
||||
main =
|
||||
Runner.program suite
|
||||
|
||||
|
||||
suite : Benchmark
|
||||
suite =
|
||||
describe "Fuzz"
|
||||
[ describe "int"
|
||||
[ benchmark "generating" (benchTest Snippets.intPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.intFail)
|
||||
]
|
||||
, describe "intRange"
|
||||
[ benchmark "generating" (benchTest Snippets.intRangePass)
|
||||
, benchmark "shrinking" (benchTest Snippets.intRangeFail)
|
||||
]
|
||||
, describe "string"
|
||||
[ benchmark "generating" (benchTest Snippets.stringPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.stringFail)
|
||||
]
|
||||
, describe "float"
|
||||
[ benchmark "generating" (benchTest Snippets.floatPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.floatFail)
|
||||
]
|
||||
, describe "bool"
|
||||
[ benchmark "generating" (benchTest Snippets.boolPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.boolFail)
|
||||
]
|
||||
, describe "char"
|
||||
[ benchmark "generating" (benchTest Snippets.charPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.charFail)
|
||||
]
|
||||
, describe "list of int"
|
||||
[ benchmark "generating" (benchTest Snippets.listIntPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.listIntFail)
|
||||
]
|
||||
, describe "maybe of int"
|
||||
[ benchmark "generating" (benchTest Snippets.maybeIntPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.maybeIntFail)
|
||||
]
|
||||
, describe "result of string and int"
|
||||
[ benchmark "generating" (benchTest Snippets.resultPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.resultFail)
|
||||
]
|
||||
, describe "map"
|
||||
[ benchmark "generating" (benchTest Snippets.mapPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.mapFail)
|
||||
]
|
||||
, describe "andMap"
|
||||
[ benchmark "generating" (benchTest Snippets.andMapPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.andMapFail)
|
||||
]
|
||||
, describe "map5"
|
||||
[ benchmark "generating" (benchTest Snippets.map5Pass)
|
||||
, benchmark "shrinking" (benchTest Snippets.map5Fail)
|
||||
]
|
||||
, describe "andThen"
|
||||
[ benchmark "generating" (benchTest Snippets.andThenPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.andThenFail)
|
||||
]
|
||||
, describe "conditional"
|
||||
[ benchmark "generating" (benchTest Snippets.conditionalPass)
|
||||
, benchmark "shrinking" (benchTest Snippets.conditionalFail)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
benchTest : Test -> (() -> List Expectation)
|
||||
benchTest test =
|
||||
case test of
|
||||
Test fn ->
|
||||
\_ -> fn (Random.Pcg.initialSeed 0) 10
|
||||
|
||||
Labeled _ test ->
|
||||
benchTest test
|
||||
|
||||
test ->
|
||||
Debug.crash <| "No support for benchmarking this type of test: " ++ toString test
|
||||
34
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/README.md
vendored
Normal file
34
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/README.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Benchmarks for elm-test
|
||||
|
||||
These are some benchmarks of the elm-test library built using the excellent [elm-benchmark](https://github.com/BrianHicks/elm-benchmark).
|
||||
|
||||
## How to run
|
||||
|
||||
```sh
|
||||
cd ./benchmarks
|
||||
elm-make Main.elm
|
||||
open index.html
|
||||
```
|
||||
|
||||
## How to use
|
||||
These benchmarks can help get an idea of the performance impact of a change in the elm-test code.
|
||||
Beware however that a fifty percent performance increase in these benchmarks will most likely not translate to a fifty percent faster tests for users.
|
||||
In real word scenario's the execution of the test body will have a significant impact on the running time of the test suite, an aspect we're not testing here because it's different for every test suite.
|
||||
To get a feeling for the impact your change has on actual test run times try running some real test suites with and without your changes.
|
||||
|
||||
## Benchmarking complete test suites
|
||||
These are some examples of test suites that contain a lot of fuzzer tests:
|
||||
- [elm-benchmark](https://github.com/BrianHicks/elm-benchmark)
|
||||
- [elm-nonempty-list](https://github.com/mgold/elm-nonempty-list)
|
||||
- [json-elm-schema](https://github.com/NoRedInk/json-elm-schema)
|
||||
|
||||
A tool you can use for benchmarking the suite is [bench](https://github.com/Gabriel439/bench).
|
||||
|
||||
To run the tests using your modified code (this only works if your modified version is backwards compatible with the version of elm-test currenlty in use by the test suite):
|
||||
- In your test suite directories `elm-package.json`:
|
||||
- Remove the dependency on `elm-test`.
|
||||
- Add dependecies of `elm-test` as dependencies of the test suite itself.
|
||||
- Add the path to your changed elm-test src directory to your `source-directories`.
|
||||
It will be something like `/<projects-dir>/elm-test/src`.
|
||||
- Run `elm-test` once to trigger compilation.
|
||||
- Now run `elm-test` with your benchmarking tool.
|
||||
250
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/Snippets.elm
vendored
Normal file
250
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/Snippets.elm
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
module Snippets exposing (..)
|
||||
|
||||
import Expect exposing (Expectation)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Test exposing (Test, fuzz)
|
||||
|
||||
|
||||
intPass : Test
|
||||
intPass =
|
||||
fuzz Fuzz.int "(passes) int" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
intFail : Test
|
||||
intFail =
|
||||
fuzz Fuzz.int "(fails) int" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
intRangePass : Test
|
||||
intRangePass =
|
||||
fuzz (Fuzz.intRange 10 100) "(passes) intRange" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
intRangeFail : Test
|
||||
intRangeFail =
|
||||
fuzz (Fuzz.intRange 10 100) "(fails) intRange" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
stringPass : Test
|
||||
stringPass =
|
||||
fuzz Fuzz.string "(passes) string" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
stringFail : Test
|
||||
stringFail =
|
||||
fuzz Fuzz.string "(fails) string" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
floatPass : Test
|
||||
floatPass =
|
||||
fuzz Fuzz.float "(passes) float" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
floatFail : Test
|
||||
floatFail =
|
||||
fuzz Fuzz.float "(fails) float" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
boolPass : Test
|
||||
boolPass =
|
||||
fuzz Fuzz.bool "(passes) bool" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
boolFail : Test
|
||||
boolFail =
|
||||
fuzz Fuzz.bool "(fails) bool" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
charPass : Test
|
||||
charPass =
|
||||
fuzz Fuzz.char "(passes) char" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
charFail : Test
|
||||
charFail =
|
||||
fuzz Fuzz.char "(fails) char" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
listIntPass : Test
|
||||
listIntPass =
|
||||
fuzz (Fuzz.list Fuzz.int) "(passes) list of int" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
listIntFail : Test
|
||||
listIntFail =
|
||||
fuzz (Fuzz.list Fuzz.int) "(fails) list of int" <|
|
||||
{- The empty list is the first value the list shrinker will try.
|
||||
If we immediately fail on that example than we're not doing a lot of shrinking.
|
||||
-}
|
||||
Expect.notEqual []
|
||||
|
||||
|
||||
maybeIntPass : Test
|
||||
maybeIntPass =
|
||||
fuzz (Fuzz.maybe Fuzz.int) "(passes) maybe of int" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
maybeIntFail : Test
|
||||
maybeIntFail =
|
||||
fuzz (Fuzz.maybe Fuzz.int) "(fails) maybe of int" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
resultPass : Test
|
||||
resultPass =
|
||||
fuzz (Fuzz.result Fuzz.string Fuzz.int) "(passes) result of string and int" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
|
||||
|
||||
resultFail : Test
|
||||
resultFail =
|
||||
fuzz (Fuzz.result Fuzz.string Fuzz.int) "(fails) result of string and int" <|
|
||||
\numbers ->
|
||||
Expect.fail "Failed"
|
||||
|
||||
|
||||
mapPass : Test
|
||||
mapPass =
|
||||
fuzz even "(passes) map" <|
|
||||
\_ -> Expect.pass
|
||||
|
||||
|
||||
mapFail : Test
|
||||
mapFail =
|
||||
fuzz even "(fails) map" <|
|
||||
\_ -> Expect.fail "Failed"
|
||||
|
||||
|
||||
andMapPass : Test
|
||||
andMapPass =
|
||||
fuzz person "(passes) andMap" <|
|
||||
\_ -> Expect.pass
|
||||
|
||||
|
||||
andMapFail : Test
|
||||
andMapFail =
|
||||
fuzz person "(fails) andMap" <|
|
||||
\_ -> Expect.fail "Failed"
|
||||
|
||||
|
||||
map5Pass : Test
|
||||
map5Pass =
|
||||
fuzz person2 "(passes) map5" <|
|
||||
\_ -> Expect.pass
|
||||
|
||||
|
||||
map5Fail : Test
|
||||
map5Fail =
|
||||
fuzz person2 "(fails) map5" <|
|
||||
\_ -> Expect.fail "Failed"
|
||||
|
||||
|
||||
andThenPass : Test
|
||||
andThenPass =
|
||||
fuzz (variableList 2 5 Fuzz.int) "(passes) andThen" <|
|
||||
\_ -> Expect.pass
|
||||
|
||||
|
||||
andThenFail : Test
|
||||
andThenFail =
|
||||
fuzz (variableList 2 5 Fuzz.int) "(fails) andThen" <|
|
||||
\_ -> Expect.fail "Failed"
|
||||
|
||||
|
||||
conditionalPass : Test
|
||||
conditionalPass =
|
||||
fuzz evenWithConditional "(passes) conditional" <|
|
||||
\_ -> Expect.pass
|
||||
|
||||
|
||||
conditionalFail : Test
|
||||
conditionalFail =
|
||||
fuzz evenWithConditional "(fails) conditional" <|
|
||||
\_ -> Expect.fail "Failed"
|
||||
|
||||
|
||||
type alias Person =
|
||||
{ firstName : String
|
||||
, lastName : String
|
||||
, age : Int
|
||||
, nationality : String
|
||||
, height : Float
|
||||
}
|
||||
|
||||
|
||||
person : Fuzzer Person
|
||||
person =
|
||||
Fuzz.map Person Fuzz.string
|
||||
|> Fuzz.andMap Fuzz.string
|
||||
|> Fuzz.andMap Fuzz.int
|
||||
|> Fuzz.andMap Fuzz.string
|
||||
|> Fuzz.andMap Fuzz.float
|
||||
|
||||
|
||||
person2 : Fuzzer Person
|
||||
person2 =
|
||||
Fuzz.map5 Person
|
||||
Fuzz.string
|
||||
Fuzz.string
|
||||
Fuzz.int
|
||||
Fuzz.string
|
||||
Fuzz.float
|
||||
|
||||
|
||||
even : Fuzzer Int
|
||||
even =
|
||||
Fuzz.map ((*) 2) Fuzz.int
|
||||
|
||||
|
||||
variableList : Int -> Int -> Fuzzer a -> Fuzzer (List a)
|
||||
variableList min max item =
|
||||
Fuzz.intRange min max
|
||||
|> Fuzz.andThen (\length -> List.repeat length item |> sequence)
|
||||
|
||||
|
||||
sequence : List (Fuzzer a) -> Fuzzer (List a)
|
||||
sequence fuzzers =
|
||||
List.foldl
|
||||
(Fuzz.map2 (::))
|
||||
(Fuzz.constant [])
|
||||
fuzzers
|
||||
|
||||
|
||||
evenWithConditional : Fuzzer Int
|
||||
evenWithConditional =
|
||||
Fuzz.intRange 1 6
|
||||
|> Fuzz.conditional
|
||||
{ retries = 3
|
||||
, fallback = (+) 1
|
||||
, condition = \n -> (n % 2) == 0
|
||||
}
|
||||
21
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/elm-package.json
vendored
Normal file
21
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/benchmarks/elm-package.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "helpful summary of your project, less than 80 characters",
|
||||
"repository": "https://github.com/user/project.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
".",
|
||||
"../src"
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"dependencies": {
|
||||
"BrianHicks/elm-benchmark": "1.0.2 <= v < 2.0.0",
|
||||
"eeue56/elm-lazy-list": "1.0.0 <= v < 2.0.0",
|
||||
"eeue56/elm-shrink": "1.0.0 <= v < 2.0.0",
|
||||
"elm-lang/core": "5.1.1 <= v < 6.0.0",
|
||||
"elm-lang/html": "2.0.0 <= v < 3.0.0",
|
||||
"eeue56/elm-lazy": "1.0.0 <= v < 2.0.0",
|
||||
"mgold/elm-random-pcg": "5.0.0 <= v < 6.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
24
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/elm-package.json
vendored
Normal file
24
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/elm-package.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"version": "4.1.1",
|
||||
"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",
|
||||
"Test.Runner.Failure",
|
||||
"Expect",
|
||||
"Fuzz"
|
||||
],
|
||||
"dependencies": {
|
||||
"eeue56/elm-lazy-list": "1.0.0 <= v < 2.0.0",
|
||||
"eeue56/elm-shrink": "1.0.0 <= v < 2.0.0",
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"eeue56/elm-lazy": "1.0.0 <= v < 2.0.0",
|
||||
"mgold/elm-random-pcg": "4.0.2 <= v < 6.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
819
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Expect.elm
vendored
Normal file
819
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Expect.elm
vendored
Normal file
@@ -0,0 +1,819 @@
|
||||
module Expect
|
||||
exposing
|
||||
( Expectation
|
||||
, FloatingPointTolerance(Absolute, AbsoluteOrRelative, Relative)
|
||||
, all
|
||||
, atLeast
|
||||
, atMost
|
||||
, equal
|
||||
, equalDicts
|
||||
, equalLists
|
||||
, equalSets
|
||||
, err
|
||||
, fail
|
||||
, false
|
||||
, greaterThan
|
||||
, lessThan
|
||||
, notEqual
|
||||
, notWithin
|
||||
, onFail
|
||||
, pass
|
||||
, true
|
||||
, within
|
||||
)
|
||||
|
||||
{-| 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)`
|
||||
- [Floating Point Comparisons](#floating-point-comparisons)
|
||||
|
||||
|
||||
## Basic Expectations
|
||||
|
||||
@docs Expectation, equal, notEqual, all
|
||||
|
||||
|
||||
## Numeric Comparisons
|
||||
|
||||
@docs lessThan, atMost, greaterThan, atLeast
|
||||
|
||||
|
||||
## Floating Point Comparisons
|
||||
|
||||
These functions allow you to compare `Float` values up to a specified rounding error, which may be relative, absolute,
|
||||
or both. For an in-depth look, see our [Guide to Floating Point Comparison](#guide-to-floating-point-comparison).
|
||||
|
||||
@docs FloatingPointTolerance, within, notWithin
|
||||
|
||||
|
||||
## Booleans
|
||||
|
||||
@docs true, false
|
||||
|
||||
|
||||
## Collections
|
||||
|
||||
@docs err, equalLists, equalDicts, equalSets
|
||||
|
||||
|
||||
## Customizing
|
||||
|
||||
These functions will let you build your own expectations.
|
||||
|
||||
@docs pass, fail, onFail
|
||||
|
||||
|
||||
## Guide to Floating Point Comparison
|
||||
|
||||
In general, if you are multiplying, you want relative tolerance, and if you're adding,
|
||||
you want absolute tolerance. If you are doing both, you want both kinds of tolerance,
|
||||
or to split the calculation into smaller parts for testing.
|
||||
|
||||
|
||||
### Absolute Tolerance
|
||||
|
||||
Let's say we want to figure out if our estimation of pi is precise enough.
|
||||
|
||||
Is `3.14` within `0.01` of `pi`? Yes, because `3.13 < pi < 3.15`.
|
||||
|
||||
test "3.14 approximates pi with absolute precision" <| \_ ->
|
||||
3.14 |> Expect.within (Absolute 0.01) pi
|
||||
|
||||
|
||||
### Relative Tolerance
|
||||
|
||||
What if we also want to know if our circle circumference estimation is close enough?
|
||||
|
||||
Let's say our circle has a radius of `r` meters. The formula for circle circumference is `C=2*r*pi`.
|
||||
To make the calculations a bit easier ([ahem](https://tauday.com/tau-manifesto)), we'll look at half the circumference; `C/2=r*pi`.
|
||||
Is `r * 3.14` within `0.01` of `r * pi`?
|
||||
That depends, what does `r` equal? If `r` is `0.01`mm, or `0.00001` meters, we're comparing
|
||||
`0.00001 * 3.14 - 0.01 < r * pi < 0.00001 * 3.14 + 0.01` or `-0.0099686 < 0.0000314159 < 0.0100314`.
|
||||
That's a huge tolerance! A circumference that is _a thousand times longer_ than we expected would pass that test!
|
||||
|
||||
On the other hand, if `r` is very large, we're going to need many more digits of pi.
|
||||
For an absolute tolerance of `0.01` and a pi estimation of `3.14`, this expectation only passes if `r < 2*pi`.
|
||||
|
||||
If we use a relative tolerance of `0.01` instead, the circle area comparison becomes much better. Is `r * 3.14` within
|
||||
`1%` of `r * pi`? Yes! In fact, three digits of pi approximation is always good enough for a 0.1% relative tolerance,
|
||||
as long as `r` isn't [too close to zero](https://en.wikipedia.org/wiki/Denormal_number).
|
||||
|
||||
fuzz
|
||||
(floatRange 0.000001 100000)
|
||||
"Circle half-circumference with relative tolerance"
|
||||
(\r -> r * 3.14 |> Expect.within (Relative 0.001) (r * pi))
|
||||
|
||||
|
||||
### Trouble with Numbers Near Zero
|
||||
|
||||
If you are adding things near zero, you probably want absolute tolerance. If you're comparing values between `-1` and `1`, you should consider using absolute tolerance.
|
||||
|
||||
For example: Is `1 + 2 - 3` within `1%` of `0`? Well, if `1`, `2` and `3` have any amount of rounding error, you might not get exactly zero. What is `1%` above and below `0`? Zero. We just lost all tolerance. Even if we hard-code the numbers, we might not get exactly zero; `0.1 + 0.2` rounds to a value just above `0.3`, since computers, counting in binary, cannot write down any of those three numbers using a finite number of digits, just like we cannot write `0.333...` exactly in base 10.
|
||||
|
||||
Another example is comparing values that are on either side of zero. `0.0001` is more than `100%` away from `-0.0001`. In fact, `infinity` is closer to `0.0001` than `0.0001` is to `-0.0001`, if you are using a relative tolerance. Twice as close, actually. So even though both `0.0001` and `-0.0001` could be considered very close to zero, they are very far apart relative to each other. The same argument applies for any number of zeroes.
|
||||
|
||||
-}
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import Set exposing (Set)
|
||||
import Test.Expectation
|
||||
import Test.Runner.Failure exposing (InvalidReason(..), Reason(..))
|
||||
|
||||
|
||||
{-| 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 =
|
||||
equateWith "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 =
|
||||
equateWith "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" (>=)
|
||||
|
||||
|
||||
{-| A type to describe how close a floating point number must be to the expected value for the test to pass. This may be
|
||||
specified as absolute or relative.
|
||||
|
||||
`AbsoluteOrRelative` tolerance uses a logical OR between the absolute (specified first) and relative tolerance. If you
|
||||
want a logical AND, use [`Expect.all`](#all).
|
||||
|
||||
-}
|
||||
type FloatingPointTolerance
|
||||
= Absolute Float
|
||||
| Relative Float
|
||||
| AbsoluteOrRelative Float Float
|
||||
|
||||
|
||||
{-| Passes if the second and third arguments are equal within a tolerance
|
||||
specified by the first argument. This is intended to avoid failing because of
|
||||
minor inaccuracies introduced by floating point arithmetic.
|
||||
|
||||
-- Fails because 0.1 + 0.2 == 0.30000000000000004 (0.1 is non-terminating in base 2)
|
||||
0.1 + 0.2 |> Expect.equal 0.3
|
||||
|
||||
-- So instead write this test, which passes
|
||||
0.1 + 0.2 |> Expect.within (Absolute 0.000000001) 0.3
|
||||
|
||||
Failures resemble code written in pipeline style, so you can tell
|
||||
which argument is which:
|
||||
|
||||
-- Fails because 3.14 is not close enough to pi
|
||||
3.14 |> Expect.within (Absolute 0.0001) pi
|
||||
|
||||
{-
|
||||
|
||||
3.14
|
||||
╷
|
||||
│ Expect.within Absolute 0.0001
|
||||
╵
|
||||
3.141592653589793
|
||||
|
||||
-}
|
||||
|
||||
-}
|
||||
within : FloatingPointTolerance -> Float -> Float -> Expectation
|
||||
within tolerance a b =
|
||||
nonNegativeToleranceError tolerance "within" <|
|
||||
compareWith ("Expect.within " ++ toString tolerance)
|
||||
(withinCompare tolerance)
|
||||
a
|
||||
b
|
||||
|
||||
|
||||
{-| Passes if (and only if) a call to `within` with the same arguments would have failed.
|
||||
-}
|
||||
notWithin : FloatingPointTolerance -> Float -> Float -> Expectation
|
||||
notWithin tolerance a b =
|
||||
nonNegativeToleranceError tolerance "notWithin" <|
|
||||
compareWith ("Expect.notWithin " ++ toString tolerance)
|
||||
(\a b -> not <| withinCompare tolerance a b)
|
||||
a
|
||||
b
|
||||
|
||||
|
||||
{-| 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
|
||||
[`Result`](http://package.elm-lang.org/packages/elm-lang/core/latest/Result) is
|
||||
an `Err` rather than `Ok`. This is useful for tests where you expect to get an
|
||||
error but you don't care about what the actual error is. If your possibly
|
||||
erroring function returns a `Maybe`, simply use `Expect.equal Nothing`.
|
||||
|
||||
-- Passes
|
||||
String.toInt "not an int"
|
||||
|> Expect.err
|
||||
|
||||
Test failures will be printed with the unexpected `Ok` value contrasting with
|
||||
any `Err`.
|
||||
|
||||
-- Fails
|
||||
String.toInt "20"
|
||||
|> Expect.err
|
||||
|
||||
{-
|
||||
|
||||
Ok 20
|
||||
╷
|
||||
│ Expect.err
|
||||
╵
|
||||
Err _
|
||||
|
||||
-}
|
||||
|
||||
-}
|
||||
err : Result a b -> Expectation
|
||||
err result =
|
||||
case result of
|
||||
Ok _ ->
|
||||
{ description = "Expect.err"
|
||||
, reason = Comparison "Err _" (toString result)
|
||||
}
|
||||
|> Test.Expectation.fail
|
||||
|
||||
Err _ ->
|
||||
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
|
||||
{ description = "Expect.equalLists"
|
||||
, reason = ListDiff (List.map toString expected) (List.map toString actual)
|
||||
}
|
||||
|> Test.Expectation.fail
|
||||
|
||||
|
||||
{-| 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
|
||||
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
|
||||
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 str =
|
||||
Test.Expectation.fail { description = str, reason = Custom }
|
||||
|
||||
|
||||
{-| 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 failure ->
|
||||
Test.Expectation.Fail { failure | description = str, reason = Custom }
|
||||
|
||||
|
||||
{-| Passes if each of the given functions passes when applied to the subject.
|
||||
|
||||
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
|
||||
Test.Expectation.fail
|
||||
{ reason = Invalid EmptyList
|
||||
, description = "Expect.all was given an empty list. You must make at least one expectation to have a valid 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
|
||||
|
||||
|
||||
|
||||
{---- Private helper functions ----}
|
||||
|
||||
|
||||
reportFailure : String -> String -> String -> Expectation
|
||||
reportFailure comparison expected actual =
|
||||
{ description = comparison
|
||||
, reason = Comparison (toString expected) (toString actual)
|
||||
}
|
||||
|> Test.Expectation.fail
|
||||
|
||||
|
||||
reportCollectionFailure : String -> a -> b -> List c -> List d -> Expectation
|
||||
reportCollectionFailure comparison expected actual missingKeys extraKeys =
|
||||
{ description = comparison
|
||||
, reason =
|
||||
{ expected = toString expected
|
||||
, actual = toString actual
|
||||
, extra = List.map toString extraKeys
|
||||
, missing = List.map toString missingKeys
|
||||
}
|
||||
|> CollectionDiff
|
||||
}
|
||||
|> Test.Expectation.fail
|
||||
|
||||
|
||||
{-| String arg is label, e.g. "Expect.equal".
|
||||
-}
|
||||
equateWith : String -> (a -> b -> Bool) -> b -> a -> Expectation
|
||||
equateWith =
|
||||
testWith Equality
|
||||
|
||||
|
||||
compareWith : String -> (a -> b -> Bool) -> b -> a -> Expectation
|
||||
compareWith =
|
||||
testWith Comparison
|
||||
|
||||
|
||||
testWith : (String -> String -> Reason) -> String -> (a -> b -> Bool) -> b -> a -> Expectation
|
||||
testWith makeReason label runTest expected actual =
|
||||
if runTest actual expected then
|
||||
pass
|
||||
else
|
||||
{ description = label
|
||||
, reason = makeReason (toString expected) (toString actual)
|
||||
}
|
||||
|> Test.Expectation.fail
|
||||
|
||||
|
||||
|
||||
{---- Private *floating point* helper functions ----}
|
||||
|
||||
|
||||
absolute : FloatingPointTolerance -> Float
|
||||
absolute tolerance =
|
||||
case tolerance of
|
||||
Absolute absolute ->
|
||||
absolute
|
||||
|
||||
AbsoluteOrRelative absolute _ ->
|
||||
absolute
|
||||
|
||||
_ ->
|
||||
0
|
||||
|
||||
|
||||
relative : FloatingPointTolerance -> Float
|
||||
relative tolerance =
|
||||
case tolerance of
|
||||
Relative relative ->
|
||||
relative
|
||||
|
||||
AbsoluteOrRelative _ relative ->
|
||||
relative
|
||||
|
||||
_ ->
|
||||
0
|
||||
|
||||
|
||||
nonNegativeToleranceError : FloatingPointTolerance -> String -> Expectation -> Expectation
|
||||
nonNegativeToleranceError tolerance name result =
|
||||
if absolute tolerance < 0 && relative tolerance < 0 then
|
||||
Test.Expectation.fail { description = "Expect." ++ name ++ " was given negative absolute and relative tolerances", reason = Custom }
|
||||
else if absolute tolerance < 0 then
|
||||
Test.Expectation.fail { description = "Expect." ++ name ++ " was given a negative absolute tolerance", reason = Custom }
|
||||
else if relative tolerance < 0 then
|
||||
Test.Expectation.fail { description = "Expect." ++ name ++ " was given a negative relative tolerance", reason = Custom }
|
||||
else
|
||||
result
|
||||
|
||||
|
||||
withinCompare : FloatingPointTolerance -> Float -> Float -> Bool
|
||||
withinCompare tolerance a b =
|
||||
let
|
||||
withinAbsoluteTolerance =
|
||||
a - absolute tolerance <= b && b <= a + absolute tolerance
|
||||
|
||||
withinRelativeTolerance =
|
||||
(a * (1 - relative tolerance) <= b && b <= a * (1 + relative tolerance))
|
||||
|| (b * (1 - relative tolerance) <= a && a <= b * (1 + relative tolerance))
|
||||
in
|
||||
(a == b) || withinAbsoluteTolerance || withinRelativeTolerance
|
||||
78
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Float.elm
vendored
Normal file
78
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Float.elm
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
module Float
|
||||
exposing
|
||||
( epsilon
|
||||
, infinity
|
||||
, maxAbsValue
|
||||
, minAbsNormal
|
||||
, minAbsValue
|
||||
, nan
|
||||
)
|
||||
|
||||
{-| Float contains useful constants related to 64 bit floating point numbers,
|
||||
as specified in IEEE 754-2008.
|
||||
|
||||
@docs epsilon, infinity, nan, minAbsNormal, minAbsValue, maxAbsValue
|
||||
|
||||
-}
|
||||
|
||||
|
||||
{-| Largest possible rounding error in a single 64 bit floating point
|
||||
calculation on an x86-x64 CPU. Also known as the Machine Epsilon.
|
||||
|
||||
If you do not know what tolerance you should use, use this number, multiplied
|
||||
by the number of floating point operations you're doing in your calculation.
|
||||
|
||||
According to the [MSDN system.double.epsilon documentation]
|
||||
(<https://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx#Remarks>),
|
||||
ARM has a machine epsilon that is too small to represent in a 64 bit float,
|
||||
so we're simply ignoring that. On phones, tablets, raspberry pi's and other
|
||||
devices with ARM chips, you might get slightly better precision than we assume
|
||||
here.
|
||||
|
||||
-}
|
||||
epsilon : Float
|
||||
epsilon =
|
||||
2.0 ^ -52
|
||||
|
||||
|
||||
{-| Positive infinity. Negative infinity is just -infinity.
|
||||
-}
|
||||
infinity : Float
|
||||
infinity =
|
||||
1.0 / 0.0
|
||||
|
||||
|
||||
{-| Not a Number. NaN does not compare equal to anything, including itself.
|
||||
Any operation including NaN will result in NaN.
|
||||
-}
|
||||
nan : Float
|
||||
nan =
|
||||
0.0 / 0.0
|
||||
|
||||
|
||||
{-| Smallest possible value which still has full precision.
|
||||
|
||||
Values closer to zero are denormalized, which means that they are
|
||||
using some of the significant bits to emulate a slightly larger mantissa.
|
||||
The number of significant binary digits is proportional to the binary
|
||||
logarithm of the denormalized number; halving a denormalized number also
|
||||
halves the precision of that number.
|
||||
|
||||
-}
|
||||
minAbsNormal : Float
|
||||
minAbsNormal =
|
||||
2.0 ^ -1022
|
||||
|
||||
|
||||
{-| Smallest absolute value representable in a 64 bit float.
|
||||
-}
|
||||
minAbsValue : Float
|
||||
minAbsValue =
|
||||
2.0 ^ -1074
|
||||
|
||||
|
||||
{-| Largest finite absolute value representable in a 64 bit float.
|
||||
-}
|
||||
maxAbsValue : Float
|
||||
maxAbsValue =
|
||||
(2.0 - epsilon) * 2.0 ^ 1023
|
||||
748
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Fuzz.elm
vendored
Normal file
748
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Fuzz.elm
vendored
Normal file
@@ -0,0 +1,748 @@
|
||||
module Fuzz exposing (Fuzzer, andMap, andThen, array, bool, char, conditional, constant, custom, float, floatRange, frequency, int, intRange, invalid, list, map, map2, map3, map4, map5, maybe, oneOf, order, percentage, result, string, tuple, tuple3, tuple4, tuple5, unit)
|
||||
|
||||
{-| 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, conditional
|
||||
@docs Fuzzer, oneOf, constant, map, map2, map3, map4, map5, andMap, andThen, frequency, conditional
|
||||
|
||||
|
||||
## Tuple Fuzzers
|
||||
|
||||
Instead of using a tuple, consider using `fuzzN`.
|
||||
@docs tuple, tuple3, tuple4, tuple5
|
||||
|
||||
|
||||
## Uncommon Fuzzers
|
||||
|
||||
@docs custom, char, unit, order, invalid
|
||||
|
||||
-}
|
||||
|
||||
import Array exposing (Array)
|
||||
import Char
|
||||
import Fuzz.Internal as Internal
|
||||
exposing
|
||||
( Fuzzer
|
||||
, Valid
|
||||
, ValidFuzzer
|
||||
, combineValid
|
||||
, invalidReason
|
||||
)
|
||||
import Lazy
|
||||
import Lazy.List exposing ((+++), LazyList)
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import RoseTree exposing (RoseTree(..))
|
||||
import Shrink exposing (Shrinker)
|
||||
import Util exposing (..)
|
||||
|
||||
|
||||
{-| 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.lazy <| \_ -> Lazy.force <| Lazy.List.map shrinkTree (shrinker a))
|
||||
in
|
||||
Ok <|
|
||||
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 =
|
||||
RoseTree.singleton ()
|
||||
|> Random.constant
|
||||
|> Ok
|
||||
|
||||
|
||||
{-| 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 =
|
||||
if hi < lo then
|
||||
Err <| "Fuzz.intRange was given a lower bound of " ++ toString lo ++ " which is greater than the upper bound, " ++ toString hi ++ "."
|
||||
else
|
||||
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 =
|
||||
if hi < lo then
|
||||
Err <| "Fuzz.floatRange was given a lower bound of " ++ toString lo ++ " which is greater than the upper bound, " ++ toString hi ++ "."
|
||||
else
|
||||
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 and the extended character set.
|
||||
-}
|
||||
char : Fuzzer Char
|
||||
char =
|
||||
custom asciiCharGenerator Shrink.character
|
||||
|
||||
|
||||
asciiCharGenerator : Generator Char
|
||||
asciiCharGenerator =
|
||||
Random.map Char.fromCode (Random.int 32 126)
|
||||
|
||||
|
||||
whitespaceCharGenerator : Generator Char
|
||||
whitespaceCharGenerator =
|
||||
Random.sample [ ' ', '\t', '\n' ] |> Random.map (Maybe.withDefault ' ')
|
||||
|
||||
|
||||
{-| Generates random printable ASCII strings of up to 1000 characters.
|
||||
|
||||
Shorter strings are more common, especially the empty string.
|
||||
|
||||
-}
|
||||
string : Fuzzer String
|
||||
string =
|
||||
let
|
||||
asciiGenerator : Generator String
|
||||
asciiGenerator =
|
||||
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 asciiCharGenerator)
|
||||
|
||||
whitespaceGenerator : Generator String
|
||||
whitespaceGenerator =
|
||||
Random.int 1 10
|
||||
|> Random.andThen (lengthString whitespaceCharGenerator)
|
||||
in
|
||||
custom
|
||||
(Random.frequency
|
||||
[ ( 9, asciiGenerator )
|
||||
, ( 1, whitespaceGenerator )
|
||||
]
|
||||
)
|
||||
Shrink.string
|
||||
|
||||
|
||||
{-| Given a fuzzer of a type, create a fuzzer of a maybe for that type.
|
||||
-}
|
||||
maybe : Fuzzer a -> Fuzzer (Maybe a)
|
||||
maybe fuzzer =
|
||||
let
|
||||
toMaybe : Bool -> RoseTree a -> RoseTree (Maybe a)
|
||||
toMaybe useNothing tree =
|
||||
if useNothing then
|
||||
RoseTree.singleton Nothing
|
||||
else
|
||||
RoseTree.map Just tree |> RoseTree.addChild (RoseTree.singleton Nothing)
|
||||
in
|
||||
(Result.map << Random.map2 toMaybe) (Random.oneIn 4) fuzzer
|
||||
|
||||
|
||||
{-| 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 fuzzerError fuzzerValue =
|
||||
let
|
||||
toResult : Bool -> RoseTree error -> RoseTree value -> RoseTree (Result error value)
|
||||
toResult useError errorTree valueTree =
|
||||
if useError then
|
||||
RoseTree.map Err errorTree
|
||||
else
|
||||
RoseTree.map Ok valueTree
|
||||
in
|
||||
(Result.map2 <| Random.map3 toResult (Random.oneIn 4)) fuzzerError fuzzerValue
|
||||
|
||||
|
||||
{-| 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 fuzzer =
|
||||
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
|
||||
fuzzer
|
||||
|> Result.map
|
||||
(\validFuzzer ->
|
||||
genLength
|
||||
|> Random.andThen (flip Random.list validFuzzer)
|
||||
|> Random.map listShrinkHelp
|
||||
)
|
||||
|
||||
|
||||
listShrinkHelp : List (RoseTree a) -> RoseTree (List a)
|
||||
listShrinkHelp listOfTrees =
|
||||
{- This extends listShrinkRecurse algorithm with an attempt to shrink directly to the empty list. -}
|
||||
listShrinkRecurse listOfTrees
|
||||
|> mapChildren (Lazy.List.cons <| RoseTree.singleton [])
|
||||
|
||||
|
||||
mapChildren : (LazyList (RoseTree a) -> LazyList (RoseTree a)) -> RoseTree a -> RoseTree a
|
||||
mapChildren fn (Rose root children) =
|
||||
Rose root (fn children)
|
||||
|
||||
|
||||
listShrinkRecurse : List (RoseTree a) -> RoseTree (List a)
|
||||
listShrinkRecurse 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, remove elements at various positions in the list.
|
||||
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
|
||||
|
||||
dropFirstHalf : List (RoseTree a) -> RoseTree (List a)
|
||||
dropFirstHalf list_ =
|
||||
List.drop (List.length list_ // 2) list_
|
||||
|> listShrinkRecurse
|
||||
|
||||
dropSecondHalf : List (RoseTree a) -> RoseTree (List a)
|
||||
dropSecondHalf list_ =
|
||||
List.take (List.length list_ // 2) list_
|
||||
|> listShrinkRecurse
|
||||
|
||||
halved : LazyList (RoseTree (List a))
|
||||
halved =
|
||||
-- The list halving shortcut is useful only for large lists.
|
||||
-- For small lists attempting to remove elements one by one is good enough.
|
||||
if n >= 8 then
|
||||
Lazy.lazy <|
|
||||
\_ ->
|
||||
Lazy.List.fromList [ dropFirstHalf listOfTrees, dropSecondHalf listOfTrees ]
|
||||
|> Lazy.force
|
||||
else
|
||||
Lazy.List.empty
|
||||
|
||||
shrinkOne prefix list =
|
||||
case list of
|
||||
[] ->
|
||||
Lazy.List.empty
|
||||
|
||||
(Rose x shrunkenXs) :: more ->
|
||||
Lazy.List.map (\childTree -> prefix ++ (childTree :: more) |> listShrinkRecurse) shrunkenXs
|
||||
|
||||
shrunkenVals =
|
||||
Lazy.lazy <|
|
||||
\_ ->
|
||||
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))
|
||||
|> Lazy.force
|
||||
|
||||
shortened =
|
||||
Lazy.lazy <|
|
||||
\_ ->
|
||||
List.range 0 (n - 1)
|
||||
|> Lazy.List.fromList
|
||||
|> Lazy.List.map (\index -> removeOne index listOfTrees)
|
||||
|> Lazy.List.map listShrinkRecurse
|
||||
|> Lazy.force
|
||||
|
||||
removeOne index list =
|
||||
List.append
|
||||
(List.take index list)
|
||||
(List.drop (index + 1) list)
|
||||
in
|
||||
Rose root (halved +++ shortened +++ shrunkenVals)
|
||||
|
||||
|
||||
{-| 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 ( fuzzerA, fuzzerB ) =
|
||||
map2 (,) fuzzerA fuzzerB
|
||||
|
||||
|
||||
{-| Turn a 3-tuple of fuzzers into a fuzzer of 3-tuples.
|
||||
-}
|
||||
tuple3 : ( Fuzzer a, Fuzzer b, Fuzzer c ) -> Fuzzer ( a, b, c )
|
||||
tuple3 ( fuzzerA, fuzzerB, fuzzerC ) =
|
||||
map3 (,,) fuzzerA fuzzerB fuzzerC
|
||||
|
||||
|
||||
{-| 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 ( fuzzerA, fuzzerB, fuzzerC, fuzzerD ) =
|
||||
map4 (,,,) fuzzerA fuzzerB fuzzerC fuzzerD
|
||||
|
||||
|
||||
{-| 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 ( fuzzerA, fuzzerB, fuzzerC, fuzzerD, fuzzerE ) =
|
||||
map5 (,,,,) fuzzerA fuzzerB fuzzerC fuzzerD fuzzerE
|
||||
|
||||
|
||||
{-| 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 =
|
||||
Ok <| Random.constant (RoseTree.singleton x)
|
||||
|
||||
|
||||
{-| Map a function over a fuzzer. This applies to both the generated and the shrunken values.
|
||||
-}
|
||||
map : (a -> b) -> Fuzzer a -> Fuzzer b
|
||||
map =
|
||||
Internal.map
|
||||
|
||||
|
||||
{-| Map over two fuzzers.
|
||||
-}
|
||||
map2 : (a -> b -> c) -> Fuzzer a -> Fuzzer b -> Fuzzer c
|
||||
map2 transform fuzzA fuzzB =
|
||||
(Result.map2 << Random.map2 << map2RoseTree) transform fuzzA fuzzB
|
||||
|
||||
|
||||
{-| Map over three fuzzers.
|
||||
-}
|
||||
map3 : (a -> b -> c -> d) -> Fuzzer a -> Fuzzer b -> Fuzzer c -> Fuzzer d
|
||||
map3 transform fuzzA fuzzB fuzzC =
|
||||
(Result.map3 << Random.map3 << map3RoseTree) transform 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 =
|
||||
(Result.map4 << Random.map4 << map4RoseTree) transform 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 =
|
||||
(Result.map5 << Random.map5 << map5RoseTree) transform fuzzA fuzzB fuzzC fuzzD fuzzE
|
||||
|
||||
|
||||
{-| Map over many fuzzers. This can act as mapN for N > 5.
|
||||
The argument order is meant to accommodate 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 =
|
||||
Internal.andThen
|
||||
|
||||
|
||||
{-| Conditionally filter a fuzzer to remove occasional undesirable
|
||||
input. Takes a limit for how many retries to attempt, and a fallback
|
||||
function to, if no acceptable input can be found, create one from an
|
||||
unacceptable one. Also takes a condition to determine if the input is
|
||||
acceptable or not, and finally the fuzzer itself.
|
||||
|
||||
A good number of max retries is ten. A large number of retries might
|
||||
blow the stack.
|
||||
|
||||
-}
|
||||
conditional : { retries : Int, fallback : a -> a, condition : a -> Bool } -> Fuzzer a -> Fuzzer a
|
||||
conditional opts fuzzer =
|
||||
Result.map (conditionalHelper opts) fuzzer
|
||||
|
||||
|
||||
conditionalHelper : { retries : Int, fallback : a -> a, condition : a -> Bool } -> ValidFuzzer a -> ValidFuzzer a
|
||||
conditionalHelper opts validFuzzer =
|
||||
if opts.retries <= 0 then
|
||||
Random.map
|
||||
(RoseTree.map opts.fallback >> RoseTree.filterBranches opts.condition)
|
||||
validFuzzer
|
||||
else
|
||||
validFuzzer
|
||||
|> Random.andThen
|
||||
(\tree ->
|
||||
case RoseTree.filter opts.condition tree of
|
||||
Just tree ->
|
||||
Random.constant tree
|
||||
|
||||
Nothing ->
|
||||
conditionalHelper { opts | retries = opts.retries - 1 } validFuzzer
|
||||
)
|
||||
|
||||
|
||||
{-| 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 )
|
||||
]
|
||||
|
||||
There are a few circumstances in which this function will return an invalid
|
||||
fuzzer, which causes it to fail any test that uses it:
|
||||
|
||||
- If you provide an empty list of frequencies
|
||||
- If any of the weights are less than 0
|
||||
- If the weights sum to 0
|
||||
|
||||
Be careful recursively using this fuzzer in its arguments. Often using `map`
|
||||
is a better way to do what you want. If you are fuzzing a tree-like data
|
||||
structure, you should include a depth limit so to avoid infinite recursion, like
|
||||
so:
|
||||
|
||||
type Tree
|
||||
= Leaf
|
||||
| Branch Tree Tree
|
||||
|
||||
tree : Int -> Fuzzer Tree
|
||||
tree i =
|
||||
if i <= 0 then
|
||||
Fuzz.constant Leaf
|
||||
else
|
||||
Fuzz.frequency
|
||||
[ ( 1, Fuzz.constant Leaf )
|
||||
, ( 2, Fuzz.map2 Branch (tree (i - 1)) (tree (i - 1)) )
|
||||
]
|
||||
|
||||
-}
|
||||
frequency : List ( Float, Fuzzer a ) -> Fuzzer a
|
||||
frequency list =
|
||||
if List.isEmpty list then
|
||||
invalid "You must provide at least one frequency pair."
|
||||
else if List.any (\( weight, _ ) -> weight < 0) list then
|
||||
invalid "No frequency weights can be less than 0."
|
||||
else if List.sum (List.map Tuple.first list) <= 0 then
|
||||
invalid "Frequency weights must sum to more than 0."
|
||||
else
|
||||
list
|
||||
|> List.map extractValid
|
||||
|> combineValid
|
||||
|> Result.map Random.frequency
|
||||
|
||||
|
||||
extractValid : ( a, Valid b ) -> Valid ( a, b )
|
||||
extractValid ( a, valid ) =
|
||||
Result.map ((,) a) valid
|
||||
|
||||
|
||||
{-| Choose one of the given fuzzers at random. Each fuzzer has an equal chance
|
||||
of being chosen; to customize the probabilities, use [`frequency`](#frequency).
|
||||
|
||||
Fuzz.oneOf
|
||||
[ Fuzz.intRange 0 3
|
||||
, Fuzz.intRange 7 9
|
||||
]
|
||||
|
||||
-}
|
||||
oneOf : List (Fuzzer a) -> Fuzzer a
|
||||
oneOf list =
|
||||
if List.isEmpty list then
|
||||
invalid "You must pass at least one Fuzzer to Fuzz.oneOf."
|
||||
else
|
||||
list
|
||||
|> List.map (\fuzzer -> ( 1, fuzzer ))
|
||||
|> frequency
|
||||
|
||||
|
||||
{-| A fuzzer that is invalid for the provided reason. Any fuzzers built with it
|
||||
are also invalid. Any tests using an invalid fuzzer fail.
|
||||
-}
|
||||
invalid : String -> Fuzzer a
|
||||
invalid reason =
|
||||
Err reason
|
||||
|
||||
|
||||
map2RoseTree : (a -> b -> c) -> RoseTree a -> RoseTree b -> RoseTree c
|
||||
map2RoseTree transform ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) =
|
||||
{- Shrinking a pair of RoseTrees
|
||||
Recurse on all pairs 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 =
|
||||
transform root1 root2
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\subtree -> map2RoseTree transform subtree rose2) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\subtree -> map2RoseTree transform rose1 subtree) children2
|
||||
in
|
||||
Rose root (shrink1 +++ shrink2)
|
||||
|
||||
|
||||
|
||||
-- The RoseTree 'mapN, n > 2' functions below follow the same strategy as map2RoseTree.
|
||||
-- They're implemented separately instead of in terms of `andMap` because this has significant perfomance benefits.
|
||||
|
||||
|
||||
map3RoseTree : (a -> b -> c -> d) -> RoseTree a -> RoseTree b -> RoseTree c -> RoseTree d
|
||||
map3RoseTree transform ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) ((Rose root3 children3) as rose3) =
|
||||
let
|
||||
root =
|
||||
transform root1 root2 root3
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\childOf1 -> map3RoseTree transform childOf1 rose2 rose3) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\childOf2 -> map3RoseTree transform rose1 childOf2 rose3) children2
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\childOf3 -> map3RoseTree transform rose1 rose2 childOf3) children3
|
||||
in
|
||||
Rose root (shrink1 +++ shrink2 +++ shrink3)
|
||||
|
||||
|
||||
map4RoseTree : (a -> b -> c -> d -> e) -> RoseTree a -> RoseTree b -> RoseTree c -> RoseTree d -> RoseTree e
|
||||
map4RoseTree transform ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) ((Rose root3 children3) as rose3) ((Rose root4 children4) as rose4) =
|
||||
let
|
||||
root =
|
||||
transform root1 root2 root3 root4
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\childOf1 -> map4RoseTree transform childOf1 rose2 rose3 rose4) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\childOf2 -> map4RoseTree transform rose1 childOf2 rose3 rose4) children2
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\childOf3 -> map4RoseTree transform rose1 rose2 childOf3 rose4) children3
|
||||
|
||||
shrink4 =
|
||||
Lazy.List.map (\childOf4 -> map4RoseTree transform rose1 rose2 rose3 childOf4) children4
|
||||
in
|
||||
Rose root (shrink1 +++ shrink2 +++ shrink3 +++ shrink4)
|
||||
|
||||
|
||||
map5RoseTree : (a -> b -> c -> d -> e -> f) -> RoseTree a -> RoseTree b -> RoseTree c -> RoseTree d -> RoseTree e -> RoseTree f
|
||||
map5RoseTree transform ((Rose root1 children1) as rose1) ((Rose root2 children2) as rose2) ((Rose root3 children3) as rose3) ((Rose root4 children4) as rose4) ((Rose root5 children5) as rose5) =
|
||||
let
|
||||
root =
|
||||
transform root1 root2 root3 root4 root5
|
||||
|
||||
shrink1 =
|
||||
Lazy.List.map (\childOf1 -> map5RoseTree transform childOf1 rose2 rose3 rose4 rose5) children1
|
||||
|
||||
shrink2 =
|
||||
Lazy.List.map (\childOf2 -> map5RoseTree transform rose1 childOf2 rose3 rose4 rose5) children2
|
||||
|
||||
shrink3 =
|
||||
Lazy.List.map (\childOf3 -> map5RoseTree transform rose1 rose2 childOf3 rose4 rose5) children3
|
||||
|
||||
shrink4 =
|
||||
Lazy.List.map (\childOf4 -> map5RoseTree transform rose1 rose2 rose3 childOf4 rose5) children4
|
||||
|
||||
shrink5 =
|
||||
Lazy.List.map (\childOf5 -> map5RoseTree transform rose1 rose2 rose3 rose4 childOf5) children5
|
||||
in
|
||||
Rose root (shrink1 +++ shrink2 +++ shrink3 +++ shrink4 +++ shrink5)
|
||||
109
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Fuzz/Internal.elm
vendored
Normal file
109
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Fuzz/Internal.elm
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
module Fuzz.Internal exposing (Fuzzer, Valid, ValidFuzzer, andThen, combineValid, invalidReason, map)
|
||||
|
||||
import Lazy
|
||||
import Lazy.List exposing ((:::), LazyList)
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import RoseTree exposing (RoseTree(Rose))
|
||||
|
||||
|
||||
type alias Fuzzer a =
|
||||
Valid (ValidFuzzer a)
|
||||
|
||||
|
||||
type alias Valid a =
|
||||
Result String a
|
||||
|
||||
|
||||
type alias ValidFuzzer a =
|
||||
Generator (RoseTree a)
|
||||
|
||||
|
||||
combineValid : List (Valid a) -> Valid (List a)
|
||||
combineValid valids =
|
||||
case valids of
|
||||
[] ->
|
||||
Ok []
|
||||
|
||||
(Ok x) :: rest ->
|
||||
Result.map ((::) x) (combineValid rest)
|
||||
|
||||
(Err reason) :: _ ->
|
||||
Err reason
|
||||
|
||||
|
||||
map : (a -> b) -> Fuzzer a -> Fuzzer b
|
||||
map fn fuzzer =
|
||||
(Result.map << Random.map << RoseTree.map) fn fuzzer
|
||||
|
||||
|
||||
andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b
|
||||
andThen fn fuzzer =
|
||||
let
|
||||
helper : (a -> Fuzzer b) -> RoseTree a -> ValidFuzzer b
|
||||
helper fn xs =
|
||||
RoseTree.map fn xs
|
||||
|> removeInvalid
|
||||
|> sequenceRoseTree
|
||||
|> Random.map RoseTree.flatten
|
||||
in
|
||||
Result.map (Random.andThen (helper fn)) fuzzer
|
||||
|
||||
|
||||
removeInvalid : RoseTree (Valid a) -> RoseTree a
|
||||
removeInvalid tree =
|
||||
case RoseTree.filterMap getValid tree of
|
||||
Just newTree ->
|
||||
newTree
|
||||
|
||||
Nothing ->
|
||||
Debug.crash "Returning an invalid fuzzer from `andThen` is currently unsupported"
|
||||
|
||||
|
||||
sequenceRoseTree : RoseTree (Generator a) -> Generator (RoseTree a)
|
||||
sequenceRoseTree (Rose root branches) =
|
||||
Random.map2
|
||||
Rose
|
||||
root
|
||||
(Lazy.List.map sequenceRoseTree branches |> sequenceLazyList)
|
||||
|
||||
|
||||
sequenceLazyList : LazyList (Generator a) -> Generator (LazyList a)
|
||||
sequenceLazyList xs =
|
||||
Random.independentSeed
|
||||
|> Random.map (runAll xs)
|
||||
|
||||
|
||||
runAll : LazyList (Generator a) -> Random.Seed -> LazyList a
|
||||
runAll xs seed =
|
||||
Lazy.lazy <|
|
||||
\_ ->
|
||||
case Lazy.force xs of
|
||||
Lazy.List.Nil ->
|
||||
Lazy.List.Nil
|
||||
|
||||
Lazy.List.Cons firstGenerator rest ->
|
||||
let
|
||||
( x, newSeed ) =
|
||||
Random.step firstGenerator seed
|
||||
in
|
||||
Lazy.List.Cons x (runAll rest newSeed)
|
||||
|
||||
|
||||
getValid : Valid a -> Maybe a
|
||||
getValid valid =
|
||||
case valid of
|
||||
Ok x ->
|
||||
Just x
|
||||
|
||||
Err _ ->
|
||||
Nothing
|
||||
|
||||
|
||||
invalidReason : Valid a -> Maybe String
|
||||
invalidReason valid =
|
||||
case valid of
|
||||
Ok _ ->
|
||||
Nothing
|
||||
|
||||
Err reason ->
|
||||
Just reason
|
||||
91
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/RoseTree.elm
vendored
Normal file
91
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/RoseTree.elm
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
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)
|
||||
|
||||
|
||||
filter : (a -> Bool) -> RoseTree a -> Maybe (RoseTree a)
|
||||
filter predicate tree =
|
||||
let
|
||||
maybeKeep x =
|
||||
if predicate x then
|
||||
Just x
|
||||
else
|
||||
Nothing
|
||||
in
|
||||
filterMap maybeKeep tree
|
||||
|
||||
|
||||
{-| filterMap a function over a rosetree
|
||||
-}
|
||||
filterMap : (a -> Maybe b) -> RoseTree a -> Maybe (RoseTree b)
|
||||
filterMap f (Rose a c) =
|
||||
case f a of
|
||||
Just newA ->
|
||||
Just <| Rose newA (LazyList.filterMap (filterMap f) c)
|
||||
|
||||
Nothing ->
|
||||
Nothing
|
||||
|
||||
|
||||
filterBranches : (a -> Bool) -> RoseTree a -> RoseTree a
|
||||
filterBranches predicate (Rose root branches) =
|
||||
Rose
|
||||
root
|
||||
(LazyList.filterMap (filter predicate) branches)
|
||||
|
||||
|
||||
{-| Flatten a rosetree of rosetrees.
|
||||
-}
|
||||
flatten : RoseTree (RoseTree a) -> RoseTree a
|
||||
flatten (Rose (Rose a c) cs) =
|
||||
Rose a (c +++ LazyList.map flatten cs)
|
||||
474
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test.elm
vendored
Normal file
474
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test.elm
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
module Test exposing (FuzzOptions, Test, concat, describe, fuzz, fuzz2, fuzz3, fuzz4, fuzz5, fuzzWith, only, skip, test, todo)
|
||||
|
||||
{-| A module containing functions for creating and managing tests.
|
||||
|
||||
@docs Test, test
|
||||
|
||||
|
||||
## Organizing Tests
|
||||
|
||||
@docs describe, concat, todo, skip, only
|
||||
|
||||
|
||||
## Fuzz Testing
|
||||
|
||||
@docs fuzz, fuzz2, fuzz3, fuzz4, fuzz5, fuzzWith, FuzzOptions
|
||||
|
||||
-}
|
||||
|
||||
import Expect exposing (Expectation)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Set
|
||||
import Test.Fuzz
|
||||
import Test.Internal as Internal
|
||||
import Test.Runner.Failure exposing (InvalidReason(..), Reason(..))
|
||||
|
||||
|
||||
{-| 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 tests =
|
||||
if List.isEmpty tests then
|
||||
Internal.failNow
|
||||
{ description = "This `concat` has no tests in it. Let's give it some!"
|
||||
, reason = Invalid EmptyList
|
||||
}
|
||||
else
|
||||
case Internal.duplicatedName tests of
|
||||
Err duped ->
|
||||
Internal.failNow
|
||||
{ description = "A test group contains multiple tests named '" ++ duped ++ "'. Do some renaming so that tests have unique names."
|
||||
, reason = Invalid DuplicatedName
|
||||
}
|
||||
|
||||
Ok _ ->
|
||||
Internal.Batch tests
|
||||
|
||||
|
||||
{-| 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.equal []
|
||||
, fuzz int "has no effect on a one-item list" <|
|
||||
\num ->
|
||||
List.reverse [ num ]
|
||||
|> Expect.equal [ num ]
|
||||
]
|
||||
]
|
||||
|
||||
Passing an empty list will result in a failing test, because you either made a
|
||||
mistake or are creating a placeholder.
|
||||
|
||||
-}
|
||||
describe : String -> List Test -> Test
|
||||
describe untrimmedDesc tests =
|
||||
let
|
||||
desc =
|
||||
String.trim untrimmedDesc
|
||||
in
|
||||
if String.isEmpty desc then
|
||||
Internal.failNow
|
||||
{ description = "This `describe` has a blank description. Let's give it a useful one!"
|
||||
, reason = Invalid BadDescription
|
||||
}
|
||||
else if List.isEmpty tests then
|
||||
Internal.failNow
|
||||
{ description = "This `describe " ++ toString desc ++ "` has no tests in it. Let's give it some!"
|
||||
, reason = Invalid EmptyList
|
||||
}
|
||||
else
|
||||
case Internal.duplicatedName tests of
|
||||
Err duped ->
|
||||
Internal.failNow
|
||||
{ description = "The tests '" ++ desc ++ "' contain multiple tests named '" ++ duped ++ "'. Let's rename them so we know which is which."
|
||||
, reason = Invalid DuplicatedName
|
||||
}
|
||||
|
||||
Ok childrenNames ->
|
||||
if Set.member desc childrenNames then
|
||||
Internal.failNow
|
||||
{ description = "The test '" ++ desc ++ "' contains a child test of the same name. Let's rename them so we know which is which."
|
||||
, reason = Invalid DuplicatedName
|
||||
}
|
||||
else
|
||||
Internal.Labeled desc (Internal.Batch tests)
|
||||
|
||||
|
||||
{-| 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.equal 0
|
||||
|
||||
-}
|
||||
test : String -> (() -> Expectation) -> Test
|
||||
test untrimmedDesc thunk =
|
||||
let
|
||||
desc =
|
||||
String.trim untrimmedDesc
|
||||
in
|
||||
if String.isEmpty desc then
|
||||
Internal.blankDescriptionFailure
|
||||
else
|
||||
Internal.Labeled desc (Internal.UnitTest (\() -> [ thunk () ]))
|
||||
|
||||
|
||||
{-| Returns a [`Test`](#Test) that is "TODO" (not yet implemented). These tests
|
||||
always fail, but test runners will only include them in their output if there
|
||||
are no other failures.
|
||||
|
||||
These tests aren't meant to be committed to version control. Instead, use them
|
||||
when you're brainstorming lots of tests you'd like to write, but you can't
|
||||
implement them all at once. When you replace `todo` with a real test, you'll be
|
||||
able to see if it fails without clutter from tests still not implemented. But,
|
||||
unlike leaving yourself comments, you'll be prompted to implement these tests
|
||||
because your suite will fail.
|
||||
|
||||
describe "a new thing"
|
||||
[ todo "does what is expected in the common case"
|
||||
, todo "correctly handles an edge case I just thought of"
|
||||
]
|
||||
|
||||
This functionality is similar to "pending" tests in other frameworks, except
|
||||
that a TODO test is considered failing but a pending test often is not.
|
||||
|
||||
-}
|
||||
todo : String -> Test
|
||||
todo desc =
|
||||
Internal.failNow
|
||||
{ description = desc
|
||||
, reason = TODO
|
||||
}
|
||||
|
||||
|
||||
{-| Returns a [`Test`](#Test) that causes other tests to be skipped, and
|
||||
only runs the given one.
|
||||
|
||||
Calls to `only` aren't meant to be committed to version control. Instead, use
|
||||
them when you want to focus on getting a particular subset of your tests to pass.
|
||||
If you use `only`, your entire test suite will fail, even if
|
||||
each of the individual tests pass. This is to help avoid accidentally
|
||||
committing a `only` to version control.
|
||||
|
||||
If you you use `only` on multiple tests, only those tests will run. If you
|
||||
put a `only` inside another `only`, only the outermost `only`
|
||||
will affect which tests gets run.
|
||||
|
||||
See also [`skip`](#skip). Note that `skip` takes precedence over `only`;
|
||||
if you use a `skip` inside an `only`, it will still get skipped, and if you use
|
||||
an `only` inside a `skip`, it will also get skipped.
|
||||
|
||||
describe "List"
|
||||
[ only <| describe "reverse"
|
||||
[ test "has no effect on an empty list" <|
|
||||
\_ ->
|
||||
List.reverse []
|
||||
|> Expect.equal []
|
||||
, fuzz int "has no effect on a one-item list" <|
|
||||
\num ->
|
||||
List.reverse [ num ]
|
||||
|> Expect.equal [ num ]
|
||||
]
|
||||
, test "This will not get run, because of the `only` above!" <|
|
||||
\_ ->
|
||||
List.length []
|
||||
|> Expect.equal 0
|
||||
]
|
||||
|
||||
-}
|
||||
only : Test -> Test
|
||||
only =
|
||||
Internal.Only
|
||||
|
||||
|
||||
{-| Returns a [`Test`](#Test) that gets skipped.
|
||||
|
||||
Calls to `skip` aren't meant to be committed to version control. Instead, use
|
||||
it when you want to focus on getting a particular subset of your tests to
|
||||
pass. If you use `skip`, your entire test suite will fail, even if
|
||||
each of the individual tests pass. This is to help avoid accidentally
|
||||
committing a `skip` to version control.
|
||||
|
||||
See also [`only`](#only). Note that `skip` takes precedence over `only`;
|
||||
if you use a `skip` inside an `only`, it will still get skipped, and if you use
|
||||
an `only` inside a `skip`, it will also get skipped.
|
||||
|
||||
describe "List"
|
||||
[ skip <| describe "reverse"
|
||||
[ test "has no effect on an empty list" <|
|
||||
\_ ->
|
||||
List.reverse []
|
||||
|> Expect.equal []
|
||||
, fuzz int "has no effect on a one-item list" <|
|
||||
\num ->
|
||||
List.reverse [ num ]
|
||||
|> Expect.equal [ num ]
|
||||
]
|
||||
, test "This is the only test that will get run; the other was skipped!" <|
|
||||
\_ ->
|
||||
List.length []
|
||||
|> Expect.equal 0
|
||||
]
|
||||
|
||||
-}
|
||||
skip : Test -> Test
|
||||
skip =
|
||||
Internal.Skipped
|
||||
|
||||
|
||||
{-| 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.equal (List.member target nums)
|
||||
|
||||
-}
|
||||
fuzzWith : FuzzOptions -> Fuzzer a -> String -> (a -> Expectation) -> Test
|
||||
fuzzWith options fuzzer desc getTest =
|
||||
if options.runs < 1 then
|
||||
Internal.failNow
|
||||
{ description = "Fuzz tests must have a run count of at least 1, not " ++ toString options.runs ++ "."
|
||||
, reason = Invalid NonpositiveFuzzCount
|
||||
}
|
||||
else
|
||||
fuzzWithHelp options (fuzz fuzzer desc getTest)
|
||||
|
||||
|
||||
fuzzWithHelp : FuzzOptions -> Test -> Test
|
||||
fuzzWithHelp options test =
|
||||
case test of
|
||||
Internal.UnitTest _ ->
|
||||
test
|
||||
|
||||
Internal.FuzzTest run ->
|
||||
Internal.FuzzTest (\seed _ -> run seed options.runs)
|
||||
|
||||
Internal.Labeled label subTest ->
|
||||
Internal.Labeled label (fuzzWithHelp options subTest)
|
||||
|
||||
Internal.Skipped subTest ->
|
||||
-- It's important to treat skipped tests exactly the same as normal,
|
||||
-- until after seed distribution has completed.
|
||||
fuzzWithHelp options subTest
|
||||
|> Internal.Only
|
||||
|
||||
Internal.Only subTest ->
|
||||
fuzzWithHelp options subTest
|
||||
|> Internal.Only
|
||||
|
||||
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 =
|
||||
Test.Fuzz.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.equal (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
|
||||
27
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Expectation.elm
vendored
Normal file
27
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Expectation.elm
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
module Test.Expectation exposing (Expectation(..), fail, withGiven)
|
||||
|
||||
import Test.Runner.Failure exposing (Reason)
|
||||
|
||||
|
||||
type Expectation
|
||||
= Pass
|
||||
| Fail { given : Maybe String, description : String, reason : Reason }
|
||||
|
||||
|
||||
{-| Create a failure without specifying the given.
|
||||
-}
|
||||
fail : { description : String, reason : Reason } -> Expectation
|
||||
fail { description, reason } =
|
||||
Fail { given = Nothing, description = description, reason = reason }
|
||||
|
||||
|
||||
{-| Set the given (fuzz test input) of an expectation.
|
||||
-}
|
||||
withGiven : String -> Expectation -> Expectation
|
||||
withGiven newGiven expectation =
|
||||
case expectation of
|
||||
Fail failure ->
|
||||
Fail { failure | given = Just newGiven }
|
||||
|
||||
Pass ->
|
||||
expectation
|
||||
164
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Fuzz.elm
vendored
Normal file
164
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Fuzz.elm
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
module Test.Fuzz exposing (fuzzTest)
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Fuzz.Internal exposing (ValidFuzzer)
|
||||
import Lazy.List
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import RoseTree exposing (RoseTree(..))
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Test.Internal exposing (Test(..), blankDescriptionFailure, failNow)
|
||||
import Test.Runner.Failure exposing (InvalidReason(..), Reason(..))
|
||||
|
||||
|
||||
{-| Reject always-failing tests because of bad names or invalid fuzzers.
|
||||
-}
|
||||
fuzzTest : Fuzzer a -> String -> (a -> Expectation) -> Test
|
||||
fuzzTest fuzzer untrimmedDesc getExpectation =
|
||||
let
|
||||
desc =
|
||||
String.trim untrimmedDesc
|
||||
in
|
||||
if String.isEmpty desc then
|
||||
blankDescriptionFailure
|
||||
else
|
||||
case fuzzer of
|
||||
Err reason ->
|
||||
failNow
|
||||
{ description = reason
|
||||
, reason = Invalid InvalidFuzzer
|
||||
}
|
||||
|
||||
Ok validFuzzer ->
|
||||
-- Preliminary checks passed; run the fuzz test
|
||||
validatedFuzzTest validFuzzer desc getExpectation
|
||||
|
||||
|
||||
{-| Knowing that the fuzz test isn't obviously invalid, run the test and package up the results.
|
||||
-}
|
||||
validatedFuzzTest : ValidFuzzer a -> String -> (a -> Expectation) -> Test
|
||||
validatedFuzzTest fuzzer desc getExpectation =
|
||||
let
|
||||
run seed runs =
|
||||
let
|
||||
failures =
|
||||
getFailures fuzzer getExpectation 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 (FuzzTest run)
|
||||
|
||||
|
||||
type alias Failures =
|
||||
Dict String Expectation
|
||||
|
||||
|
||||
getFailures : ValidFuzzer a -> (a -> Expectation) -> Random.Seed -> Int -> Dict String Expectation
|
||||
getFailures fuzzer getExpectation initialSeed totalRuns =
|
||||
{- Fuzz test algorithm with memoization and opt-in RoseTrees:
|
||||
Generate a single value from the fuzzer's genVal random generator
|
||||
Determine if the value is memoized. If so, skip. Otherwise continue.
|
||||
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
|
||||
genVal =
|
||||
Random.map RoseTree.root fuzzer
|
||||
|
||||
initialFailures =
|
||||
Dict.empty
|
||||
|
||||
helper currentSeed remainingRuns failures =
|
||||
let
|
||||
( value, nextSeed ) =
|
||||
Random.step genVal currentSeed
|
||||
|
||||
newFailures =
|
||||
findNewFailure fuzzer getExpectation failures currentSeed value
|
||||
in
|
||||
if remainingRuns <= 1 then
|
||||
newFailures
|
||||
else
|
||||
helper nextSeed (remainingRuns - 1) newFailures
|
||||
in
|
||||
helper initialSeed totalRuns initialFailures
|
||||
|
||||
|
||||
{-| Knowing that a value in not in the cache, determine if it causes the test to pass or fail.
|
||||
-}
|
||||
findNewFailure :
|
||||
ValidFuzzer a
|
||||
-> (a -> Expectation)
|
||||
-> Failures
|
||||
-> Random.Seed
|
||||
-> a
|
||||
-> Failures
|
||||
findNewFailure fuzzer getExpectation failures currentSeed value =
|
||||
case getExpectation value of
|
||||
Pass ->
|
||||
failures
|
||||
|
||||
failedExpectation ->
|
||||
let
|
||||
( rosetree, nextSeed ) =
|
||||
-- nextSeed is not used here because caller function has currentSeed
|
||||
Random.step fuzzer currentSeed
|
||||
in
|
||||
shrinkAndAdd rosetree getExpectation failedExpectation failures
|
||||
|
||||
|
||||
{-| Knowing that the rosetree's root already failed, finds the shrunken failure.
|
||||
Returns the updated failures dictionary.
|
||||
-}
|
||||
shrinkAndAdd :
|
||||
RoseTree a
|
||||
-> (a -> Expectation)
|
||||
-> Expectation
|
||||
-> Failures
|
||||
-> Failures
|
||||
shrinkAndAdd rootTree getExpectation rootsExpectation failures =
|
||||
let
|
||||
shrink : Expectation -> RoseTree a -> ( a, Expectation )
|
||||
shrink oldExpectation (Rose failingValue branches) =
|
||||
case Lazy.List.headAndTail branches of
|
||||
Just ( (Rose possiblyFailingValue _) as rosetree, moreLazyRoseTrees ) ->
|
||||
-- either way, recurse with the most recent failing expectation, and failing input with its list of shrunken values
|
||||
case getExpectation possiblyFailingValue of
|
||||
Pass ->
|
||||
shrink oldExpectation
|
||||
(Rose failingValue moreLazyRoseTrees)
|
||||
|
||||
newExpectation ->
|
||||
let
|
||||
( minimalValue, finalExpectation ) =
|
||||
shrink newExpectation rosetree
|
||||
in
|
||||
( minimalValue
|
||||
, finalExpectation
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( failingValue, oldExpectation )
|
||||
|
||||
(Rose failingValue _) =
|
||||
rootTree
|
||||
|
||||
( minimalValue, finalExpectation ) =
|
||||
shrink rootsExpectation rootTree
|
||||
in
|
||||
Dict.insert (toString minimalValue) finalExpectation failures
|
||||
|
||||
|
||||
formatExpectation : ( String, Expectation ) -> Expectation
|
||||
formatExpectation ( given, expectation ) =
|
||||
Test.Expectation.withGiven given expectation
|
||||
69
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Internal.elm
vendored
Normal file
69
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Internal.elm
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
module Test.Internal exposing (Test(..), blankDescriptionFailure, duplicatedName, failNow)
|
||||
|
||||
import Random.Pcg as Random exposing (Generator)
|
||||
import Set exposing (Set)
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Test.Runner.Failure exposing (InvalidReason(..), Reason(..))
|
||||
|
||||
|
||||
type Test
|
||||
= UnitTest (() -> List Expectation)
|
||||
| FuzzTest (Random.Seed -> Int -> List Expectation)
|
||||
| Labeled String Test
|
||||
| Skipped Test
|
||||
| Only Test
|
||||
| Batch (List Test)
|
||||
|
||||
|
||||
{-| Create a test that always fails for the given reason and description.
|
||||
-}
|
||||
failNow : { description : String, reason : Reason } -> Test
|
||||
failNow record =
|
||||
UnitTest
|
||||
(\() -> [ Test.Expectation.fail record ])
|
||||
|
||||
|
||||
blankDescriptionFailure : Test
|
||||
blankDescriptionFailure =
|
||||
failNow
|
||||
{ description = "This test has a blank description. Let's give it a useful one!"
|
||||
, reason = Invalid BadDescription
|
||||
}
|
||||
|
||||
|
||||
duplicatedName : List Test -> Result String (Set String)
|
||||
duplicatedName =
|
||||
let
|
||||
names : Test -> List String
|
||||
names test =
|
||||
case test of
|
||||
Labeled str _ ->
|
||||
[ str ]
|
||||
|
||||
Batch subtests ->
|
||||
List.concatMap names subtests
|
||||
|
||||
UnitTest _ ->
|
||||
[]
|
||||
|
||||
FuzzTest _ ->
|
||||
[]
|
||||
|
||||
Skipped subTest ->
|
||||
names subTest
|
||||
|
||||
Only subTest ->
|
||||
names subTest
|
||||
|
||||
insertOrFail : String -> Result String (Set String) -> Result String (Set String)
|
||||
insertOrFail newName =
|
||||
Result.andThen
|
||||
(\oldNames ->
|
||||
if Set.member newName oldNames then
|
||||
Err newName
|
||||
else
|
||||
Ok <| Set.insert newName oldNames
|
||||
)
|
||||
in
|
||||
List.concatMap names
|
||||
>> List.foldl insertOrFail (Ok Set.empty)
|
||||
532
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Runner.elm
vendored
Normal file
532
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Runner.elm
vendored
Normal file
@@ -0,0 +1,532 @@
|
||||
module Test.Runner
|
||||
exposing
|
||||
( Runner
|
||||
, SeededRunners(..)
|
||||
, Shrinkable
|
||||
, formatLabels
|
||||
, fromTest
|
||||
, fuzz
|
||||
, getFailure
|
||||
, getFailureReason
|
||||
, isTodo
|
||||
, shrink
|
||||
)
|
||||
|
||||
{-| This is an "experts only" module that exposes functions needed to run and
|
||||
display tests. A typical user will use an existing runner library for Node or
|
||||
the browser, which is implemented using this interface. A list of these runners
|
||||
can be found in the `README`.
|
||||
|
||||
|
||||
## Runner
|
||||
|
||||
@docs Runner, SeededRunners, fromTest
|
||||
|
||||
|
||||
## Expectations
|
||||
|
||||
@docs getFailure, getFailureReason, isTodo
|
||||
|
||||
|
||||
## Formatting
|
||||
|
||||
@docs formatLabels
|
||||
|
||||
|
||||
## Fuzzers
|
||||
|
||||
These functions give you the ability to run fuzzers separate of running fuzz tests.
|
||||
|
||||
@docs Shrinkable, fuzz, shrink
|
||||
|
||||
-}
|
||||
|
||||
import Bitwise
|
||||
import Char
|
||||
import Expect exposing (Expectation)
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Lazy.List as LazyList exposing (LazyList)
|
||||
import Random.Pcg as Random
|
||||
import RoseTree exposing (RoseTree(Rose))
|
||||
import String
|
||||
import Test exposing (Test)
|
||||
import Test.Expectation
|
||||
import Test.Internal as Internal
|
||||
import Test.Runner.Failure exposing (Reason(..))
|
||||
|
||||
|
||||
{-| An unevaluated test. Run it with [`run`](#run) to evaluate it into a
|
||||
list of `Expectation`s.
|
||||
-}
|
||||
type Runnable
|
||||
= Thunk (() -> List Expectation)
|
||||
|
||||
|
||||
{-| A function which, when evaluated, produces a list of expectations. Also a
|
||||
list of labels which apply to this outcome.
|
||||
-}
|
||||
type alias Runner =
|
||||
{ run : () -> List Expectation
|
||||
, labels : List String
|
||||
}
|
||||
|
||||
|
||||
{-| A structured test runner, incorporating:
|
||||
|
||||
- The expectations to run
|
||||
- The hierarchy of description strings that describe the results
|
||||
|
||||
-}
|
||||
type RunnableTree
|
||||
= Runnable Runnable
|
||||
| Labeled String RunnableTree
|
||||
| Batch (List RunnableTree)
|
||||
|
||||
|
||||
{-| Convert a `Test` into `SeededRunners`.
|
||||
|
||||
In order to run any fuzz tests that the `Test` may have, it requires a default run count as well
|
||||
as an initial `Random.Seed`. `100` is a good run count. To obtain a good random seed, pass a
|
||||
random 32-bit integer to `Random.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.Seed -> Test -> SeededRunners
|
||||
fromTest runs seed test =
|
||||
if runs < 1 then
|
||||
Invalid ("Test runner run count must be at least 1, not " ++ toString runs)
|
||||
else
|
||||
let
|
||||
distribution =
|
||||
distributeSeeds runs seed test
|
||||
in
|
||||
if List.isEmpty distribution.only then
|
||||
if countAllRunnables distribution.skipped == 0 then
|
||||
distribution.all
|
||||
|> List.concatMap fromRunnableTree
|
||||
|> Plain
|
||||
else
|
||||
distribution.all
|
||||
|> List.concatMap fromRunnableTree
|
||||
|> Skipping
|
||||
else
|
||||
distribution.only
|
||||
|> List.concatMap fromRunnableTree
|
||||
|> Only
|
||||
|
||||
|
||||
countAllRunnables : List RunnableTree -> Int
|
||||
countAllRunnables =
|
||||
List.foldl (countRunnables >> (+)) 0
|
||||
|
||||
|
||||
countRunnables : RunnableTree -> Int
|
||||
countRunnables runnable =
|
||||
case runnable of
|
||||
Runnable _ ->
|
||||
1
|
||||
|
||||
Labeled _ runner ->
|
||||
countRunnables runner
|
||||
|
||||
Batch runners ->
|
||||
countAllRunnables runners
|
||||
|
||||
|
||||
run : Runnable -> List Expectation
|
||||
run (Thunk fn) =
|
||||
fn ()
|
||||
|
||||
|
||||
fromRunnableTree : RunnableTree -> List Runner
|
||||
fromRunnableTree =
|
||||
fromRunnableTreeHelp []
|
||||
|
||||
|
||||
fromRunnableTreeHelp : List String -> RunnableTree -> List Runner
|
||||
fromRunnableTreeHelp labels runner =
|
||||
case runner of
|
||||
Runnable runnable ->
|
||||
[ { labels = labels
|
||||
, run = \_ -> run runnable
|
||||
}
|
||||
]
|
||||
|
||||
Labeled label subRunner ->
|
||||
fromRunnableTreeHelp (label :: labels) subRunner
|
||||
|
||||
Batch runners ->
|
||||
List.concatMap (fromRunnableTreeHelp labels) runners
|
||||
|
||||
|
||||
type alias Distribution =
|
||||
{ seed : Random.Seed
|
||||
, only : List RunnableTree
|
||||
, all : List RunnableTree
|
||||
, skipped : List RunnableTree
|
||||
}
|
||||
|
||||
|
||||
{-| Test Runners which have had seeds distributed to them, and which are now
|
||||
either invalid or are ready to run. Seeded runners include some metadata:
|
||||
|
||||
- `Invalid` runners had a problem (e.g. two sibling tests had the same description) making them un-runnable.
|
||||
- `Only` runners can be run, but `Test.only` was used somewhere, so ultimately they will lead to a failed test run even if each test that gets run passes.
|
||||
- `Skipping` runners can be run, but `Test.skip` was used somewhere, so ultimately they will lead to a failed test run even if each test that gets run passes.
|
||||
- `Plain` runners are ready to run, and have none of these issues.
|
||||
|
||||
-}
|
||||
type SeededRunners
|
||||
= Plain (List Runner)
|
||||
| Only (List Runner)
|
||||
| Skipping (List Runner)
|
||||
| Invalid String
|
||||
|
||||
|
||||
emptyDistribution : Random.Seed -> Distribution
|
||||
emptyDistribution seed =
|
||||
{ seed = seed
|
||||
, all = []
|
||||
, only = []
|
||||
, skipped = []
|
||||
}
|
||||
|
||||
|
||||
{-| This breaks down a test into individual Runners, while assigning different
|
||||
random number seeds to them. Along the way it also does a few other things:
|
||||
|
||||
1. Collect any tests created with `Test.only` so later we can run only those.
|
||||
2. Collect any tests created with `Test.todo` so later we can fail the run.
|
||||
3. Validate that the run count is at least 1.
|
||||
|
||||
Some design notes:
|
||||
|
||||
1. `only` tests and `skip` tests do not affect seed distribution. This is
|
||||
important for the case where a user runs tests, sees one failure, and decides
|
||||
to isolate it by using both `only` and providing the same seed as before. If
|
||||
`only` changes seed distribution, then that test result might not reproduce!
|
||||
This would be very frustrating, as it would mean you could reproduce the
|
||||
failure when not using `only`, but it magically disappeared as soon as you
|
||||
tried to isolate it. The same logic applies to `skip`.
|
||||
|
||||
2. Theoretically this could become tail-recursive. However, the Labeled and Batch
|
||||
cases would presumably become very gnarly, and it's unclear whether there would
|
||||
be a performance benefit or penalty in the end. If some brave soul wants to
|
||||
attempt it for kicks, beware that this is not a performance optimization for
|
||||
the faint of heart. Practically speaking, it seems unlikely to be worthwhile
|
||||
unless somehow people start seeing stack overflows during seed distribution -
|
||||
which would presumably require some absurdly deeply nested `describe` calls.
|
||||
|
||||
-}
|
||||
distributeSeeds : Int -> Random.Seed -> Test -> Distribution
|
||||
distributeSeeds =
|
||||
distributeSeedsHelp False
|
||||
|
||||
|
||||
distributeSeedsHelp : Bool -> Int -> Random.Seed -> Test -> Distribution
|
||||
distributeSeedsHelp hashed runs seed test =
|
||||
case test of
|
||||
Internal.UnitTest run ->
|
||||
{ seed = seed
|
||||
, all = [ Runnable (Thunk (\_ -> run ())) ]
|
||||
, only = []
|
||||
, skipped = []
|
||||
}
|
||||
|
||||
Internal.FuzzTest run ->
|
||||
let
|
||||
( firstSeed, nextSeed ) =
|
||||
Random.step Random.independentSeed seed
|
||||
in
|
||||
{ seed = nextSeed
|
||||
, all = [ Runnable (Thunk (\_ -> run firstSeed runs)) ]
|
||||
, only = []
|
||||
, skipped = []
|
||||
}
|
||||
|
||||
Internal.Labeled description subTest ->
|
||||
-- This fixes https://github.com/elm-community/elm-test/issues/192
|
||||
-- The first time we hit a Labeled, we want to use the hash of
|
||||
-- that label, along with the original seed, as our starting
|
||||
-- point for distribution. Repeating this process more than
|
||||
-- once would be a waste.
|
||||
if hashed then
|
||||
let
|
||||
next =
|
||||
distributeSeedsHelp True runs seed subTest
|
||||
in
|
||||
{ seed = next.seed
|
||||
, all = List.map (Labeled description) next.all
|
||||
, only = List.map (Labeled description) next.only
|
||||
, skipped = List.map (Labeled description) next.skipped
|
||||
}
|
||||
else
|
||||
let
|
||||
intFromSeed =
|
||||
-- At this point, this seed will be the original
|
||||
-- one passed into distributeSeeds. We know this
|
||||
-- because the only other branch that does a
|
||||
-- Random.step on that seed is the Internal.Test
|
||||
-- branch, and you can't have a Labeled inside a
|
||||
-- Test, so that couldn't have come up yet.
|
||||
seed
|
||||
-- Convert the Seed back to an Int
|
||||
|> Random.step (Random.int 0 Random.maxInt)
|
||||
|> Tuple.first
|
||||
|
||||
hashedSeed =
|
||||
description
|
||||
-- Hash from String to Int
|
||||
|> fnvHashString fnvInit
|
||||
-- Incorporate the originally passed-in seed
|
||||
|> fnvHash intFromSeed
|
||||
-- Convert Int back to Seed
|
||||
|> Random.initialSeed
|
||||
|
||||
next =
|
||||
distributeSeedsHelp True runs hashedSeed subTest
|
||||
in
|
||||
-- Using seed instead of next.seed fixes https://github.com/elm-community/elm-test/issues/192
|
||||
-- by making it so that all the tests underneath this Label begin
|
||||
-- with the hashed seed, but subsequent sibling tests in this Batch
|
||||
-- get the same seed as before.
|
||||
{ seed = seed
|
||||
, all = List.map (Labeled description) next.all
|
||||
, only = List.map (Labeled description) next.only
|
||||
, skipped = List.map (Labeled description) next.skipped
|
||||
}
|
||||
|
||||
Internal.Skipped subTest ->
|
||||
let
|
||||
-- Go through the motions in order to obtain the seed, but then
|
||||
-- move everything to skipped.
|
||||
next =
|
||||
distributeSeedsHelp hashed runs seed subTest
|
||||
in
|
||||
{ seed = next.seed
|
||||
, all = []
|
||||
, only = []
|
||||
, skipped = next.all
|
||||
}
|
||||
|
||||
Internal.Only subTest ->
|
||||
let
|
||||
next =
|
||||
distributeSeedsHelp hashed runs seed subTest
|
||||
in
|
||||
-- `only` all the things!
|
||||
{ next | only = next.all }
|
||||
|
||||
Internal.Batch tests ->
|
||||
List.foldl (batchDistribute hashed runs) (emptyDistribution seed) tests
|
||||
|
||||
|
||||
batchDistribute : Bool -> Int -> Test -> Distribution -> Distribution
|
||||
batchDistribute hashed runs test prev =
|
||||
let
|
||||
next =
|
||||
distributeSeedsHelp hashed runs prev.seed test
|
||||
in
|
||||
{ seed = next.seed
|
||||
, all = prev.all ++ next.all
|
||||
, only = prev.only ++ next.only
|
||||
, skipped = prev.skipped ++ next.skipped
|
||||
}
|
||||
|
||||
|
||||
{-| FNV-1a initial hash value
|
||||
-}
|
||||
fnvInit : Int
|
||||
fnvInit =
|
||||
2166136261
|
||||
|
||||
|
||||
{-| FNV-1a helper for strings, using Char.toCode
|
||||
-}
|
||||
fnvHashString : Int -> String -> Int
|
||||
fnvHashString hash str =
|
||||
str |> String.toList |> List.map Char.toCode |> List.foldl fnvHash hash
|
||||
|
||||
|
||||
{-| FNV-1a implementation.
|
||||
-}
|
||||
fnvHash : Int -> Int -> Int
|
||||
fnvHash a b =
|
||||
Bitwise.xor a b * 16777619 |> Bitwise.shiftRightZfBy 0
|
||||
|
||||
|
||||
{-| **DEPRECATED.** Please use [`getFailureReason`](#getFailureReason) instead.
|
||||
This function will be removed in the next major version.
|
||||
|
||||
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 `Nothing`).
|
||||
|
||||
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 : Maybe String, message : String }
|
||||
getFailure expectation =
|
||||
case expectation of
|
||||
Test.Expectation.Pass ->
|
||||
Nothing
|
||||
|
||||
Test.Expectation.Fail { given, description, reason } ->
|
||||
Just
|
||||
{ given = given
|
||||
, message = Test.Runner.Failure.format description reason
|
||||
}
|
||||
|
||||
|
||||
{-| Return `Nothing` if the given [`Expectation`](#Expectation) is a [`pass`](#pass).
|
||||
|
||||
If it is a [`fail`](#fail), return a record containing the expectation
|
||||
description, the [`Reason`](#Reason) the test failed, and the given inputs if
|
||||
it was a fuzz test. (If it was not a fuzz test, the record's `given` field
|
||||
will be `Nothing`).
|
||||
|
||||
For example:
|
||||
|
||||
getFailureReason (Expect.equal 1 2)
|
||||
-- Just { reason = Equal 1 2, description = "Expect.equal", given = Nothing }
|
||||
|
||||
getFailureReason (Expect.equal 1 1)
|
||||
-- Nothing
|
||||
|
||||
-}
|
||||
getFailureReason :
|
||||
Expectation
|
||||
->
|
||||
Maybe
|
||||
{ given : Maybe String
|
||||
, description : String
|
||||
, reason : Reason
|
||||
}
|
||||
getFailureReason expectation =
|
||||
case expectation of
|
||||
Test.Expectation.Pass ->
|
||||
Nothing
|
||||
|
||||
Test.Expectation.Fail record ->
|
||||
Just record
|
||||
|
||||
|
||||
{-| Determine if an expectation was created by a call to `Test.todo`. Runners
|
||||
may treat these tests differently in their output.
|
||||
-}
|
||||
isTodo : Expectation -> Bool
|
||||
isTodo expectation =
|
||||
case expectation of
|
||||
Test.Expectation.Pass ->
|
||||
False
|
||||
|
||||
Test.Expectation.Fail { reason } ->
|
||||
reason == TODO
|
||||
|
||||
|
||||
{-| A standard way to format descriptions 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
|
||||
|
||||
Example:
|
||||
|
||||
[ "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
|
||||
|
||||
|
||||
type alias Shrunken a =
|
||||
{ down : LazyList (RoseTree a)
|
||||
, over : LazyList (RoseTree a)
|
||||
}
|
||||
|
||||
|
||||
{-| A `Shrinkable a` is an opaque type that allows you to obtain a value of type
|
||||
`a` that is smaller than the one you've previously obtained.
|
||||
-}
|
||||
type Shrinkable a
|
||||
= Shrinkable (Shrunken a)
|
||||
|
||||
|
||||
{-| Given a fuzzer, return a random generator to produce a value and a
|
||||
Shrinkable. The value is what a fuzz test would have received as input.
|
||||
-}
|
||||
fuzz : Fuzzer a -> Random.Generator ( a, Shrinkable a )
|
||||
fuzz fuzzer =
|
||||
case fuzzer of
|
||||
Ok validFuzzer ->
|
||||
validFuzzer
|
||||
|> Random.map
|
||||
(\(Rose root children) ->
|
||||
( root, Shrinkable { down = children, over = LazyList.empty } )
|
||||
)
|
||||
|
||||
Err reason ->
|
||||
Debug.crash <| "Cannot call `fuzz` with an invalid fuzzer: " ++ reason
|
||||
|
||||
|
||||
{-| Given a Shrinkable, attempt to shrink the value further. Pass `False` to
|
||||
indicate that the last value you've seen (from either `fuzz` or this function)
|
||||
caused the test to **fail**. This will attempt to find a smaller value. Pass
|
||||
`True` if the test passed. If you have already seen a failure, this will attempt
|
||||
to shrink that failure in another way. In both cases, it may be impossible to
|
||||
shrink the value, represented by `Nothing`.
|
||||
-}
|
||||
shrink : Bool -> Shrinkable a -> Maybe ( a, Shrinkable a )
|
||||
shrink causedPass (Shrinkable { down, over }) =
|
||||
let
|
||||
tryNext =
|
||||
if causedPass then
|
||||
over
|
||||
else
|
||||
down
|
||||
in
|
||||
case LazyList.headAndTail tryNext of
|
||||
Just ( Rose root children, tl ) ->
|
||||
Just ( root, Shrinkable { down = children, over = tl } )
|
||||
|
||||
Nothing ->
|
||||
Nothing
|
||||
174
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Runner/Failure.elm
vendored
Normal file
174
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Test/Runner/Failure.elm
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
module Test.Runner.Failure exposing (InvalidReason(..), Reason(..), format)
|
||||
|
||||
{-| The reason a test failed.
|
||||
|
||||
@docs Reason, InvalidReason, format
|
||||
|
||||
-}
|
||||
|
||||
|
||||
{-| The reason a test failed.
|
||||
|
||||
Test runners can use this to provide nice output, e.g. by doing diffs on the
|
||||
two parts of an `Expect.equal` failure.
|
||||
|
||||
-}
|
||||
type Reason
|
||||
= Custom
|
||||
| Equality String String
|
||||
| Comparison String String
|
||||
-- Expected, actual, (index of problem, expected element, actual element)
|
||||
| ListDiff (List String) (List String)
|
||||
{- I don't think we need to show the diff twice with + and - reversed. Just show it after the main vertical bar.
|
||||
"Extra" and "missing" are relative to the actual value.
|
||||
-}
|
||||
| CollectionDiff
|
||||
{ expected : String
|
||||
, actual : String
|
||||
, extra : List String
|
||||
, missing : List String
|
||||
}
|
||||
| TODO
|
||||
| Invalid InvalidReason
|
||||
|
||||
|
||||
{-| The reason a test run was invalid.
|
||||
|
||||
Test runners should report these to the user in whatever format is appropriate.
|
||||
|
||||
-}
|
||||
type InvalidReason
|
||||
= EmptyList
|
||||
| NonpositiveFuzzCount
|
||||
| InvalidFuzzer
|
||||
| BadDescription
|
||||
| DuplicatedName
|
||||
|
||||
|
||||
verticalBar : String -> String -> String -> String
|
||||
verticalBar comparison expected actual =
|
||||
[ actual
|
||||
, "╵"
|
||||
, "│ " ++ comparison
|
||||
, "╷"
|
||||
, expected
|
||||
]
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
{-| DEPRECATED. In the future, test runners should implement versions of this
|
||||
that make sense for their own environments.
|
||||
|
||||
Format test run failures in a reasonable way.
|
||||
|
||||
-}
|
||||
format : String -> Reason -> String
|
||||
format description reason =
|
||||
case reason of
|
||||
Custom ->
|
||||
description
|
||||
|
||||
Equality e a ->
|
||||
verticalBar description e a
|
||||
|
||||
Comparison e a ->
|
||||
verticalBar description e a
|
||||
|
||||
TODO ->
|
||||
description
|
||||
|
||||
Invalid BadDescription ->
|
||||
if description == "" then
|
||||
"The empty string is not a valid test description."
|
||||
else
|
||||
"This is an invalid test description: " ++ description
|
||||
|
||||
Invalid _ ->
|
||||
description
|
||||
|
||||
ListDiff expected actual ->
|
||||
listDiffToString 0
|
||||
description
|
||||
{ expected = expected
|
||||
, actual = actual
|
||||
}
|
||||
{ originalExpected = expected
|
||||
, originalActual = actual
|
||||
}
|
||||
|
||||
CollectionDiff { expected, actual, extra, missing } ->
|
||||
let
|
||||
extraStr =
|
||||
if List.isEmpty extra then
|
||||
""
|
||||
else
|
||||
"\nThese keys are extra: "
|
||||
++ (extra |> String.join ", " |> (\d -> "[ " ++ d ++ " ]"))
|
||||
|
||||
missingStr =
|
||||
if List.isEmpty missing then
|
||||
""
|
||||
else
|
||||
"\nThese keys are missing: "
|
||||
++ (missing |> String.join ", " |> (\d -> "[ " ++ d ++ " ]"))
|
||||
in
|
||||
String.join ""
|
||||
[ verticalBar description expected actual
|
||||
, "\n"
|
||||
, extraStr
|
||||
, missingStr
|
||||
]
|
||||
|
||||
|
||||
listDiffToString :
|
||||
Int
|
||||
-> String
|
||||
-> { expected : List String, actual : List String }
|
||||
-> { originalExpected : List String, originalActual : List String }
|
||||
-> String
|
||||
listDiffToString index description { expected, actual } originals =
|
||||
case ( expected, actual ) of
|
||||
( [], [] ) ->
|
||||
[ "Two lists were unequal previously, yet ended up equal later."
|
||||
, "This should never happen!"
|
||||
, "Please report this bug to https://github.com/elm-community/elm-test/issues - and include these lists: "
|
||||
, "\n"
|
||||
, toString originals.originalExpected
|
||||
, "\n"
|
||||
, toString originals.originalActual
|
||||
]
|
||||
|> String.join ""
|
||||
|
||||
( first :: _, [] ) ->
|
||||
verticalBar (description ++ " was shorter than")
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
|
||||
( [], first :: _ ) ->
|
||||
verticalBar (description ++ " was longer than")
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
|
||||
( firstExpected :: restExpected, firstActual :: restActual ) ->
|
||||
if firstExpected == firstActual then
|
||||
-- They're still the same so far; keep going.
|
||||
listDiffToString (index + 1)
|
||||
description
|
||||
{ expected = restExpected
|
||||
, actual = restActual
|
||||
}
|
||||
originals
|
||||
else
|
||||
-- We found elements that differ; fail!
|
||||
String.join ""
|
||||
[ verticalBar description
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
, "\n\nThe first diff is at index "
|
||||
, toString index
|
||||
, ": it was `"
|
||||
, firstActual
|
||||
, "`, but `"
|
||||
, firstExpected
|
||||
, "` was expected."
|
||||
]
|
||||
32
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/src/Util.elm
vendored
Normal file
32
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.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 Array exposing (Array)
|
||||
import Random.Pcg exposing (..)
|
||||
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
|
||||
128
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/FloatWithinTests.elm
vendored
Normal file
128
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/FloatWithinTests.elm
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
module FloatWithinTests exposing (floatWithinTests)
|
||||
|
||||
import Expect exposing (FloatingPointTolerance(Absolute, AbsoluteOrRelative, Relative))
|
||||
import Fuzz exposing (..)
|
||||
import Helpers exposing (..)
|
||||
import Test exposing (..)
|
||||
|
||||
|
||||
floatWithinTests : Test
|
||||
floatWithinTests =
|
||||
describe "Expect.within"
|
||||
[ describe "use-cases"
|
||||
[ fuzz float "pythagorean identity" <|
|
||||
\x ->
|
||||
sin x ^ 2 + cos x ^ 2 |> Expect.within (AbsoluteOrRelative 0.000001 0.00001) 1.0
|
||||
, test "floats known to not add exactly" <|
|
||||
\_ -> 0.1 + 0.2 |> Expect.within (Absolute 0.000000001) 0.3
|
||||
, test "approximation of pi" <|
|
||||
\_ -> 3.14 |> Expect.within (Absolute 0.01) pi
|
||||
, fuzz (floatRange 0.000001 100000) "relative tolerance of circle circumference using pi approximation" <|
|
||||
\radius ->
|
||||
(radius * pi)
|
||||
|> Expect.within (Relative 0.001) (radius * 3.14)
|
||||
, expectToFail <|
|
||||
test "approximation of pi is not considered too accurate" <|
|
||||
\_ -> 3.14 |> Expect.within (Absolute 0.001) pi
|
||||
, expectToFail <|
|
||||
fuzz (floatRange 0.000001 100000) "too high absolute tolerance of circle circumference using pi approximation" <|
|
||||
\radius ->
|
||||
(radius * pi)
|
||||
|> Expect.within (Absolute 0.001) (radius * 3.14)
|
||||
, expectToFail <|
|
||||
fuzz (floatRange 0.000001 100000) "too high relative tolerance of circle circumference using pi approximation" <|
|
||||
\radius ->
|
||||
(radius * pi)
|
||||
|> Expect.within (Relative 0.0001) (radius * 3.14)
|
||||
]
|
||||
, describe "edge-cases"
|
||||
[ fuzz2 float float "self equality" <|
|
||||
\epsilon value ->
|
||||
let
|
||||
eps =
|
||||
if epsilon /= 0 then
|
||||
epsilon
|
||||
else
|
||||
1
|
||||
in
|
||||
value |> Expect.within (Relative (abs eps)) value
|
||||
, fuzz float "NaN inequality" <|
|
||||
\epsilon ->
|
||||
let
|
||||
nan =
|
||||
0.0 / 0.0
|
||||
in
|
||||
nan |> Expect.notWithin (Relative (abs epsilon)) nan
|
||||
, fuzz2 float float "NaN does not equal anything" <|
|
||||
\epsilon a ->
|
||||
let
|
||||
nan =
|
||||
0.0 / 0.0
|
||||
in
|
||||
nan |> Expect.notWithin (Relative (abs epsilon)) a
|
||||
, fuzz float "Infinity equality" <|
|
||||
\epsilon ->
|
||||
let
|
||||
infinity =
|
||||
1.0 / 0.0
|
||||
in
|
||||
infinity |> Expect.within (Relative (abs epsilon)) infinity
|
||||
, fuzz float "Negative infinity equality" <|
|
||||
\epsilon ->
|
||||
let
|
||||
negativeInfinity =
|
||||
-1.0 / 0.0
|
||||
in
|
||||
negativeInfinity |> Expect.within (Relative (abs epsilon)) negativeInfinity
|
||||
, fuzz3 float float float "within and notWithin should never agree on relative tolerance" <|
|
||||
\epsilon a b ->
|
||||
let
|
||||
withinTest =
|
||||
a |> Expect.within (Relative (abs epsilon)) b
|
||||
|
||||
notWithinTest =
|
||||
a |> Expect.notWithin (Relative (abs epsilon)) b
|
||||
in
|
||||
different withinTest notWithinTest
|
||||
, fuzz3 float float float "within and notWithin should never agree on absolute tolerance" <|
|
||||
\epsilon a b ->
|
||||
let
|
||||
withinTest =
|
||||
a |> Expect.within (Absolute (abs epsilon)) b
|
||||
|
||||
notWithinTest =
|
||||
a |> Expect.notWithin (Absolute (abs epsilon)) b
|
||||
in
|
||||
different withinTest notWithinTest
|
||||
, fuzz4 float float float float "within and notWithin should never agree on absolute or relative tolerance" <|
|
||||
\absoluteEpsilon relativeEpsilon a b ->
|
||||
let
|
||||
withinTest =
|
||||
a |> Expect.within (AbsoluteOrRelative (abs absoluteEpsilon) (abs relativeEpsilon)) b
|
||||
|
||||
notWithinTest =
|
||||
a |> Expect.notWithin (AbsoluteOrRelative (abs absoluteEpsilon) (abs relativeEpsilon)) b
|
||||
in
|
||||
different withinTest notWithinTest
|
||||
, fuzz float "Zero equality" <|
|
||||
\epsilon -> 0.0 |> Expect.within (Relative (abs epsilon)) 0.0
|
||||
, fuzz3 float float float "within absolute commutativity" <|
|
||||
\epsilon a b ->
|
||||
same (Expect.within (Absolute (abs epsilon)) a b) (Expect.within (Absolute (abs epsilon)) b a)
|
||||
, fuzz3 float float float "notWithin absolute commutativity" <|
|
||||
\epsilon a b ->
|
||||
same (Expect.notWithin (Absolute (abs epsilon)) a b) (Expect.notWithin (Absolute (abs epsilon)) b a)
|
||||
, fuzz2 float float "within absolute reflexive" <|
|
||||
\epsilon a ->
|
||||
Expect.within (Absolute (abs epsilon)) a a
|
||||
, fuzz3 float float float "within relative commutativity" <|
|
||||
\epsilon a b ->
|
||||
same (Expect.within (Relative (abs epsilon)) a b) (Expect.within (Relative (abs epsilon)) b a)
|
||||
, fuzz3 float float float "notWithin relative commutativity" <|
|
||||
\epsilon a b ->
|
||||
same (Expect.notWithin (Relative (abs epsilon)) a b) (Expect.notWithin (Relative (abs epsilon)) b a)
|
||||
, fuzz2 float float "within relative reflexive" <|
|
||||
\epsilon a ->
|
||||
Expect.within (Relative (abs epsilon)) a a
|
||||
]
|
||||
]
|
||||
304
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/FuzzerTests.elm
vendored
Normal file
304
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/FuzzerTests.elm
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
module FuzzerTests exposing (fuzzerTests)
|
||||
|
||||
import Expect
|
||||
import Fuzz exposing (..)
|
||||
import Helpers exposing (..)
|
||||
import Lazy.List
|
||||
import Random.Pcg as Random
|
||||
import RoseTree
|
||||
import Test exposing (..)
|
||||
import Test.Runner
|
||||
|
||||
|
||||
die : Fuzzer Int
|
||||
die =
|
||||
Fuzz.intRange 1 6
|
||||
|
||||
|
||||
seed : Fuzzer Random.Seed
|
||||
seed =
|
||||
Fuzz.custom
|
||||
(Random.int Random.minInt Random.maxInt |> Random.map Random.initialSeed)
|
||||
(always Lazy.List.empty)
|
||||
|
||||
|
||||
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
|
||||
(frequency [ ( 1, intRange 1 6 ), ( 1, intRange 1 20 ) ])
|
||||
"Fuzz.frequency"
|
||||
(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)
|
||||
, fuzz
|
||||
(map2 (,) die die
|
||||
|> conditional
|
||||
{ retries = 10
|
||||
, fallback = \( a, b ) -> ( a, (b + 1) % 6 )
|
||||
, condition = \( a, b ) -> a /= b
|
||||
}
|
||||
)
|
||||
"conditional: reroll dice until they are not equal"
|
||||
<|
|
||||
\( roll1, roll2 ) ->
|
||||
roll1 |> Expect.notEqual roll2
|
||||
, fuzz seed "conditional: shrunken values all pass condition" <|
|
||||
\seed ->
|
||||
let
|
||||
evenInt : Fuzzer Int
|
||||
evenInt =
|
||||
Fuzz.intRange 0 10
|
||||
|> Fuzz.conditional
|
||||
{ retries = 3
|
||||
, fallback = (+) 1
|
||||
, condition = even
|
||||
}
|
||||
|
||||
even : Int -> Bool
|
||||
even n =
|
||||
(n % 2) == 0
|
||||
|
||||
shrinkable : Test.Runner.Shrinkable Int
|
||||
shrinkable =
|
||||
Test.Runner.fuzz evenInt
|
||||
|> flip Random.step seed
|
||||
|> Tuple.first
|
||||
|> Tuple.second
|
||||
|
||||
testShrinkable : Test.Runner.Shrinkable Int -> Expect.Expectation
|
||||
testShrinkable shrinkable =
|
||||
case Test.Runner.shrink False shrinkable of
|
||||
Nothing ->
|
||||
Expect.pass
|
||||
|
||||
Just ( value, next ) ->
|
||||
if even value then
|
||||
testShrinkable next
|
||||
else
|
||||
Expect.fail <| "Shrunken value does not pass conditional: " ++ toString value
|
||||
in
|
||||
testShrinkable shrinkable
|
||||
, describe "Whitebox testing using Fuzz.Internal"
|
||||
[ fuzz randomSeedFuzzer "the same value is generated with and without shrinking" <|
|
||||
\seed ->
|
||||
let
|
||||
step gen =
|
||||
Random.step gen seed
|
||||
|
||||
aFuzzer =
|
||||
tuple5
|
||||
( tuple ( list int, array float )
|
||||
, maybe bool
|
||||
, result unit char
|
||||
, tuple3
|
||||
( percentage
|
||||
, map2 (+) int int
|
||||
, frequency [ ( 1, constant True ), ( 3, constant False ) ]
|
||||
)
|
||||
, tuple3 ( intRange 0 100, floatRange -51 pi, map abs int )
|
||||
)
|
||||
|
||||
valNoShrink =
|
||||
aFuzzer |> Result.map (Random.map RoseTree.root >> step >> Tuple.first)
|
||||
|
||||
valWithShrink =
|
||||
aFuzzer |> Result.map (step >> Tuple.first >> RoseTree.root)
|
||||
in
|
||||
Expect.equal valNoShrink valWithShrink
|
||||
, shrinkingTests
|
||||
, manualFuzzerTests
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
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]"
|
||||
, fuzz (intRange 1 8 |> andThen (\i -> intRange 0 (2 ^ i))) "Fuzz.andThen shrinks a number" <|
|
||||
\i ->
|
||||
i <= 2 |> Expect.true "3"
|
||||
]
|
||||
|
||||
|
||||
type alias ShrinkResult a =
|
||||
Maybe ( a, Test.Runner.Shrinkable a )
|
||||
|
||||
|
||||
manualFuzzerTests : Test
|
||||
manualFuzzerTests =
|
||||
describe "Test.Runner.{fuzz, shrink}"
|
||||
[ fuzz randomSeedFuzzer "Claim there are no even numbers" <|
|
||||
\seed ->
|
||||
let
|
||||
-- fuzzer is guaranteed to produce an even number
|
||||
fuzzer =
|
||||
Fuzz.intRange 2 10000
|
||||
|> Fuzz.map
|
||||
(\n ->
|
||||
if failsTest n then
|
||||
n
|
||||
else
|
||||
n + 1
|
||||
)
|
||||
|
||||
failsTest n =
|
||||
n % 2 == 0
|
||||
|
||||
pair =
|
||||
Random.step (Test.Runner.fuzz fuzzer) seed
|
||||
|> Tuple.first
|
||||
|> Just
|
||||
|
||||
unfold acc maybePair =
|
||||
case maybePair of
|
||||
Just ( valN, shrinkN ) ->
|
||||
if failsTest valN then
|
||||
unfold (valN :: acc) (Test.Runner.shrink False shrinkN)
|
||||
else
|
||||
unfold acc (Test.Runner.shrink True shrinkN)
|
||||
|
||||
Nothing ->
|
||||
acc
|
||||
in
|
||||
unfold [] pair
|
||||
|> Expect.all
|
||||
[ List.all failsTest >> Expect.true "Not all elements were even"
|
||||
, List.head
|
||||
>> Maybe.map (Expect.all [ Expect.lessThan 5, Expect.atLeast 0 ])
|
||||
>> Maybe.withDefault (Expect.fail "Did not cause failure")
|
||||
, List.reverse >> List.head >> Expect.equal (Maybe.map Tuple.first pair)
|
||||
]
|
||||
, fuzz randomSeedFuzzer "No strings contain the letter e" <|
|
||||
\seed ->
|
||||
let
|
||||
-- fuzzer is guaranteed to produce a string with the letter e
|
||||
fuzzer =
|
||||
map2 (\pre suf -> pre ++ "e" ++ suf) string string
|
||||
|
||||
failsTest =
|
||||
String.contains "e"
|
||||
|
||||
pair =
|
||||
Random.step (Test.Runner.fuzz fuzzer) seed
|
||||
|> Tuple.first
|
||||
|> Just
|
||||
|
||||
unfold acc maybePair =
|
||||
case maybePair of
|
||||
Just ( valN, shrinkN ) ->
|
||||
if failsTest valN then
|
||||
unfold (valN :: acc) (Test.Runner.shrink False shrinkN)
|
||||
else
|
||||
unfold acc (Test.Runner.shrink True shrinkN)
|
||||
|
||||
Nothing ->
|
||||
acc
|
||||
in
|
||||
unfold [] pair
|
||||
|> Expect.all
|
||||
[ List.all failsTest >> Expect.true "Not all contained the letter e"
|
||||
, List.head >> Expect.equal (Just "e")
|
||||
, List.reverse >> List.head >> Expect.equal (Maybe.map Tuple.first pair)
|
||||
]
|
||||
, fuzz randomSeedFuzzer "List shrinker finds the smallest counter example" <|
|
||||
\seed ->
|
||||
let
|
||||
fuzzer : Fuzzer (List Int)
|
||||
fuzzer =
|
||||
Fuzz.list Fuzz.int
|
||||
|
||||
allEven : List Int -> Bool
|
||||
allEven xs =
|
||||
List.all (\x -> x % 2 == 0) xs
|
||||
|
||||
initialShrink : ShrinkResult (List Int)
|
||||
initialShrink =
|
||||
Random.step (Test.Runner.fuzz fuzzer) seed
|
||||
|> Tuple.first
|
||||
|> Just
|
||||
|
||||
shrink : Maybe (List Int) -> ShrinkResult (List Int) -> Maybe (List Int)
|
||||
shrink shrunken lastShrink =
|
||||
case lastShrink of
|
||||
Just ( valN, shrinkN ) ->
|
||||
shrink
|
||||
(if allEven valN then
|
||||
shrunken
|
||||
else
|
||||
Just valN
|
||||
)
|
||||
(Test.Runner.shrink (allEven valN) shrinkN)
|
||||
|
||||
Nothing ->
|
||||
shrunken
|
||||
in
|
||||
case shrink Nothing initialShrink of
|
||||
Just shrunken ->
|
||||
Expect.equal [ 1 ] shrunken
|
||||
|
||||
Nothing ->
|
||||
Expect.pass
|
||||
]
|
||||
159
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Helpers.elm
vendored
Normal file
159
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Helpers.elm
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
module Helpers exposing (different, expectPass, expectToFail, randomSeedFuzzer, same, succeeded, testShrinking, testStringLengthIsPreserved)
|
||||
|
||||
import Expect
|
||||
import Fuzz exposing (Fuzzer)
|
||||
import Random.Pcg as Random
|
||||
import Shrink
|
||||
import Test exposing (Test)
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Test.Internal as Internal
|
||||
import Test.Runner.Failure exposing (Reason(..))
|
||||
|
||||
|
||||
expectPass : a -> Expectation
|
||||
expectPass _ =
|
||||
Expect.pass
|
||||
|
||||
|
||||
testStringLengthIsPreserved : List String -> Expectation
|
||||
testStringLengthIsPreserved strings =
|
||||
strings
|
||||
|> List.map String.length
|
||||
|> List.sum
|
||||
|> Expect.equal (String.length (List.foldl (++) "" strings))
|
||||
|
||||
|
||||
expectToFail : Test -> Test
|
||||
expectToFail =
|
||||
expectFailureHelper (always Nothing)
|
||||
|
||||
|
||||
succeeded : Expectation -> Bool
|
||||
succeeded expectation =
|
||||
case expectation of
|
||||
Pass ->
|
||||
True
|
||||
|
||||
Fail _ ->
|
||||
False
|
||||
|
||||
|
||||
passesToFails :
|
||||
({ reason : Reason
|
||||
, description : String
|
||||
, given : Maybe String
|
||||
}
|
||||
-> Maybe String
|
||||
)
|
||||
-> List Expectation
|
||||
-> List Expectation
|
||||
passesToFails f expectations =
|
||||
expectations
|
||||
|> List.filterMap (passToFail f)
|
||||
|> List.map Expect.fail
|
||||
|> (\list ->
|
||||
if List.isEmpty list then
|
||||
[ Expect.pass ]
|
||||
else
|
||||
list
|
||||
)
|
||||
|
||||
|
||||
passToFail :
|
||||
({ reason : Reason
|
||||
, description : String
|
||||
, given : Maybe String
|
||||
}
|
||||
-> Maybe String
|
||||
)
|
||||
-> Expectation
|
||||
-> Maybe String
|
||||
passToFail f expectation =
|
||||
case expectation of
|
||||
Pass ->
|
||||
Just "Expected this test to fail, but it passed!"
|
||||
|
||||
Fail record ->
|
||||
f record
|
||||
|
||||
|
||||
expectFailureHelper : ({ description : String, given : Maybe String, reason : Reason } -> Maybe String) -> Test -> Test
|
||||
expectFailureHelper f test =
|
||||
case test of
|
||||
Internal.UnitTest runTest ->
|
||||
Internal.UnitTest <|
|
||||
\() ->
|
||||
passesToFails f (runTest ())
|
||||
|
||||
Internal.FuzzTest runTest ->
|
||||
Internal.FuzzTest <|
|
||||
\seed runs ->
|
||||
passesToFails f (runTest seed runs)
|
||||
|
||||
Internal.Labeled desc labeledTest ->
|
||||
Internal.Labeled desc (expectFailureHelper f labeledTest)
|
||||
|
||||
Internal.Batch tests ->
|
||||
Internal.Batch (List.map (expectFailureHelper f) tests)
|
||||
|
||||
Internal.Skipped subTest ->
|
||||
expectFailureHelper f subTest
|
||||
|> Internal.Skipped
|
||||
|
||||
Internal.Only subTest ->
|
||||
expectFailureHelper f subTest
|
||||
|> Internal.Only
|
||||
|
||||
|
||||
testShrinking : Test -> Test
|
||||
testShrinking =
|
||||
let
|
||||
handleFailure { given, description } =
|
||||
let
|
||||
acceptable =
|
||||
String.split "|" description
|
||||
in
|
||||
case given of
|
||||
Nothing ->
|
||||
Just "Expected this test to have a given value!"
|
||||
|
||||
Just g ->
|
||||
if List.member g acceptable then
|
||||
Nothing
|
||||
else
|
||||
Just <| "Got shrunken value " ++ g ++ " but expected " ++ String.join " or " acceptable
|
||||
in
|
||||
expectFailureHelper handleFailure
|
||||
|
||||
|
||||
{-| get a good distribution of random seeds, and don't shrink our seeds!
|
||||
-}
|
||||
randomSeedFuzzer : Fuzzer Random.Seed
|
||||
randomSeedFuzzer =
|
||||
Fuzz.custom (Random.int 0 0xFFFFFFFF) Shrink.noShrink |> Fuzz.map Random.initialSeed
|
||||
|
||||
|
||||
same : Expectation -> Expectation -> Expectation
|
||||
same a b =
|
||||
case ( a, b ) of
|
||||
( Test.Expectation.Pass, Test.Expectation.Pass ) ->
|
||||
Test.Expectation.Pass
|
||||
|
||||
( Test.Expectation.Fail _, Test.Expectation.Fail _ ) ->
|
||||
Test.Expectation.Pass
|
||||
|
||||
( a, b ) ->
|
||||
Test.Expectation.fail { description = "expected both arguments to fail, or both to succeed", reason = Equality (toString a) (toString b) }
|
||||
|
||||
|
||||
different : Expectation -> Expectation -> Expectation
|
||||
different a b =
|
||||
case ( a, b ) of
|
||||
( Test.Expectation.Pass, Test.Expectation.Fail _ ) ->
|
||||
Test.Expectation.Pass
|
||||
|
||||
( Test.Expectation.Fail _, Test.Expectation.Pass ) ->
|
||||
Test.Expectation.Pass
|
||||
|
||||
( a, b ) ->
|
||||
Test.Expectation.fail { description = "expected one argument to fail", reason = Equality (toString a) (toString b) }
|
||||
82
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Main.elm
vendored
Normal file
82
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Main.elm
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
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 Platform
|
||||
import Runner.Log
|
||||
import Runner.String exposing (Summary)
|
||||
import SeedTests
|
||||
import Tests
|
||||
|
||||
|
||||
main : Program Never () msg
|
||||
main =
|
||||
let
|
||||
program =
|
||||
Platform.program
|
||||
{ init = ( (), Cmd.none )
|
||||
, update = \_ _ -> ( (), Cmd.none )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
}
|
||||
in
|
||||
runAllTests program
|
||||
|
||||
|
||||
runAllTests : a -> a
|
||||
runAllTests a =
|
||||
let
|
||||
runSeedTest =
|
||||
Runner.String.runWithOptions 1 SeedTests.fixedSeed
|
||||
|
||||
_ =
|
||||
[ [ Runner.String.run Tests.all ]
|
||||
, List.map runSeedTest SeedTests.tests
|
||||
, List.map (runSeedTest >> removeAutoFail) SeedTests.noAutoFail
|
||||
]
|
||||
|> List.concat
|
||||
|> List.foldl combineSummaries emptySummary
|
||||
|> Runner.Log.logOutput
|
||||
in
|
||||
a
|
||||
|
||||
|
||||
emptySummary : Summary
|
||||
emptySummary =
|
||||
{ output = "", passed = 0, failed = 0, autoFail = Nothing }
|
||||
|
||||
|
||||
{-| Considers autoFail as pass so we can actually write tests about Test.skip
|
||||
and Test.only which do not automatically fail.
|
||||
-}
|
||||
removeAutoFail : Summary -> Summary
|
||||
removeAutoFail summary =
|
||||
{ summary | autoFail = Nothing }
|
||||
|
||||
|
||||
combineSummaries : Summary -> Summary -> Summary
|
||||
combineSummaries first second =
|
||||
{ output = first.output ++ second.output
|
||||
, passed = first.passed + second.passed
|
||||
, failed = first.failed + second.failed
|
||||
, autoFail =
|
||||
case ( first.autoFail, second.autoFail ) of
|
||||
( Nothing, Nothing ) ->
|
||||
Nothing
|
||||
|
||||
( Nothing, second ) ->
|
||||
second
|
||||
|
||||
( first, Nothing ) ->
|
||||
first
|
||||
|
||||
( Just first, Just second ) ->
|
||||
[ first, second ]
|
||||
|> String.join "\n"
|
||||
|> Just
|
||||
}
|
||||
6
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/README.md
vendored
Normal file
6
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.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`
|
||||
82
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/Log.elm
vendored
Normal file
82
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/Log.elm
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
module Runner.Log exposing (logOutput, 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 Runner.String exposing (Summary)
|
||||
import String
|
||||
import Test exposing (Test)
|
||||
|
||||
|
||||
{-| Run the test using the default `Test.Runner.String` options.
|
||||
-}
|
||||
run : Test -> ()
|
||||
run test =
|
||||
Runner.String.run test
|
||||
|> logOutput
|
||||
|
||||
|
||||
{-| Run the test using the provided options.
|
||||
-}
|
||||
runWithOptions : Int -> Random.Seed -> Test -> ()
|
||||
runWithOptions runs seed test =
|
||||
Runner.String.runWithOptions runs seed test
|
||||
|> logOutput
|
||||
|
||||
|
||||
summarize : Summary -> String
|
||||
summarize { output, passed, failed, autoFail } =
|
||||
let
|
||||
headline =
|
||||
if failed > 0 then
|
||||
output ++ "\n\nTEST RUN FAILED"
|
||||
else
|
||||
case autoFail of
|
||||
Nothing ->
|
||||
"TEST RUN PASSED"
|
||||
|
||||
Just reason ->
|
||||
"TEST RUN FAILED because " ++ reason
|
||||
in
|
||||
String.join "\n"
|
||||
[ output
|
||||
, headline ++ "\n"
|
||||
, "Passed: " ++ toString passed
|
||||
, "Failed: " ++ toString failed
|
||||
]
|
||||
|
||||
|
||||
logOutput : Summary -> ()
|
||||
logOutput summary =
|
||||
let
|
||||
output =
|
||||
summarize summary ++ "\n\nExit code"
|
||||
|
||||
_ =
|
||||
if summary.failed > 0 || summary.autoFail /= Nothing then
|
||||
output
|
||||
|> flip Debug.log 1
|
||||
|> (\_ -> Debug.crash "FAILED TEST RUN")
|
||||
|> (\_ -> ())
|
||||
else
|
||||
output
|
||||
|> flip Debug.log 0
|
||||
|> (\_ -> ())
|
||||
in
|
||||
()
|
||||
134
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/String.elm
vendored
Normal file
134
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/String.elm
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
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 Expect exposing (Expectation)
|
||||
import Random.Pcg as Random
|
||||
import Runner.String.Format
|
||||
import Test exposing (Test)
|
||||
import Test.Runner exposing (Runner, SeededRunners(..))
|
||||
|
||||
|
||||
{-| The output string, the number of passed tests,
|
||||
and the number of failed tests.
|
||||
-}
|
||||
type alias Summary =
|
||||
{ output : String, passed : Int, failed : Int, autoFail : Maybe String }
|
||||
|
||||
|
||||
toOutput : Summary -> SeededRunners -> Summary
|
||||
toOutput summary seededRunners =
|
||||
let
|
||||
render =
|
||||
List.foldl (toOutputHelp [])
|
||||
in
|
||||
case seededRunners of
|
||||
Plain runners ->
|
||||
render { summary | autoFail = Nothing } runners
|
||||
|
||||
Only runners ->
|
||||
render { summary | autoFail = Just "Test.only was used" } runners
|
||||
|
||||
Skipping runners ->
|
||||
render { summary | autoFail = Just "Test.skip was used" } runners
|
||||
|
||||
Invalid message ->
|
||||
{ output = message, passed = 0, failed = 0, autoFail = Nothing }
|
||||
|
||||
|
||||
toOutputHelp : List String -> Runner -> Summary -> Summary
|
||||
toOutputHelp labels runner summary =
|
||||
runner.run ()
|
||||
|> List.foldl fromExpectation summary
|
||||
|
||||
|
||||
fromExpectation : Expectation -> Summary -> Summary
|
||||
fromExpectation expectation summary =
|
||||
case Test.Runner.getFailureReason expectation of
|
||||
Nothing ->
|
||||
{ summary | passed = summary.passed + 1 }
|
||||
|
||||
Just { given, description, reason } ->
|
||||
let
|
||||
message =
|
||||
Runner.String.Format.format description reason
|
||||
|
||||
prefix =
|
||||
case given of
|
||||
Nothing ->
|
||||
""
|
||||
|
||||
Just g ->
|
||||
"Given " ++ g ++ "\n\n"
|
||||
|
||||
newOutput =
|
||||
"\n\n" ++ (prefix ++ indentLines message) ++ "\n"
|
||||
in
|
||||
{ summary
|
||||
| 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 =
|
||||
let
|
||||
seededRunners =
|
||||
Test.Runner.fromTest runs seed test
|
||||
in
|
||||
toOutput
|
||||
{ output = ""
|
||||
, passed = 0
|
||||
, failed = 0
|
||||
, autoFail = Just "no tests were run"
|
||||
}
|
||||
seededRunners
|
||||
182
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/String/Format.elm
vendored
Normal file
182
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Runner/String/Format.elm
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
module Runner.String.Format exposing (format)
|
||||
|
||||
import Diff exposing (Change(..))
|
||||
import Test.Runner.Failure exposing (InvalidReason(BadDescription), Reason(..))
|
||||
|
||||
|
||||
format : String -> Reason -> String
|
||||
format description reason =
|
||||
case reason of
|
||||
Custom ->
|
||||
description
|
||||
|
||||
Equality expected actual ->
|
||||
equalityToString { operation = description, expected = expected, actual = actual }
|
||||
|
||||
Comparison first second ->
|
||||
verticalBar description first second
|
||||
|
||||
TODO ->
|
||||
description
|
||||
|
||||
Invalid BadDescription ->
|
||||
if description == "" then
|
||||
"The empty string is not a valid test description."
|
||||
else
|
||||
"This is an invalid test description: " ++ description
|
||||
|
||||
Invalid _ ->
|
||||
description
|
||||
|
||||
ListDiff expected actual ->
|
||||
listDiffToString 0
|
||||
description
|
||||
{ expected = expected
|
||||
, actual = actual
|
||||
}
|
||||
{ originalExpected = expected
|
||||
, originalActual = actual
|
||||
}
|
||||
|
||||
CollectionDiff { expected, actual, extra, missing } ->
|
||||
let
|
||||
extraStr =
|
||||
if List.isEmpty extra then
|
||||
""
|
||||
else
|
||||
"\nThese keys are extra: "
|
||||
++ (extra |> String.join ", " |> (\d -> "[ " ++ d ++ " ]"))
|
||||
|
||||
missingStr =
|
||||
if List.isEmpty missing then
|
||||
""
|
||||
else
|
||||
"\nThese keys are missing: "
|
||||
++ (missing |> String.join ", " |> (\d -> "[ " ++ d ++ " ]"))
|
||||
in
|
||||
String.join ""
|
||||
[ verticalBar description expected actual
|
||||
, "\n"
|
||||
, extraStr
|
||||
, missingStr
|
||||
]
|
||||
|
||||
|
||||
verticalBar : String -> String -> String -> String
|
||||
verticalBar comparison expected actual =
|
||||
[ actual
|
||||
, "╵"
|
||||
, "│ " ++ comparison
|
||||
, "╷"
|
||||
, expected
|
||||
]
|
||||
|> String.join "\n"
|
||||
|
||||
|
||||
listDiffToString :
|
||||
Int
|
||||
-> String
|
||||
-> { expected : List String, actual : List String }
|
||||
-> { originalExpected : List String, originalActual : List String }
|
||||
-> String
|
||||
listDiffToString index description { expected, actual } originals =
|
||||
case ( expected, actual ) of
|
||||
( [], [] ) ->
|
||||
[ "Two lists were unequal previously, yet ended up equal later."
|
||||
, "This should never happen!"
|
||||
, "Please report this bug to https://github.com/elm-community/elm-test/issues - and include these lists: "
|
||||
, "\n"
|
||||
, toString originals.originalExpected
|
||||
, "\n"
|
||||
, toString originals.originalActual
|
||||
]
|
||||
|> String.join ""
|
||||
|
||||
( first :: _, [] ) ->
|
||||
verticalBar (description ++ " was shorter than")
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
|
||||
( [], first :: _ ) ->
|
||||
verticalBar (description ++ " was longer than")
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
|
||||
( firstExpected :: restExpected, firstActual :: restActual ) ->
|
||||
if firstExpected == firstActual then
|
||||
-- They're still the same so far; keep going.
|
||||
listDiffToString (index + 1)
|
||||
description
|
||||
{ expected = restExpected
|
||||
, actual = restActual
|
||||
}
|
||||
originals
|
||||
else
|
||||
-- We found elements that differ; fail!
|
||||
String.join ""
|
||||
[ verticalBar description
|
||||
(toString originals.originalExpected)
|
||||
(toString originals.originalActual)
|
||||
, "\n\nThe first diff is at index "
|
||||
, toString index
|
||||
, ": it was `"
|
||||
, firstActual
|
||||
, "`, but `"
|
||||
, firstExpected
|
||||
, "` was expected."
|
||||
]
|
||||
|
||||
|
||||
equalityToString : { operation : String, expected : String, actual : String } -> String
|
||||
equalityToString { operation, expected, actual } =
|
||||
-- TODO make sure this looks reasonable for multiline strings
|
||||
let
|
||||
( formattedExpected, belowFormattedExpected ) =
|
||||
Diff.diff (String.toList expected) (String.toList actual)
|
||||
|> List.map formatExpectedChange
|
||||
|> List.unzip
|
||||
|
||||
( formattedActual, belowFormattedActual ) =
|
||||
Diff.diff (String.toList actual) (String.toList expected)
|
||||
|> List.map formatActualChange
|
||||
|> List.unzip
|
||||
|
||||
combinedExpected =
|
||||
String.join "\n"
|
||||
[ String.join "" formattedExpected
|
||||
, String.join "" belowFormattedExpected
|
||||
]
|
||||
|
||||
combinedActual =
|
||||
String.join "\n"
|
||||
[ String.join "" formattedActual
|
||||
, String.join "" belowFormattedActual
|
||||
]
|
||||
in
|
||||
verticalBar operation combinedExpected combinedActual
|
||||
|
||||
|
||||
formatExpectedChange : Change Char -> ( String, String )
|
||||
formatExpectedChange diff =
|
||||
case diff of
|
||||
Added char ->
|
||||
( "", "" )
|
||||
|
||||
Removed char ->
|
||||
( String.fromChar char, "▲" )
|
||||
|
||||
NoChange char ->
|
||||
( String.fromChar char, " " )
|
||||
|
||||
|
||||
formatActualChange : Change Char -> ( String, String )
|
||||
formatActualChange diff =
|
||||
case diff of
|
||||
Added char ->
|
||||
( "", "" )
|
||||
|
||||
Removed char ->
|
||||
( "▼", String.fromChar char )
|
||||
|
||||
NoChange char ->
|
||||
( " ", String.fromChar char )
|
||||
196
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/RunnerTests.elm
vendored
Normal file
196
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/RunnerTests.elm
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
module RunnerTests exposing (all)
|
||||
|
||||
import Expect
|
||||
import Fuzz exposing (..)
|
||||
import Helpers exposing (expectPass)
|
||||
import Random.Pcg as Random
|
||||
import Test exposing (..)
|
||||
import Test.Runner exposing (SeededRunners(..))
|
||||
|
||||
|
||||
all : Test
|
||||
all =
|
||||
Test.concat
|
||||
[ fromTest ]
|
||||
|
||||
|
||||
toSeededRunners : Test -> SeededRunners
|
||||
toSeededRunners =
|
||||
Test.Runner.fromTest 5 (Random.initialSeed 42)
|
||||
|
||||
|
||||
fromTest : Test
|
||||
fromTest =
|
||||
describe "TestRunner.fromTest"
|
||||
[ describe "test length"
|
||||
[ fuzz2 int int "only positive tests runs are valid" <|
|
||||
\runs intSeed ->
|
||||
case Test.Runner.fromTest runs (Random.initialSeed intSeed) passing of
|
||||
Invalid str ->
|
||||
if runs > 0 then
|
||||
Expect.fail ("Expected a run count of " ++ toString runs ++ " to be valid, but was invalid with this message: " ++ toString str)
|
||||
else
|
||||
Expect.pass
|
||||
|
||||
val ->
|
||||
if runs > 0 then
|
||||
Expect.pass
|
||||
else
|
||||
Expect.fail ("Expected a run count of " ++ toString runs ++ " to be invalid, but was valid with this value: " ++ toString val)
|
||||
, test "an only inside another only has no effect" <|
|
||||
\_ ->
|
||||
let
|
||||
runners =
|
||||
toSeededRunners <|
|
||||
describe "three tests"
|
||||
[ test "passes" expectPass
|
||||
, Test.only <|
|
||||
describe "two tests"
|
||||
[ test "fails" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
, Test.only <|
|
||||
test "is an only" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
]
|
||||
]
|
||||
in
|
||||
case runners of
|
||||
Only runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 2
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Only, but was " ++ toString val)
|
||||
, test "a skip inside an only takes effect" <|
|
||||
\_ ->
|
||||
let
|
||||
runners =
|
||||
toSeededRunners <|
|
||||
describe "three tests"
|
||||
[ test "passes" expectPass
|
||||
, Test.only <|
|
||||
describe "two tests"
|
||||
[ test "fails" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
, Test.skip <|
|
||||
test "is skipped" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
]
|
||||
]
|
||||
in
|
||||
case runners of
|
||||
Only runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Only, but was " ++ toString val)
|
||||
, test "an only inside a skip has no effect" <|
|
||||
\_ ->
|
||||
let
|
||||
runners =
|
||||
toSeededRunners <|
|
||||
describe "three tests"
|
||||
[ test "passes" expectPass
|
||||
, Test.skip <|
|
||||
describe "two tests"
|
||||
[ test "fails" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
, Test.only <|
|
||||
test "is skipped" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
]
|
||||
]
|
||||
in
|
||||
case runners of
|
||||
Skipping runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Skipping, but was " ++ toString val)
|
||||
, test "a test that uses only is an Only summary" <|
|
||||
\_ ->
|
||||
case toSeededRunners (Test.only <| test "passes" expectPass) of
|
||||
Only runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Only, but was " ++ toString val)
|
||||
, test "a skip inside another skip has no effect" <|
|
||||
\_ ->
|
||||
let
|
||||
runners =
|
||||
toSeededRunners <|
|
||||
describe "three tests"
|
||||
[ test "passes" expectPass
|
||||
, Test.skip <|
|
||||
describe "two tests"
|
||||
[ test "fails" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
, Test.skip <|
|
||||
test "is skipped" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
]
|
||||
]
|
||||
in
|
||||
case runners of
|
||||
Skipping runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Skipping, but was " ++ toString val)
|
||||
, test "a pair of tests where one uses skip is a Skipping summary" <|
|
||||
\_ ->
|
||||
let
|
||||
runners =
|
||||
toSeededRunners <|
|
||||
describe "two tests"
|
||||
[ test "passes" expectPass
|
||||
, Test.skip <|
|
||||
test "fails" <|
|
||||
\_ -> Expect.fail "failed on purpose"
|
||||
]
|
||||
in
|
||||
case runners of
|
||||
Skipping runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Skipping, but was " ++ toString val)
|
||||
, test "when all tests are skipped, we get an empty Skipping summary" <|
|
||||
\_ ->
|
||||
case toSeededRunners (Test.skip <| test "passes" expectPass) of
|
||||
Skipping runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 0
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Skipping, but was " ++ toString val)
|
||||
, test "a test that does not use only or skip is a Plain summary" <|
|
||||
\_ ->
|
||||
case toSeededRunners (test "passes" expectPass) of
|
||||
Plain runners ->
|
||||
runners
|
||||
|> List.length
|
||||
|> Expect.equal 1
|
||||
|
||||
val ->
|
||||
Expect.fail ("Expected SeededRunner to be Plain, but was " ++ toString val)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
passing : Test
|
||||
passing =
|
||||
test "A passing test" expectPass
|
||||
190
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/SeedTests.elm
vendored
Normal file
190
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/SeedTests.elm
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
module SeedTests exposing (fixedSeed, noAutoFail, tests)
|
||||
|
||||
import Expect exposing (FloatingPointTolerance(Absolute, AbsoluteOrRelative, Relative))
|
||||
import Fuzz exposing (..)
|
||||
import Random.Pcg as Random
|
||||
import Test exposing (..)
|
||||
|
||||
|
||||
-- NOTE: These tests are only here so that we can watch out for regressions. All constants in this file are what the implementation happened to output, not what we expected the implementation to output.
|
||||
|
||||
|
||||
expectedNum : Int
|
||||
expectedNum =
|
||||
-3954212174
|
||||
|
||||
|
||||
oneSeedAlreadyDistributed : Int
|
||||
oneSeedAlreadyDistributed =
|
||||
198384431
|
||||
|
||||
|
||||
fixedSeed : Random.Seed
|
||||
fixedSeed =
|
||||
Random.initialSeed 133742
|
||||
|
||||
|
||||
{-| Most of the tests will use this, but we won't run it directly.
|
||||
|
||||
When these tests are run using fixedSeed and a run count of 1, this is the
|
||||
exact number they will get when the description around this fuzz test is
|
||||
exactly the string "Seed test".
|
||||
|
||||
-}
|
||||
fuzzTest : Test
|
||||
fuzzTest =
|
||||
fuzz int "It receives the expected number" <|
|
||||
\num ->
|
||||
Expect.equal num expectedNum
|
||||
|
||||
|
||||
fuzzTestAfterOneDistributed : Test
|
||||
fuzzTestAfterOneDistributed =
|
||||
fuzz int "This should be different than expectedNum, because there is a fuzz test before it." <|
|
||||
\num ->
|
||||
Expect.equal num oneSeedAlreadyDistributed
|
||||
|
||||
|
||||
tests : List Test
|
||||
tests =
|
||||
[ describe "Seed test"
|
||||
[ fuzzTest ]
|
||||
, describe "Seed test"
|
||||
[ fuzz int "It receives the expected number even though this text is different" <|
|
||||
\num ->
|
||||
Expect.equal num expectedNum
|
||||
]
|
||||
, describe "Seed test"
|
||||
[ describe "Nested describes shouldn't affect seed distribution"
|
||||
[ fuzzTest ]
|
||||
]
|
||||
, describe "Seed test"
|
||||
[ test "Unit tests before should not affect seed distribution" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
, fuzzTest
|
||||
, test "Unit tests after should not affect seed distribution" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
]
|
||||
, -- Wrapping in a Test.concat shouldn't change anything
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ fuzzTest ]
|
||||
]
|
||||
, -- Wrapping in a Test.concat wth unit tests shouldn't change anything
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ test "Unit tests before should not affect seed distribution" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
, fuzzTest
|
||||
, test "Unit tests after should not affect seed distribution" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
]
|
||||
]
|
||||
, -- Putting a fuzz test before it, within a second label, *should* change things
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ fuzzTest
|
||||
, fuzzTestAfterOneDistributed
|
||||
]
|
||||
]
|
||||
, Test.concat
|
||||
[ fuzz int "top-level fuzz tests don't affect subsequent top-level fuzz tests, since they use their labels to get different seeds" <|
|
||||
\num ->
|
||||
Expect.equal num 409469537
|
||||
, describe "Seed test"
|
||||
[ fuzzTest ]
|
||||
, describe "another top-level fuzz test"
|
||||
[ fuzz int "it still gets different values, due to computing the seed as a hash of the label, and these labels must be unique" <|
|
||||
\num ->
|
||||
Expect.equal num 0
|
||||
]
|
||||
]
|
||||
, describe "Fuzz tests with different outer describe texts get different seeds"
|
||||
[ fuzz int "It receives the expected number" <|
|
||||
\num ->
|
||||
Expect.equal num 2049737128
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
noAutoFail : List Test
|
||||
noAutoFail =
|
||||
[ -- Test.skip does not affect seed distribution
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ skip fuzzTest
|
||||
, fuzzTestAfterOneDistributed
|
||||
]
|
||||
]
|
||||
, -- Test.only does not affect seed distribution
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ only fuzzTest ]
|
||||
]
|
||||
, -- Test.only skips the other tests in question
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ skip <|
|
||||
test "Autofail" <|
|
||||
\_ ->
|
||||
Expect.fail "Test.skip is broken! This should not have been run."
|
||||
, fuzzTest
|
||||
]
|
||||
]
|
||||
, -- Test.only skips the other tests.
|
||||
Test.concat
|
||||
[ describe "Seed test"
|
||||
[ only <|
|
||||
fuzz int "No Autofail here" <|
|
||||
\num ->
|
||||
Expect.equal num expectedNum
|
||||
, test "This should never get run" <|
|
||||
\() ->
|
||||
Expect.fail "Test.only is broken! This should not have been run."
|
||||
]
|
||||
]
|
||||
, -- Test.skip skips the test in question
|
||||
describe "Seed test"
|
||||
[ skip <|
|
||||
fuzz int "Skip test sanity check" <|
|
||||
\_ ->
|
||||
Expect.fail "Test.skip is broken! This should not have been run."
|
||||
, fuzzTestAfterOneDistributed
|
||||
]
|
||||
, -- the previous test gets the same answer if Test.skip is removed
|
||||
describe "Seed test"
|
||||
[ fuzz int "Skip test sanity check" <|
|
||||
\_ ->
|
||||
Expect.pass
|
||||
, fuzzTestAfterOneDistributed
|
||||
]
|
||||
, -- Test.only skips the other tests.
|
||||
describe "Seed test"
|
||||
[ only <|
|
||||
fuzz int "No Autofail here" <|
|
||||
\num ->
|
||||
Expect.equal num expectedNum
|
||||
, test "this should never get run" <|
|
||||
\() ->
|
||||
Expect.fail "Test.only is broken! This should not have been run."
|
||||
]
|
||||
, -- Test.only does not affect seed distribution
|
||||
describe "Seed test"
|
||||
[ test "Autofail" <|
|
||||
\_ -> Expect.fail "Test.only is broken! This should not have been run."
|
||||
, fuzzTest
|
||||
, only <|
|
||||
fuzzTestAfterOneDistributed
|
||||
]
|
||||
, -- the previous test gets the same answer if Test.only is removed
|
||||
describe "Seed test"
|
||||
[ test "Autofail" <|
|
||||
\_ -> Expect.pass
|
||||
, fuzzTest
|
||||
, fuzzTestAfterOneDistributed
|
||||
]
|
||||
]
|
||||
175
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Tests.elm
vendored
Normal file
175
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/Tests.elm
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
module Tests exposing (all)
|
||||
|
||||
import Expect exposing (FloatingPointTolerance(Absolute, AbsoluteOrRelative, Relative))
|
||||
import FloatWithinTests exposing (floatWithinTests)
|
||||
import Fuzz exposing (..)
|
||||
import FuzzerTests exposing (fuzzerTests)
|
||||
import Helpers exposing (..)
|
||||
import Random.Pcg as Random
|
||||
import RunnerTests
|
||||
import Shrink
|
||||
import Test exposing (..)
|
||||
import Test.Expectation exposing (Expectation(..))
|
||||
import Test.Runner
|
||||
import Test.Runner.Failure exposing (Reason(..))
|
||||
|
||||
|
||||
all : Test
|
||||
all =
|
||||
Test.concat
|
||||
[ readmeExample
|
||||
, regressions
|
||||
, testTests
|
||||
, expectationTests
|
||||
, fuzzerTests
|
||||
, floatWithinTests
|
||||
, RunnerTests.all
|
||||
]
|
||||
|
||||
|
||||
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"
|
||||
, fuzz string "restores the original string if you run it again" <|
|
||||
\randomlyGeneratedString ->
|
||||
randomlyGeneratedString
|
||||
|> String.reverse
|
||||
|> String.reverse
|
||||
|> Expect.equal randomlyGeneratedString
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
expectationTests : Test
|
||||
expectationTests =
|
||||
describe "Expectations"
|
||||
[ describe "Expect.err"
|
||||
[ test "passes on Err _" <|
|
||||
\_ ->
|
||||
Err 12 |> Expect.err
|
||||
, expectToFail <|
|
||||
test "passes on Ok _" <|
|
||||
\_ ->
|
||||
Ok 12 |> Expect.err
|
||||
]
|
||||
, describe "Expect.all"
|
||||
[ expectToFail <|
|
||||
test "fails with empty list" <|
|
||||
\_ -> "dummy subject" |> Expect.all []
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
regressions : Test
|
||||
regressions =
|
||||
describe "regression tests"
|
||||
[ fuzz (intRange 1 32) "for #39" <|
|
||||
\positiveInt ->
|
||||
positiveInt
|
||||
|> Expect.greaterThan 0
|
||||
, fuzz
|
||||
(custom (Random.int 1 8) Shrink.noShrink)
|
||||
"fuzz tests run 100 times"
|
||||
(Expect.notEqual 5)
|
||||
|> expectToFail
|
||||
|
||||
{- If fuzz tests actually run 100 times, then asserting that no number
|
||||
in 1..8 equals 5 fails with 0.999998 probability. If they only run
|
||||
once, or stop after a duplicate due to #127, then it's much more
|
||||
likely (but not guaranteed) that the 5 won't turn up. See #128.
|
||||
-}
|
||||
]
|
||||
|
||||
|
||||
testTests : Test
|
||||
testTests =
|
||||
describe "functions that create tests"
|
||||
[ describe "describe"
|
||||
[ expectToFail <| describe "fails with empty list" []
|
||||
, expectToFail <| describe "" [ test "describe with empty description fail" expectPass ]
|
||||
]
|
||||
, describe "test"
|
||||
[ expectToFail <| test "" expectPass
|
||||
]
|
||||
, describe "fuzz"
|
||||
[ expectToFail <| fuzz Fuzz.bool "" expectPass
|
||||
]
|
||||
, describe "fuzzWith"
|
||||
[ expectToFail <| fuzzWith { runs = 0 } Fuzz.bool "nonpositive" expectPass
|
||||
, expectToFail <| fuzzWith { runs = 1 } Fuzz.bool "" expectPass
|
||||
]
|
||||
, describe "Test.todo"
|
||||
[ expectToFail <| todo "a TODO test fails"
|
||||
, test "Passes are not TODO"
|
||||
(\_ -> Expect.pass |> Test.Runner.isTodo |> Expect.false "was true")
|
||||
, test "Simple failures are not TODO" <|
|
||||
\_ ->
|
||||
Expect.fail "reason" |> Test.Runner.isTodo |> Expect.false "was true"
|
||||
, test "Failures with TODO reason are TODO" <|
|
||||
\_ ->
|
||||
Test.Expectation.fail { description = "", reason = TODO }
|
||||
|> Test.Runner.isTodo
|
||||
|> Expect.true "was false"
|
||||
]
|
||||
, identicalNamesAreRejectedTests
|
||||
]
|
||||
|
||||
|
||||
identicalNamesAreRejectedTests : Test
|
||||
identicalNamesAreRejectedTests =
|
||||
describe "Identically-named sibling and parent/child tests fail"
|
||||
[ expectToFail <|
|
||||
describe "a describe with two identically named children fails"
|
||||
[ test "foo" expectPass
|
||||
, test "foo" expectPass
|
||||
]
|
||||
, expectToFail <|
|
||||
describe "a describe with the same name as a child test fails"
|
||||
[ test "a describe with the same name as a child test fails" expectPass
|
||||
]
|
||||
, expectToFail <|
|
||||
describe "a describe with the same name as a child describe fails"
|
||||
[ describe "a describe with the same name as a child describe fails"
|
||||
[ test "a test" expectPass ]
|
||||
]
|
||||
, expectToFail <|
|
||||
Test.concat
|
||||
[ describe "a describe with the same name as a sibling describe fails"
|
||||
[ test "a test" expectPass ]
|
||||
, describe "a describe with the same name as a sibling describe fails"
|
||||
[ test "another test" expectPass ]
|
||||
]
|
||||
, expectToFail <|
|
||||
Test.concat
|
||||
[ Test.concat
|
||||
[ describe "a describe with the same name as a de facto sibling describe fails"
|
||||
[ test "a test" expectPass ]
|
||||
]
|
||||
, describe "a describe with the same name as a de facto sibling describe fails"
|
||||
[ test "another test" expectPass ]
|
||||
]
|
||||
, expectToFail <|
|
||||
Test.concat
|
||||
[ Test.concat
|
||||
[ describe "a describe with the same name as a de facto sibling describe fails"
|
||||
[ test "a test" expectPass ]
|
||||
]
|
||||
, Test.concat
|
||||
[ describe "a describe with the same name as a de facto sibling describe fails"
|
||||
[ test "another test" expectPass ]
|
||||
]
|
||||
]
|
||||
]
|
||||
20
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/elm-package.json
vendored
Normal file
20
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/elm-package.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"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": {
|
||||
"eeue56/elm-lazy-list": "1.0.0 <= v < 2.0.0",
|
||||
"eeue56/elm-shrink": "1.0.0 <= v < 2.0.0",
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"jinjor/elm-diff": "1.0.0 <= v < 2.0.0",
|
||||
"eeue56/elm-lazy": "1.0.0 <= v < 2.0.0",
|
||||
"mgold/elm-random-pcg": "4.0.2 <= v < 5.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
22
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/package.json
vendored
Normal file
22
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.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"
|
||||
}
|
||||
}
|
||||
22
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/run-tests.js
vendored
Normal file
22
part5/tests/elm-stuff/packages/elm-community/elm-test/4.2.0/tests/run-tests.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
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);
|
||||
});
|
||||
4
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/.gitignore
vendored
Normal file
4
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Ignore build or dist files
|
||||
elm-stuff
|
||||
node_modules
|
||||
tests/Doc
|
||||
36
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/.travis.yml
vendored
Normal file
36
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/.travis.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js: "node"
|
||||
os: linux
|
||||
env: ELM_VERSION=0.18.0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- test/elm-stuff/build-artifacts
|
||||
- sysconfcpus
|
||||
|
||||
before_install:
|
||||
- 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:
|
||||
- node --version
|
||||
- npm --version
|
||||
- cd tests
|
||||
- npm install -g elm@$ELM_VERSION
|
||||
- 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
|
||||
68
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/CHANGELOG.md
vendored
Normal file
68
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
### 2.6.0
|
||||
|
||||
**Additions:**
|
||||
- `keys` allows extracting _only_ the keys from a JSON object
|
||||
|
||||
### 2.5.0
|
||||
|
||||
**Additions:**
|
||||
- `dict` helps encoding `Dict`
|
||||
|
||||
### 2.4.0
|
||||
|
||||
**Additions:**
|
||||
- `collection` helps with decoding array-like JavaScript structures such as `HTMLCollection`
|
||||
- `combine` helps combining a `List` of decoders into a single `Decoder` for a `List` of such things
|
||||
|
||||
### 2.3.0
|
||||
|
||||
**Additions:**
|
||||
- `indexedList` to get access to the current js array index while decoding
|
||||
|
||||
**Other Stuff:**
|
||||
- `elm-doc-test` is now `elm-verify-examples`!
|
||||
|
||||
### 2.2.0
|
||||
|
||||
**Additions:**
|
||||
- `parseInt` and `parseFloat` for weird api's that return numbers as strings
|
||||
- `doubleEncoded` for a more generic _json as a string in json_ issues
|
||||
|
||||
**Fixes:**
|
||||
- `optionalField` decodes the field, rather than the surrounding object now.
|
||||
|
||||
**Other Stuff:**
|
||||
- Code Style conforms to elm-format@exp
|
||||
- Doc tests!
|
||||
- Travis integration
|
||||
|
||||
### 2.1.0
|
||||
|
||||
**Additions:**
|
||||
- `optionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe.Maybe a)` - Decode an optional field, succeeding with `Nothing` if it is missing, but still giving an error if it is malformed.
|
||||
|
||||
### 2.0.0
|
||||
|
||||
**Breaking Changes:**
|
||||
- Upgrade for Elm 0.18
|
||||
- Removed `maybeNull` in favor of `Json.Decode.nullable`
|
||||
- Removed `lazy` in favor of `Json.Decode.lazy`
|
||||
- Renamed `apply` to `andMap` and reversed arguments to `Decoder a -> Decoder (a -> b) -> Decoder b` to make it work nicely with `(|>)`
|
||||
|
||||
**Additions:**
|
||||
- `fromResult : Result String a -> Decoder a` - convert a `Result` to a `Decoder`, helpful in `andThen` callbacks following the removal of `Json.Decode.customDecoder`
|
||||
- `Json.Encode.Extra.maybe : (a -> Value) -> Maybe a -> Value` - encode a `Maybe a` given an encoder for `a`. Thanks to @hendore for this addition.
|
||||
|
||||
**Other Stuff:**
|
||||
- Code style conforms to elm-format
|
||||
|
||||
#### 1.1.0
|
||||
|
||||
**Additions:**
|
||||
- `Json.Decode.Extra.sequence` - lets you generate a list of `Decoder a` and attempt to apply them to a JSON list. _Authored by @cobalamin_
|
||||
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
**Breaking Changes:**
|
||||
- Upgrade for Elm 0.17
|
||||
21
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/LICENSE
vendored
Normal file
21
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 CircuitHub Inc., Elm Community members
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
9
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/README.md
vendored
Normal file
9
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/README.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[](https://travis-ci.org/elm-community/json-extra)
|
||||
|
||||
# json-extra
|
||||
|
||||
```
|
||||
elm-package install elm-community/json-extra
|
||||
```
|
||||
|
||||
Convenience functions for working with JSON
|
||||
61
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/docs/andMap.md
vendored
Normal file
61
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/docs/andMap.md
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
## Json.Decode.Extra.andMap
|
||||
|
||||
Imagine you have a data type for a user
|
||||
|
||||
```elm
|
||||
import Date (Date)
|
||||
|
||||
type alias User =
|
||||
{ id : Int
|
||||
, createdAt : Date
|
||||
, updatedAt : Date
|
||||
, deletedAt : Maybe Date
|
||||
, username : Maybe String
|
||||
, email : Maybe String
|
||||
, isAdmin : Bool
|
||||
}
|
||||
```
|
||||
|
||||
You can use `andMap` to incrementally apply decoders to your `User` type alias
|
||||
by using that type alias as a function. Recall that record type aliases are
|
||||
also functions which accept arguments in the order their fields are declared. In
|
||||
this case, `User` looks like
|
||||
|
||||
```elm
|
||||
User : Int -> Date -> Date -> Maybe Date -> Maybe String -> Maybe String -> Bool -> User
|
||||
```
|
||||
|
||||
And also recall that Elm functions can be partially applied. We can use these
|
||||
properties to apply each field of our JSON object to each field in our user one
|
||||
field at a time. All we need to do is also wrap `User` in a decoder and step
|
||||
through using `andMap`.
|
||||
|
||||
```elm
|
||||
userDecoder : Decoder User
|
||||
userDecoder =
|
||||
succeed User
|
||||
|> andMap (field "id" int)
|
||||
|> andMap (field "createdAt" date)
|
||||
|> andMap (field "updatedAt" date)
|
||||
|> andMap (field "deletedAt" (maybe date))
|
||||
|> andMap (field "username" (maybe string))
|
||||
|> andMap (field "email" (maybe string))
|
||||
|> andMap (field "isAdmin" bool)
|
||||
```
|
||||
|
||||
This is a shortened form of
|
||||
|
||||
```elm
|
||||
userDecoder : Decoder User
|
||||
userDecoder =
|
||||
succeed User
|
||||
|> andThen (\f -> map f (field "id" int))
|
||||
|> andThen (\f -> map f (field "createdAt" date))
|
||||
|> andThen (\f -> map f (field "updatedAt" date))
|
||||
|> andThen (\f -> map f (field "deletedAt" (maybe date)))
|
||||
|> andThen (\f -> map f (field "username" (maybe string)))
|
||||
|> andThen (\f -> map f (field "email" (maybe string)))
|
||||
|> andThen (\f -> map f (field "isAdmin" bool))
|
||||
```
|
||||
|
||||
See also: The [docs for `(|:)`](https://github.com/elm-community/json-extra/blob/master/docs/infixAndMap.md)
|
||||
131
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/docs/infixAndMap.md
vendored
Normal file
131
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/docs/infixAndMap.md
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
## Json.Decode.Extra.(|:)
|
||||
|
||||
|
||||
Infix version of `andMap` that makes for a nice DSL when decoding objects.
|
||||
|
||||
Consider the following type alias for a `Location`:
|
||||
|
||||
```elm
|
||||
type alias Location =
|
||||
{ id : Int
|
||||
, name : String
|
||||
, address : String
|
||||
}
|
||||
```
|
||||
|
||||
We can use `(|:)` to build up a decoder for `Location`:
|
||||
|
||||
```elm
|
||||
locationDecoder : Decoder Location
|
||||
locationDecoder =
|
||||
succeed Location
|
||||
|: (field "id" int)
|
||||
|: (field "name" string)
|
||||
|: (field "address" string)
|
||||
```
|
||||
|
||||
|
||||
|
||||
If you're curious, here's how this works behind the scenes, read on.
|
||||
|
||||
`Location` is a type alias, and type aliases give you a convenience function
|
||||
that returns an instance of the record in question. Try this out in `elm-repl`:
|
||||
|
||||
```elm
|
||||
> type alias Location = { id : Int, name: String, address: String }
|
||||
|
||||
> Location
|
||||
<function> : Int -> String -> String -> Repl.Location
|
||||
|
||||
> Location 1 "The White House" "1600 Pennsylvania Ave"
|
||||
{ id = 1, name = "The White House", address = "1600 Pennsylvania Ave" }
|
||||
```
|
||||
|
||||
In other words, if you call the `Location` function, passing three arguments,
|
||||
it will return a new `Location` record by filling in each of its fields. (The
|
||||
argument order is based on the order in which we listed the fields in the
|
||||
type alias; the first argument sets `id`, the second argument sets `name`, etc.)
|
||||
|
||||
Now try running this through `elm-repl`:
|
||||
|
||||
```elm
|
||||
> import Json.Decode exposing (succeed, int, string, field)
|
||||
|
||||
> succeed Location
|
||||
<function>
|
||||
: Json.Decode.Decoder
|
||||
(Int -> String -> String -> Repl.Location)
|
||||
```
|
||||
|
||||
So `succeed Location` gives us a `Decoder (Int -> String -> String -> Location)`.
|
||||
That's not what we want! What we want is a `Decoder Location`. All we have so
|
||||
far is a `Decoder` that wraps not a `Location`, but rather a function that
|
||||
returns a `Location`.
|
||||
|
||||
What `|: (field "id" int)` does is to take that wrapped function and pass an
|
||||
argument to it.
|
||||
|
||||
```elm
|
||||
> import Json.Decode exposing (succeed, int, string, field)
|
||||
|
||||
> (field "id" int)
|
||||
<function> : Json.Decode.Decoder Int
|
||||
|
||||
> succeed Location |: (field "id" int)
|
||||
<function>
|
||||
: Json.Decode.Decoder
|
||||
(String -> String -> Repl.Location)
|
||||
```
|
||||
|
||||
Notice how the wrapped function no longer takes an `Int` as its first argument.
|
||||
That's because `(|:)` went ahead and supplied one: the `Int` wrapped by the decoder
|
||||
`(field "id" int)` (which returns a `Decoder Int`).
|
||||
|
||||
Compare:
|
||||
|
||||
```elm
|
||||
> succeed Location
|
||||
Decoder (Int -> String -> String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int)
|
||||
Decoder (String -> String -> Location)
|
||||
```
|
||||
|
||||
We still want a `Decoder Location` and we still don't have it yet. Our decoder
|
||||
still wraps a function instead of a plain `Location`. However, that function is
|
||||
now smaller by one argument!
|
||||
|
||||
Let's repeat this pattern to provide the first `String` argument next.
|
||||
|
||||
```elm
|
||||
> succeed Location
|
||||
Decoder (Int -> String -> String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int)
|
||||
Decoder (String -> String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int) |: (field "name" string)
|
||||
Decoder (String -> Location)
|
||||
```
|
||||
|
||||
Smaller and smaller! Now we're down from `(Int -> String -> String -> Location)`
|
||||
to `(String -> Location)`. What happens if we repeat the pattern one more time?
|
||||
|
||||
```elm
|
||||
> succeed Location
|
||||
Decoder (Int -> String -> String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int)
|
||||
Decoder (String -> String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int) |: (field "name" string)
|
||||
Decoder (String -> Location)
|
||||
|
||||
> succeed Location |: (field "id" int) |: (field "name" string) |: (field "address" string)
|
||||
Decoder Location
|
||||
```
|
||||
|
||||
Having now supplied all three arguments to the wrapped function, it has ceased
|
||||
to be a function. It's now just a plain old `Location`, like we wanted all along.
|
||||
|
||||
We win!
|
||||
17
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/elm-package.json
vendored
Normal file
17
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/elm-package.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "2.6.0",
|
||||
"summary": "Convenience functions for working with Json",
|
||||
"repository": "https://github.com/elm-community/json-extra.git",
|
||||
"license": "MIT",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"exposed-modules": [
|
||||
"Json.Decode.Extra",
|
||||
"Json.Encode.Extra"
|
||||
],
|
||||
"dependencies": {
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
2642
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/package-lock.json
generated
vendored
Normal file
2642
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/package.json
vendored
Normal file
9
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/package.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"elm-test": "^0.18.9",
|
||||
"elm-verify-examples": "^1.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "elm-verify-examples && elm-test"
|
||||
}
|
||||
}
|
||||
434
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/src/Json/Decode/Extra.elm
vendored
Normal file
434
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/src/Json/Decode/Extra.elm
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
module Json.Decode.Extra
|
||||
exposing
|
||||
( (|:)
|
||||
, andMap
|
||||
, collection
|
||||
, combine
|
||||
, date
|
||||
, dict2
|
||||
, doubleEncoded
|
||||
, fromResult
|
||||
, indexedList
|
||||
, keys
|
||||
, optionalField
|
||||
, parseFloat
|
||||
, parseInt
|
||||
, sequence
|
||||
, set
|
||||
, withDefault
|
||||
)
|
||||
|
||||
{-| Convenience functions for working with Json
|
||||
|
||||
Examples assume the following imports:
|
||||
|
||||
import Json.Decode exposing (..)
|
||||
import Date
|
||||
import Set
|
||||
import Dict
|
||||
|
||||
|
||||
# Date
|
||||
|
||||
@docs date
|
||||
|
||||
|
||||
# Incremental Decoding
|
||||
|
||||
@docs andMap, (|:)
|
||||
|
||||
|
||||
# List
|
||||
|
||||
@docs collection, sequence, combine, indexedList, keys
|
||||
|
||||
|
||||
# Set
|
||||
|
||||
@docs set
|
||||
|
||||
|
||||
# Dict
|
||||
|
||||
@docs dict2
|
||||
|
||||
|
||||
# Maybe
|
||||
|
||||
@docs withDefault, optionalField
|
||||
|
||||
|
||||
# Result
|
||||
|
||||
@docs fromResult
|
||||
|
||||
|
||||
# Encoded strings
|
||||
|
||||
@docs parseInt, parseFloat, doubleEncoded
|
||||
|
||||
-}
|
||||
|
||||
import Date
|
||||
import Dict exposing (Dict)
|
||||
import Json.Decode exposing (..)
|
||||
import Set exposing (Set)
|
||||
import String
|
||||
|
||||
|
||||
{-| Can be helpful when decoding large objects incrementally.
|
||||
|
||||
See [the `andMap` docs](https://github.com/elm-community/json-extra/blob/2.0.0/docs/andMap.md)
|
||||
for an explanation of how `andMap` works and how to use it.
|
||||
|
||||
-}
|
||||
andMap : Decoder a -> Decoder (a -> b) -> Decoder b
|
||||
andMap =
|
||||
map2 (|>)
|
||||
|
||||
|
||||
{-| Infix version of `andMap` that makes for a nice DSL when decoding objects.
|
||||
|
||||
See [the `(|:)` docs](https://github.com/elm-community/json-extra/blob/2.0.0/docs/infixAndMap.md)
|
||||
for an explanation of how `(|:)` works and how to use it.
|
||||
|
||||
-}
|
||||
(|:) : Decoder (a -> b) -> Decoder a -> Decoder b
|
||||
(|:) =
|
||||
flip andMap
|
||||
|
||||
|
||||
{-| Extract a date using [`Date.fromString`](http://package.elm-lang.org/packages/elm-lang/core/latest/Date#fromString)
|
||||
|
||||
""" "2012-04-23T18:25:43.511Z" """
|
||||
|> decodeString date
|
||||
--> Date.fromString "2012-04-23T18:25:43.511Z"
|
||||
|
||||
""" "foo" """
|
||||
|> decodeString date
|
||||
--> Err "I ran into a `fail` decoder: Unable to parse 'foo' as a date. Dates must be in the ISO 8601 format."
|
||||
|
||||
-}
|
||||
date : Decoder Date.Date
|
||||
date =
|
||||
string
|
||||
|> andThen (Date.fromString >> fromResult)
|
||||
|
||||
|
||||
{-| Extract a set.
|
||||
|
||||
"[ 1, 1, 5, 2 ]"
|
||||
|> decodeString (set int)
|
||||
--> Ok <| Set.fromList [ 1, 2, 5 ]
|
||||
|
||||
-}
|
||||
set : Decoder comparable -> Decoder (Set comparable)
|
||||
set decoder =
|
||||
list decoder
|
||||
|> map Set.fromList
|
||||
|
||||
|
||||
{-| Extract a dict using separate decoders for keys and values.
|
||||
|
||||
""" { "1": "foo", "2": "bar" } """
|
||||
|> decodeString (dict2 int string)
|
||||
--> Ok <| Dict.fromList [ ( 1, "foo" ), ( 2, "bar" ) ]
|
||||
|
||||
-}
|
||||
dict2 : Decoder comparable -> Decoder v -> Decoder (Dict comparable v)
|
||||
dict2 keyDecoder valueDecoder =
|
||||
keyValuePairs valueDecoder
|
||||
|> andThen (decodeDictFromTuples keyDecoder)
|
||||
|
||||
|
||||
{-| Helper function for dict
|
||||
-}
|
||||
decodeDictFromTuples : Decoder comparable -> List ( String, v ) -> Decoder (Dict comparable v)
|
||||
decodeDictFromTuples keyDecoder tuples =
|
||||
case tuples of
|
||||
[] ->
|
||||
succeed Dict.empty
|
||||
|
||||
( strKey, value ) :: rest ->
|
||||
case decodeString keyDecoder strKey of
|
||||
Ok key ->
|
||||
decodeDictFromTuples keyDecoder rest
|
||||
|> andThen (Dict.insert key value >> succeed)
|
||||
|
||||
Err error ->
|
||||
fail error
|
||||
|
||||
|
||||
{-| Try running the given decoder; if that fails, then succeed with the given
|
||||
fallback value.
|
||||
|
||||
""" { "children": "oops" } """
|
||||
|> decodeString (field "children" (list string) |> withDefault [])
|
||||
--> Ok []
|
||||
|
||||
""" null """
|
||||
|> decodeString (field "children" (list string) |> withDefault [])
|
||||
--> Ok []
|
||||
|
||||
""" 30 """
|
||||
|> decodeString (int |> withDefault 42)
|
||||
--> Ok 30
|
||||
|
||||
-}
|
||||
withDefault : a -> Decoder a -> Decoder a
|
||||
withDefault fallback decoder =
|
||||
maybe decoder
|
||||
|> map (Maybe.withDefault fallback)
|
||||
|
||||
|
||||
{-| If a field is missing, succeed with `Nothing`. If it is present, decode it
|
||||
as normal and wrap successes in a `Just`.
|
||||
|
||||
When decoding with
|
||||
[`maybe`](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode#maybe),
|
||||
if a field is present but malformed, you get a success and Nothing.
|
||||
`optionalField` gives you a failed decoding in that case, so you know
|
||||
you received malformed data.
|
||||
|
||||
Examples:
|
||||
|
||||
Let's define a `stuffDecoder` that extracts the `"stuff"` field, if it exists.
|
||||
|
||||
stuffDecoder : Decoder (Maybe String)
|
||||
stuffDecoder =
|
||||
optionalField "stuff" string
|
||||
|
||||
If the "stuff" field is missing, decode to Nothing.
|
||||
|
||||
""" { } """
|
||||
|> decodeString stuffDecoder
|
||||
--> Ok Nothing
|
||||
|
||||
If the "stuff" field is present but not a String, fail decoding.
|
||||
|
||||
""" { "stuff": [] } """
|
||||
|> decodeString stuffDecoder
|
||||
--> Err "Expecting a String at _.stuff but instead got: []"
|
||||
|
||||
If the "stuff" field is present and valid, decode to Just String.
|
||||
|
||||
""" { "stuff": "yay!" } """
|
||||
|> decodeString stuffDecoder
|
||||
--> Ok <| Just "yay!"
|
||||
|
||||
-}
|
||||
optionalField : String -> Decoder a -> Decoder (Maybe a)
|
||||
optionalField fieldName decoder =
|
||||
let
|
||||
finishDecoding json =
|
||||
case decodeValue (field fieldName value) json of
|
||||
Ok val ->
|
||||
-- The field is present, so run the decoder on it.
|
||||
map Just (field fieldName decoder)
|
||||
|
||||
Err _ ->
|
||||
-- The field was missing, which is fine!
|
||||
succeed Nothing
|
||||
in
|
||||
value
|
||||
|> andThen finishDecoding
|
||||
|
||||
|
||||
{-| This function turns a list of decoders into a decoder that returns a list.
|
||||
|
||||
The returned decoder will zip the list of decoders with a list of values,
|
||||
matching each decoder with exactly one value at the same position. This is most
|
||||
often useful in cases when you find yourself needing to dynamically generate a
|
||||
list of decoders based on some data, and decode some other data with this list
|
||||
of decoders.
|
||||
|
||||
Note that this function, unlike `List.map2`'s behaviour, expects the list of
|
||||
decoders to have the same length as the list of values in the JSON.
|
||||
|
||||
sequence
|
||||
[ map Just string
|
||||
, succeed Nothing
|
||||
, map Just string
|
||||
]
|
||||
|> flip decodeString """ [ "pick me", "ignore me", "and pick me" ] """
|
||||
--> Ok [ Just "pick me", Nothing, Just "and pick me" ]
|
||||
|
||||
-}
|
||||
sequence : List (Decoder a) -> Decoder (List a)
|
||||
sequence decoders =
|
||||
list value |> andThen (sequenceHelp decoders)
|
||||
|
||||
|
||||
{-| Helper function for sequence
|
||||
-}
|
||||
sequenceHelp : List (Decoder a) -> List Value -> Decoder (List a)
|
||||
sequenceHelp decoders jsonValues =
|
||||
if List.length jsonValues /= List.length decoders then
|
||||
fail "Number of decoders does not match number of values"
|
||||
else
|
||||
List.map2 decodeValue decoders jsonValues
|
||||
|> List.foldr (Result.map2 (::)) (Ok [])
|
||||
|> fromResult
|
||||
|
||||
|
||||
{-| Get access to the current index while decoding a list element.
|
||||
|
||||
repeatedStringDecoder : Int -> Decoder String
|
||||
repeatedStringDecoder times =
|
||||
string |> map (String.repeat times)
|
||||
|
||||
""" [ "a", "b", "c", "d" ] """
|
||||
|> decodeString (indexedList repeatedStringDecoder)
|
||||
--> Ok [ "", "b", "cc", "ddd" ]
|
||||
|
||||
-}
|
||||
indexedList : (Int -> Decoder a) -> Decoder (List a)
|
||||
indexedList indexedDecoder =
|
||||
list value
|
||||
|> andThen
|
||||
(\values ->
|
||||
List.range 0 (List.length values - 1)
|
||||
|> List.map indexedDecoder
|
||||
|> sequence
|
||||
)
|
||||
|
||||
|
||||
{-| Get a list of the keys of a JSON object
|
||||
|
||||
""" { "alice": 42, "bob": 99 } """
|
||||
|> decodeString keys
|
||||
--> Ok [ "alice", "bob" ]
|
||||
|
||||
-}
|
||||
keys : Decoder (List String)
|
||||
keys =
|
||||
keyValuePairs (succeed ())
|
||||
|> map (List.foldl (\( key, _ ) acc -> key :: acc) [])
|
||||
|
||||
|
||||
{-| Transform a result into a decoder
|
||||
|
||||
Sometimes it can be useful to use functions that primarily operate on
|
||||
`Result` in decoders. An example of this is `Json.Decode.Extra.date`. It
|
||||
uses the built-in `Date.fromString` to parse a `String` as a `Date`, and
|
||||
then converts the `Result` from that conversion into a decoder which has
|
||||
either already succeeded or failed based on the outcome.
|
||||
|
||||
validateString : String -> Result String String
|
||||
validateString input =
|
||||
case input of
|
||||
"" ->
|
||||
Err "Empty string is not allowed"
|
||||
_ ->
|
||||
Ok input
|
||||
|
||||
""" "something" """
|
||||
|> decodeString (string |> andThen (fromResult << validateString))
|
||||
--> Ok "something"
|
||||
|
||||
""" "" """
|
||||
|> decodeString (string |> andThen (fromResult << validateString))
|
||||
--> Err "I ran into a `fail` decoder: Empty string is not allowed"
|
||||
|
||||
-}
|
||||
fromResult : Result String a -> Decoder a
|
||||
fromResult result =
|
||||
case result of
|
||||
Ok successValue ->
|
||||
succeed successValue
|
||||
|
||||
Err errorMessage ->
|
||||
fail errorMessage
|
||||
|
||||
|
||||
{-| Extract an int using [`String.toInt`](http://package.elm-lang.org/packages/elm-lang/core/latest/String#toInt)
|
||||
|
||||
""" { "field": "123" } """
|
||||
|> decodeString (field "field" parseInt)
|
||||
--> Ok 123
|
||||
|
||||
-}
|
||||
parseInt : Decoder Int
|
||||
parseInt =
|
||||
string |> andThen (String.toInt >> fromResult)
|
||||
|
||||
|
||||
{-| Extract a float using [`String.toFloat`](http://package.elm-lang.org/packages/elm-lang/core/latest/String#toFloat)
|
||||
|
||||
""" { "field": "50.5" } """
|
||||
|> decodeString (field "field" parseFloat)
|
||||
--> Ok 50.5
|
||||
|
||||
-}
|
||||
parseFloat : Decoder Float
|
||||
parseFloat =
|
||||
string |> andThen (String.toFloat >> fromResult)
|
||||
|
||||
|
||||
{-| Extract a JSON-encoded string field
|
||||
|
||||
"Yo dawg, I heard you like JSON..."
|
||||
|
||||
If someone has put JSON in your JSON (perhaps a JSON log entry, encoded
|
||||
as a string) this is the function you're looking for. Give it a decoder
|
||||
and it will return a new decoder that applies your decoder to a string
|
||||
field and yields the result (or fails if your decoder fails).
|
||||
|
||||
logEntriesDecoder : Decoder (List String)
|
||||
logEntriesDecoder =
|
||||
doubleEncoded (list string)
|
||||
|
||||
logsDecoder : Decoder (List String)
|
||||
logsDecoder =
|
||||
field "logs" logEntriesDecoder
|
||||
|
||||
""" { "logs": "[\\"log1\\", \\"log2\\"]"} """
|
||||
|> decodeString logsDecoder
|
||||
--> Ok [ "log1", "log2" ]
|
||||
|
||||
-}
|
||||
doubleEncoded : Decoder a -> Decoder a
|
||||
doubleEncoded decoder =
|
||||
string |> andThen (fromResult << decodeString decoder)
|
||||
|
||||
|
||||
{-| Helps convering a list of decoders into a decoder for a list of that type.
|
||||
|
||||
decoders : List (Decoder String)
|
||||
decoders =
|
||||
[ field "foo" string
|
||||
, field "bar" string
|
||||
, field "another" string
|
||||
]
|
||||
|
||||
""" { "foo": "hello", "another": "!", "bar": "world" } """
|
||||
|> decodeString (combine decoders)
|
||||
--> Ok [ "hello", "world", "!" ]
|
||||
|
||||
-}
|
||||
combine : List (Decoder a) -> Decoder (List a)
|
||||
combine =
|
||||
List.foldr (map2 (::)) (succeed [])
|
||||
|
||||
|
||||
{-| Some JavaScript structures look like arrays, but aren't really. Examples
|
||||
include `HTMLCollection`, `NodeList` and everything else that has a `length`
|
||||
property, has values indexed by an integer key between 0 and `length`, but yet
|
||||
_is not_ a JavaScript Array.
|
||||
|
||||
This decoder can come to the rescue.
|
||||
|
||||
""" { "length": 3, "0": "foo", "1": "bar", "2": "baz" } """
|
||||
|> decodeString (collection string)
|
||||
--> Ok [ "foo", "bar", "baz" ]
|
||||
|
||||
-}
|
||||
collection : Decoder a -> Decoder (List a)
|
||||
collection decoder =
|
||||
field "length" int
|
||||
|> andThen
|
||||
(\length ->
|
||||
List.range 0 (length - 1)
|
||||
|> List.map (\index -> field (toString index) decoder)
|
||||
|> combine
|
||||
)
|
||||
43
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/src/Json/Encode/Extra.elm
vendored
Normal file
43
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/src/Json/Encode/Extra.elm
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
module Json.Encode.Extra exposing (dict, maybe)
|
||||
|
||||
{-| Convenience functions for turning Elm values into Json values.
|
||||
|
||||
@docs dict, maybe
|
||||
|
||||
-}
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import Json.Encode exposing (Value, encode, int, null, object)
|
||||
|
||||
|
||||
{-| Encode a Maybe value. If the value is `Nothing` it will be encoded as `null`
|
||||
|
||||
import Json.Encode exposing (int, null, encode)
|
||||
|
||||
maybe int (Just 50)
|
||||
--> int 50
|
||||
|
||||
maybe int Nothing
|
||||
--> null
|
||||
|
||||
-}
|
||||
maybe : (a -> Value) -> Maybe a -> Value
|
||||
maybe encoder =
|
||||
Maybe.map encoder >> Maybe.withDefault null
|
||||
|
||||
|
||||
{-| Turn a `Dict` into a JSON object.
|
||||
|
||||
import Dict
|
||||
|
||||
Dict.fromList [ ( "Sue", 38 ), ( "Tom", 42 ) ]
|
||||
|> dict identity int
|
||||
|> encode 0
|
||||
--> """{"Sue":38,"Tom":42}"""
|
||||
|
||||
-}
|
||||
dict : (comparable -> String) -> (v -> Value) -> Dict comparable v -> Value
|
||||
dict toKey toValue dict =
|
||||
Dict.toList dict
|
||||
|> List.map (\( key, value ) -> ( toKey key, toValue value ))
|
||||
|> object
|
||||
16
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/tests/elm-package.json
vendored
Normal file
16
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/tests/elm-package.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "Test Suites",
|
||||
"repository": "https://github.com/elm-community/json-extra.git",
|
||||
"license": "MIT",
|
||||
"source-directories": [
|
||||
"../src",
|
||||
"."
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"dependencies": {
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"elm-community/elm-test": "4.0.0 <= v < 5.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
7
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/tests/elm-verify-examples.json
vendored
Normal file
7
part5/tests/elm-stuff/packages/elm-community/json-extra/2.6.0/tests/elm-verify-examples.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"root": "../src",
|
||||
"tests": [
|
||||
"Json.Encode.Extra",
|
||||
"Json.Decode.Extra"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user