Giter Club home page Giter Club logo

tasty's Introduction

Tasty

Tasty is a modern testing framework for Haskell.

It lets you combine your unit tests, golden tests, QuickCheck/SmallCheck properties, and any other types of tests into a single test suite.

Features:

  • Run tests in parallel but report results in a deterministic order
  • Filter the tests to be run using patterns specified on the command line
  • Hierarchical, colored display of test results
  • Reporting of test statistics
  • Acquire and release resources (sockets, temporary files etc.) that can be shared among several tests
  • Extensibility: add your own test providers and ingredients (runners) above and beyond those provided

To find out what's new, read the change log.

Example

Here's how your test.hs might look like:

import Test.Tasty
import Test.Tasty.SmallCheck as SC
import Test.Tasty.QuickCheck as QC
import Test.Tasty.HUnit

import Data.List
import Data.Ord

main = defaultMain tests

tests :: TestTree
tests = testGroup "Tests" [properties, unitTests]

properties :: TestTree
properties = testGroup "Properties" [scProps, qcProps]

scProps = testGroup "(checked by SmallCheck)"
  [ SC.testProperty "sort == sort . reverse" $
      \list -> sort (list :: [Int]) == sort (reverse list)
  , SC.testProperty "Fermat's little theorem" $
      \x -> ((x :: Integer)^7 - x) `mod` 7 == 0
  -- the following property does not hold
  , SC.testProperty "Fermat's last theorem" $
      \x y z n ->
        (n :: Integer) >= 3 SC.==> x^n + y^n /= (z^n :: Integer)
  ]

qcProps = testGroup "(checked by QuickCheck)"
  [ QC.testProperty "sort == sort . reverse" $
      \list -> sort (list :: [Int]) == sort (reverse list)
  , QC.testProperty "Fermat's little theorem" $
      \x -> ((x :: Integer)^7 - x) `mod` 7 == 0
  -- the following property does not hold
  , QC.testProperty "Fermat's last theorem" $
      \x y z n ->
        (n :: Integer) >= 3 QC.==> x^n + y^n /= (z^n :: Integer)
  ]

unitTests = testGroup "Unit tests"
  [ testCase "List comparison (different length)" $
      [1, 2, 3] `compare` [1,2] @?= GT

  -- the following test does not hold
  , testCase "List comparison (same length)" $
      [1, 2, 3] `compare` [1,2,2] @?= LT
  ]

And here is the output of the above program:

(Note that whether QuickCheck finds a counterexample to the third property is determined by chance.)

Packages

tasty is the core package. It contains basic definitions and APIs and a console runner.

In order to create a test suite, you also need to install one or more «providers» (see below).

Providers

The following providers exist:

It's easy to create custom providers using the API from Test.Tasty.Providers.

Ingredients

Ingredients represent different actions that you can perform on your test suite. One obvious ingredient that you want to include is one that runs tests and reports the progress and results.

Another standard ingredient is one that simply prints the names of all tests.

It is possible to write custom ingredients using the API from Test.Tasty.Runners.

Some ingredients that can enhance your test suite are:

  • tasty-ant-xml adds a possibility to write the test results in a machine-readable XML format, which is understood by various CI systems and IDEs
  • tasty-rerun adds support for minimal test reruns by recording previous test runs and using this information to filter the test tree. For example, you can use this ingredient to only run failed tests, or only run tests that threw an exception.
  • tasty-html adds the possibility to write the test results as a HTML file
  • tasty-stats adds the possibility to collect statistics of the test suite in a CSV file.

Test discovery

tasty by itself forces you to explicitly write out the TestTree yourself. The packages listed below allow you to write tests at the top-level, and will automatically collect them into a single TestTree.

Other packages

  • tasty-hunit-adapter converts existing HUnit test suites into tasty test suites
  • tasty-expected-failure provides test markers for when you expect failures or wish to ignore tests.
  • tasty-bench covers performance regression testing and extends tasty to a benchmark framework similar to criterion and gauge.

Options

Options allow one to customize the run-time behavior of the test suite, such as:

  • mode of operation (run tests, list tests, run tests quietly etc.)
  • which tests are run (see «Patterns» below)
  • parameters of individual providers (like depth of search for SmallCheck)

Setting options

There are two main ways to set options:

Runtime

When using the standard console runner, the options can be passed on the command line or via environment variables. To see the available options, run your test suite with the --help flag. The output will look something like this (depending on which ingredients and providers the test suite uses):

% ./test --help
Mmm... tasty test suite

Usage: test [-p|--pattern PATTERN] [-t|--timeout DURATION] [--no-progress]
            [-l|--list-tests] [-j|--num-threads NUMBER] [-q|--quiet]
            [--hide-successes] [--color never|always|auto] [--ansi-tricks ARG]
            [--smallcheck-depth NUMBER] [--smallcheck-max-count NUMBER]
            [--quickcheck-tests NUMBER] [--quickcheck-replay SEED]
            [--quickcheck-show-replay] [--quickcheck-max-size NUMBER]
            [--quickcheck-max-ratio NUMBER] [--quickcheck-verbose]
            [--quickcheck-shrinks NUMBER]

Available options:
  -h,--help                Show this help text
  -p,--pattern PATTERN     Select only tests which satisfy a pattern or awk
                           expression
  -t,--timeout DURATION    Timeout for individual tests (suffixes: ms,s,m,h;
                           default: s)
  --no-progress            Do not show progress
  -l,--list-tests          Do not run the tests; just print their names
  -j,--num-threads NUMBER  Number of threads to use for tests execution
                           (default: # of cores/capabilities)
  -q,--quiet               Do not produce any output; indicate success only by
                           the exit code
  --hide-successes         Do not print tests that passed successfully
  --min-duration-to-report DURATION
                           The minimum amount of time a test can take before
                           tasty prints timing information (suffixes: ms,s,m,h;
                           default: s)
  --color never|always|auto
                           When to use colored output (default: auto)
  --ansi-tricks ARG        Enable various ANSI terminal tricks. Can be set to
                           'true' or 'false'. (default: true)
  --smallcheck-depth NUMBER
                           Depth to use for smallcheck tests
  --smallcheck-max-count NUMBER
                           Maximum smallcheck test count
  --quickcheck-tests NUMBER
                           Number of test cases for QuickCheck to generate.
                           Underscores accepted: e.g. 10_000_000
  --quickcheck-replay SEED Random seed to use for replaying a previous test run
                           (use same --quickcheck-max-size)
  --quickcheck-show-replay Show a replay token for replaying tests
  --quickcheck-max-size NUMBER
                           Size of the biggest test cases quickcheck generates
  --quickcheck-max-ratio NUMBER
                           Maximum number of discared tests per successful test
                           before giving up
  --quickcheck-verbose     Show the generated test cases
  --quickcheck-shrinks NUMBER
                           Number of shrinks allowed before QuickCheck will fail
                           a test

Every option can be passed via environment. To obtain the environment variable name from the option name, replace hyphens - with underscores _, capitalize all letters, and prepend TASTY_. For example, the environment equivalent of --smallcheck-depth is TASTY_SMALLCHECK_DEPTH.

Note on boolean options: by convention, boolean ("on/off") options are specified using a switch on the command line, for example --quickcheck-show-replay instead of --quickcheck-show-replay=true. However, when passed via the environment, the option value needs to be True or False (case-insensitive), e.g. TASTY_QUICKCHECK_SHOW_REPLAY=true.

If you're using a non-console runner, please refer to its documentation to find out how to configure options during the run time.

Compile-time

You can also specify options in the test suite itself, using localOption. It can be applied not only to the whole test tree, but also to individual tests or subgroups, so that different tests can be run with different options.

It is possible to combine run-time and compile-time options, too, by using adjustOption. For example, make the overall testing depth configurable during the run time, but increase or decrease it slightly for individual tests.

This method currently doesn't work for ingredient options, such as --quiet or --num-threads. You can set them by setting the corresponding environment variable before calling defaultMain:

import Test.Tasty
import System.Environment

main = do
  setEnv "TASTY_NUM_THREADS" "1"
  defaultMain _

It is possible to restrict the set of executed tests using the -p/--pattern option.

Tasty patterns are very powerful, but if you just want to quickly run tests containing foo somewhere in their name or in the name of an enclosing test group, you can just pass -p foo. If you need more power, or if that didn't work as expected, read on.

A pattern is an awk expression. When the expression is evaluated, the field $1 is set to the outermost test group name, $2 is set to the next test group name, and so on up to $NF, which is set to the test's own name. The field $0 is set to all other fields concatenated using . as a separator.

As an example, consider a test inside two test groups:

  testGroup "One" [ testGroup "Two" [ testCase "Three" _ ] ]

When a pattern is evaluated for the above test case, the available fields and variables are:

$0 = "One.Two.Three"
$1 = "One"
$2 = "Two"
$3 = "Three"
NF = 3

Here are some examples of awk expressions accepted as patterns:

  • $2 == "Two" — select the subgroup Two
  • $2 == "Two" && $3 == "Three" — select the test or subgroup named Three in the subgroup named Two
  • $2 == "Two" || $2 == "Twenty-two" — select two subgroups
  • $0 !~ /skip/ or ! /skip/ — select tests whose full names (including group names) do not contain the word skip
  • $NF !~ /skip/ — select tests whose own names (but not group names) do not contain the word skip
  • $(NF-1) ~ /QuickCheck/ — select tests whose immediate parent group name contains QuickCheck

As an extension to the awk expression language, if a pattern pat contains only letters, digits, and characters from the set ._ - (period, underscore, space, hyphen), it is treated like /pat/ (and therefore matched against $0). This is so that we can use -p foo as a shortcut for -p /foo/.

The only deviation from awk that you will likely notice is that Tasty does not implement regular expression matching. Instead, $1 ~ /foo/ means that the string foo occurs somewhere in $1, case-sensitively. We want to avoid a heavy dependency of regex-tdfa or similar libraries; however, if there is demand, regular expression support could be added under a cabal flag.

The following operators are supported (in the order of decreasing precedence):

Syntax

Name

Type of Result

Associativity

(expr)

Grouping

Type of expr

N/A

$expr

Field reference

String

N/A

!expr

-expr

Logical not

Unary minus

Numeric

Numeric

N/A

N/A

expr + expr

expr - expr

Addition

Subtraction

Numeric

Numeric

Left

Left

expr expr

String concatenation

String

Right

expr < expr

expr <= expr

expr != expr

expr == expr

expr > expr

expr >= expr

Less than

Less than or equal to

Not equal to

Equal to

Greater than

Greater than or equal to

Numeric

Numeric

Numeric

Numeric

Numeric

Numeric

None

None

None

None

None

None

expr ~ pat

expr !~ pat

(pat must be a literal, not an expression, e.g. /foo/)

Substring match

No substring match

Numeric

Numeric

None

None

expr && expr

Logical AND

Numeric

Left

expr || expr

Logical OR

Numeric

Left

expr1 ? expr2 : expr3

Conditional expression

Type of selected
expr2 or expr3

Right

The following built-in functions are supported:

substr(s, m[, n])

Return the at most n-character substring of s that begins at position m, numbering from 1. If n is omitted, or if n specifies more characters than are left in the string, the length of the substring will be limited by the length of the string s.

tolower(s)

Convert the string s to lower case.

toupper(s)

Convert the string s to upper case.

match(s, pat)

Return the position, in characters, numbering from 1, in string s where the pattern pat occurs, or zero if it does not occur at all. pat must be a literal, not an expression, e.g. /foo/.

length([s])

Return the length, in characters, of its argument taken as a string, or of the whole record, $0, if there is no argument.

Running tests in parallel

In order to run tests in parallel, you have to do the following:

  • Compile (or, more precisely, link) your test program with the -threaded flag;
  • Launch the program with +RTS -N -RTS.

Timeout

To apply timeout to individual tests, use the --timeout (or -t) command-line option, or set the option in your test suite using the mkTimeout function.

Timeouts can be fractional, and can be optionally followed by a suffix ms (milliseconds), s (seconds), m (minutes), or h (hours). When there's no suffix, seconds are assumed.

Example:

./test --timeout=0.5m

sets a 30 seconds timeout for each individual test.

Options controlling console output

The following options control behavior of the standard console interface:

-q,--quiet
Run the tests but don't output anything. The result is indicated only by the exit code, which is 1 if at least one test has failed, and 0 if all tests have passed. Execution stops when the first failure is detected, so not all tests are necessarily run. This may be useful for various batch systems, such as commit hooks.
--hide-successes
Report only the tests that has failed. Especially useful when the number of tests is large.
-l,--list-tests
Don't run the tests; only list their names, in the format accepted by --pattern.
--color
Whether to produce colorful output. Accepted values: never, always, auto. auto means that colors will only be enabled when output goes to a terminal and is the default value.

Custom options

It is possible to add custom options, too.

To do that,

  1. Define a datatype to represent the option, and make it an instance of IsOption
  2. Register the options with the includingOptions ingredient
  3. To query the option value, use askOption.

See the Custom options in Tasty article for some examples.

Project organization and integration with Cabal

There may be several ways to organize your project. What follows is not Tasty's requirements but my recommendations.

Tests for a library

Place your test suite sources in a dedicated subdirectory (called tests here) instead of putting them among the main library sources.

The directory structure will be as follows:

my-project/
  my-project.cabal
  src/
    ...
  tests/
    test.hs
    Mod1.hs
    Mod2.hs
    ...

test.hs is where your main function is defined. The tests may be contained in test.hs or spread across multiple modules (Mod1.hs, Mod2.hs, ...) which are then imported by test.hs.

Add the following section to the cabal file (my-project.cabal):

test-suite test
  default-language:
    Haskell2010
  type:
    exitcode-stdio-1.0
  hs-source-dirs:
    tests
  main-is:
    test.hs
  build-depends:
      base >= 4 && < 5
    , tasty >= 0.7 -- insert the current version here
    , my-project   -- depend on the library we're testing
    , ...

Tests for a program

All the above applies, except you can't depend on the library if there's no library. You have two options:

  • Re-organize the project into a library and a program, so that both the program and the test suite depend on this new library. The library can be declared in the same cabal file.
  • Add your program sources directory to the Hs-source-dirs. Note that this will lead to double compilation (once for the program and once for the test suite).

Dependencies

Tasty executes tests in parallel to make them finish faster. If this parallelism is not desirable, you can declare dependencies between tests, so that one test will not start until certain other tests finish.

Dependencies are declared using the after or sequentialTestGroup combinator:

  • after AllFinish "pattern" my_tests will execute the test tree my_tests only after all tests that match the pattern finish.
  • after AllSucceed "pattern" my_tests will execute the test tree my_tests only after all tests that match the pattern finish and only if they all succeed. If at least one dependency fails, then my_tests will be skipped.
  • sequentialTestGroup groupName dependencyType [tree1, tree2, ..] will execute all tests in tree1 first, after which it will execute all tests in tree2, and so forth. Like after, dependencyType can either be set to AllFinish or AllSucceed.

The relevant types are:

after
  :: DependencyType -- ^ whether to run the tests even if some of the dependencies fail
  -> String         -- ^ the pattern
  -> TestTree       -- ^ the subtree that depends on other tests
  -> TestTree       -- ^ the subtree annotated with dependency information

sequentialTestGroup
  :: TestName       -- ^ name of the group
  -> DependencyType -- ^ whether to run the tests even if some of the dependencies fail
  -> [TestTree]     -- ^ trees to execute sequentially
  -> TestTree

data DependencyType = AllSucceed | AllFinish

The pattern follows the same AWK-like syntax and semantics as described in Patterns. There is also a variant named after_ that accepts the AST of the pattern instead of a textual representation.

Let's consider some typical examples. (A note about terminology: here by "resource" I mean anything stateful and external to the test: it could be a file, a database record, or even a value stored in an IORef that's shared among tests. The resource may or may not be managed by withResource.)

  1. Two tests, Test A and Test B, access the same shared resource and cannot be run concurrently. To achieve this, make Test A a dependency of Test B:

    testGroup "Tests accessing the same resource"
      [ testCase "Test A" $ ...
      , after AllFinish "Test A" $
          testCase "Test B" $ ...
      ]
  2. Test A creates a resource and Test B uses that resource. Like above, we make Test A a dependency of Test B, except now we don't want to run Test B if Test A failed because the resource may not have been set up properly. So we use AllSucceed instead of AllFinish

    testGroup "Tests creating and using a resource"
      [ testCase "Test A" $ ...
      , after AllSucceed "Test A" $
          testCase "Test B" $ ...
      ]

Here are some caveats to keep in mind when using patterns to specify dependencies in Tasty:

  1. If Test B depends on Test A, remember that either of them may be filtered out using the --pattern option. Collecting the dependency info happens after filtering. Therefore, if Test A is filtered out, Test B will run unconditionally, and if Test B is filtered out, it simply won't run.

  2. Tasty does not currently check whether the pattern in a dependency matches anything at all, so make sure your patterns are correct and do not contain typos. Fortunately, misspecified dependencies usually lead to test failures and so can be detected that way.

  3. Dependencies shouldn't form a cycle, otherwise Tasty with fail with the message "Test dependencies have cycles." A common cause of this is a test matching its own dependency pattern.

  4. Using dependencies may introduce quadratic complexity. Specifically, resolving dependencies is O(number_of_tests × number_of_dependencies), since each pattern has to be matched against each test name. As a guideline, if you have up to 1000 tests, the overhead will be negligible, but if you have thousands of tests or more, then you probably shouldn't have more than a few dependencies.

    Additionally, it is recommended that the dependencies follow the natural order of tests, i.e. that the later tests in the test tree depend on the earlier ones and not vice versa. If the execution order mandated by the dependencies is sufficiently different from the natural order of tests in the test tree, searching for the next test to execute may also have an overhead quadratic in the number of tests.

Use sequentialTestGroup to mitigate these problems.

FAQ

  1. Q: When my tests write to stdout/stderr, the output is garbled. Why is that and what do I do?

    A: It is not recommended that you print anything to the console when using the console test reporter (which is the default one). See #103 for the discussion.

    Some ideas on how to work around this:

    • Use testCaseSteps (for tasty-hunit only).
    • Use a test reporter that does not print to the console (like tasty-ant-xml).
    • Write your output to files instead.
  2. Q: Why doesn't the --hide-successes option work properly? The test headings show up and/or the output appears garbled.

    A: This can happen sometimes when the terminal is narrower than the output. A workaround is to disable ANSI tricks: pass --ansi-tricks=false on the command line or set TASTY_ANSI_TRICKS=false in the environment.

    See issue #152.

  3. Q: Patterns with slashes do not work on Windows. How can I fix it?

    A: If you are running Git for Windows terminal, it has a habit of converting slashes to backslashes. Set MSYS_NO_PATHCONV=1 when running the Git for Windows terminal and MSYS2_ARG_CONV_EXCL=* when running a MinGW bash directly to prevent this behaviour, or follow other suggestions from Known Issues.

Press

Blog posts and other publications related to tasty. If you wrote or just found something not mentioned here, send a pull request!

GHC version support policy

We only support the GHC/base versions from the last 5 years.

Maintainers

Roman Cheplyaka is the primary maintainer.

Oliver Charles is the backup maintainer. Please get in touch with him if the primary maintainer cannot be reached.

tasty's People

Contributors

amesgen avatar andreasabel avatar asr avatar bennofs avatar bodigrim avatar bollu avatar brandonchinn178 avatar coot avatar decentral1se avatar fabianhjr avatar facundominguez avatar gridaphobe avatar gwils avatar larsrh avatar liskin avatar mankykitty avatar martijnbastiaan avatar mbj avatar merijn avatar minad avatar mitchellwrosen avatar nomeata avatar ocharles avatar phadej avatar rudymatela avatar ryanglscott avatar sergv avatar shimuuar avatar sjakobi avatar unkindpartition avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tasty's Issues

Inter-test dependencies

@jstolarek writes:

I want to run test A first and if it succeeds I want to run test B (if A fails B is skipped).

@joeyh has also requested this feature in #47.

The main problem here is a syntax/API for declaring dependencies. It would be relatively easy for hspec-style monadic test suites, but I don't see a good way to do it using the current list-based interface.

(This could be a reason to move to the monadic interface. But it's a big change, and I'd like to explore other options first.)

Output QuickCheck's test classification

QuickCheck allows to classify test cases using classify function. When running such property with quickCheck function the output is:

+++ OK, passed 100 tests (29% Short)

It would be good if tasty could display that information as well.

--hide-successes would be great

We're running a batch of 50,000 tests and are trying to switch from test-framework to tasty.

Actually, test-framework has a bug, where even when you do --hide-successes, it still prints out whitespace for all successful tests, which adds up to a lot of whitespace.

IF tasty could get that feature sans the bug it would be great.

Provide a changelog

I see 0.2 just got released, but there is no CHANGELOG/NEWS/whatever file, nor does the main landing page contain a changelog. It would great if you could include one.

Initialization/finalization hooks

It should be possible to add an initialization/finalization hook to any subtree.

The hooks will be only executed when the tests are run.

It's not clear what to do when we need the result of the initialization phase in the test itself. (Like in bracket.) Note that we don't want to make test itself be dependent (or in IO) as in test-framework, because then we won't be able to analyze the tree statically.

Resource logging clobbering test cases

I have some external resources (using withResource) in a test suite i'm working on that forks some processes that are kept alive for the entire test run. The may do logging and I would like to be able to see that in the tests as well (rather than just disabling logging altogether) since it may be informative.

The output currently looks like this

Test
  test1:       [2014-02-20 15:43:06 CET] (ThreadId 542) foo INFO: Starting EKG
[2014-02-20 15:43:06 CET] (ThreadId 542) foo INFO: Starting http server
OK
  test2:    OK
  test3:   [2014-02-20 15:43:08 CET] (ThreadId 542) foo INFO: Shutting down http server.
[2014-02-20 15:43:08 CET] (ThreadId 542) foo INFO: Shut down.
OK
All 3 tests passed

even though these things happen before/after the test cases actually run. Would it be possible to move this around a bit so the output becomes nicer?

Cannot install Tasty with "cabal install Tasty"

Cannot install unbounded-delays-0.1.0.6:

Configuring unbounded-delays-0.1.0.6...

/var/folders/rj/xzzy28195qxfd92y6tt29mlc0000gn/T/11238.c:1:12:
warning: control reaches end of non-void function [-Wreturn-type]
int foo() {}
^
1 warning generated.
Building unbounded-delays-0.1.0.6...
Preprocessing library unbounded-delays-0.1.0.6...

Control/Concurrent/Timeout.hs:5:4:
error: invalid preprocessing directive
#-}
^

Control/Concurrent/Timeout.hs:82:17:
warning: missing terminating '"' character [-Winvalid-pp-token]
interval means "wait indefinitely".
^

Control/Concurrent/Timeout.hs:85:59:
warning: missing terminating ' character [-Winvalid-pp-token]
should behave exactly the same as @f@ as long as @f@ doesn't time out. This
^

Control/Concurrent/Timeout.hs:94:29:
warning: missing terminating ' character [-Winvalid-pp-token]
runtime system, but it doesn't work at all for non-Haskell code. Foreign
^

Control/Concurrent/Timeout.hs:102:16:
warning: missing terminating ' character [-Winvalid-pp-token]
they really don't because the runtime system uses scheduling mechanisms like
^
4 warnings and 1 error generated.
Failed to install unbounded-delays-0.1.0.6
cabal: Error: some packages failed to install:
tasty-0.8.0.2 depends on unbounded-delays-0.1.0.6 which failed to install.
unbounded-delays-0.1.0.6 failed during the building phase. The exception was:
ExitFailure 1

Print QuickCheck failure as a HUnit test

It would be nice if when a Quickcheck property failed it printed out HUnit test case I could copy into my code.

For instance lets say I had the property:

prop_print_parse_roundtrip :: Expr -> Bool
prop_print_parse_roundtrip x = Right x == parse (print x)

Which when failed, in addition to what is currently printed to the console, would be something like

HUnit test case

case_prop_print_parse_roundtrip_regression_0 :: Assertion
case_prop_print_parse_roundtrip_regression_0 = 
      assertBool "" $ prop_print_parse_roundtrip $ IntLit (-1)

Which I could then copy into my test file.

Status may be updated too often due to Progress

If a thread only wants to be notified when the Status genuinely changes, it still will be woken up every time Progress is updated.

A solution could be to track progress in a separate TVar.

Issue compiling tasty with base 4.5 on debian wheezy

Here are is the terminal output and my cabal file. I was following this tutorial but had to change my cabal file to accept base 4.5 since I use debian wheezy:

http://yannesposito.com/Scratch/en/blog/Holy-Haskell-Starter/

cody@zentop:~/programming/haskell/init-haskell-project/holy-project$ cabal 
$ cabal install
Resolving dependencies...
Configuring tasty-0.2...
Building tasty-0.2...
Preprocessing library tasty-0.2...
[ 1 of 11] Compiling Test.Tasty.Parallel ( Test/Tasty/Parallel.hs, dist/dist-sandbox-3c66a978/build/Test/Tasty/Parallel.o )
[ 2 of 11] Compiling Test.Tasty.Options ( Test/Tasty/Options.hs, dist/dist-sandbox-3c66a978/build/Test/Tasty/Options.o )

Test/Tasty/Options.hs:54:17:
    Couldn't match expected type `ReadM v'
                with actual type `Either ParseError b0'
    Expected type: String -> ReadM v
  Actual type: String -> Either ParseError b0
    In the first argument of `reader', namely `parse'
    In the first argument of `(<>)', namely `reader parse'
Failed to install tasty-0.2
cabal: Error: some packages failed to install:
holy-project-0.1.0.0 depends on tasty-0.2 which failed to install.
tasty-0.2 failed during the building phase. The exception was:
ExitFailure 1
tasty-hunit-0.4.1 depends on tasty-0.2 which failed to install.
tasty-quickcheck-0.3.1 depends on tasty-0.2 which failed to install.
tasty-smallcheck-0.2 depends on tasty-0.2 which failed to install.

cabal file:

-- Initial holy-project.cabal generated by cabal init.  For further documentation,
-- see http://haskell.org/cabal/users-guide/

name:                   holy-project
version:                0.1.0.0
synopsis:               Start your haskell project with cabal, git, and tests.
-- description:
homepage:               http://github.com/codygman/holy-project
license:                MIT
license-file:           LICENSE
author:                 Cody Goodman
maintainer:             [email protected]
-- copyright:
category:               Unknown
build-type:             Simple
-- extra-source-files:
cabal-version:          >=1.10

executable holy-project
  main-is:              Main.hs
  -- other-modules:
  -- other-extensions:
  build-depends:        base >=4.4 && <4.7
                        , ansi-terminal
  hs-source-dirs:       src
  ghc-options:          -Wall
  default-language:     Haskell2010

library
  exposed-modules:      HolyProject
                        , HolyProject.Swallow
                        , HolyProject.Coconut
  -- other-modules:
  -- other-extensions:
  build-depends:        base >=4.4 && <4.7
  ghc-options:          -Wall
  hs-source-dirs:       src
  default-language:     Haskell2010

executable test-holy-project
  hs-source-dirs:       test
  ghc-options:          -Wall
  main-is:              Test.hs
  default-language:     Haskell2010
  build-depends:        base ==4.5.*, Cabal >= 1.16.0
                        , holy-project
                        , HUnit
                        , QuickCheck
                        , smallcheck
                        , tasty
                        , tasty-hunit
                        , tasty-quickcheck
                        , tasty-smallcheck
test-suite Tests
  hs-source-dirs:       test
  ghc-options:          -Wall
  main-is:              Test.hs
  Type:                 exitcode-stdio-1.0
  default-language:     Haskell2010
  build-depends:        base ==4.5.*, Cabal >= 1.16.0
                        , holy-project
                        , HUnit
                        , QuickCheck
                        , smallcheck
                        , tasty
                        , tasty-hunit
                        , tasty-quickcheck
                        , tasty-smallcheck

Build failure with stm <= 2.2.0.1

When compiling with stm-2.2.0.1:

[ 1 of 11] Compiling Test.Tasty.Parallel ( Test/Tasty/Parallel.hs, dist/build/Test/Tasty/Parallel.o )
Test/Tasty/Parallel.hs:64:13:
  Not in scope: `modifyTVar'
  Perhaps you meant one of these:
    `modifyMVar' (imported from Control.Concurrent),
    `modifyMVar_' (imported from Control.Concurrent)

Test/Tasty/Parallel.hs:78:36:
   Not in scope: modifyTVar'
   Perhaps you meant one of these:
     `modifyMVar' (imported from Control.Concurrent),
     `modifyMVar_' (imported from Control.Concurrent)

modifyTVar is present in stm-2.3: http://hackage.haskell.org/packages/archive/stm/2.3/doc/html/src/Control-Concurrent-STM-TVar.html#modifyTVar

Possible solutions:

  • Add lower bound on stm dependency
  • Copy implementation from stm package (like with myForkFinally)

Add defaultIngredients

I'm trying to use tasty for the first time, and I want XML output support.

In order to add it, I had to read the source code for defaultMain to see what the default Ingredients were, as otherwise my test suite did nothing but print an error message when I just added antXMLRunner.

It's a bit unreasonable for many users to know or care what the default Ingredients should be, not to mention fragile in case they ever change.

As such, I'd suggest adding a public top-level value:

defaultIngredients :: [Ingredient]
defaultIngredients = [consoleTestReporter, listingTests]

A user who just wants to extend whatever the defaults are could then simply use

defaultMainWithIngredients (defaultIngredients ++ [antXMLRunner])

and get what they need in a future-proof way.

resource aquire run before test output flushed

I have a test suite which starts with some quickcheck tests, and then some hunit tests that all need a common resource. I had been setting up the resource in the first hunit test, which is horrible and won't work with tasty-rerun. So, I changed it to use tasty's resources.

Since my resource setup actually involves a few tests of my program code, and was already in the form of hunit tests, I actually run tryIngredients inside the resource aquisition action! So, nested tasty. This actually works ok!

However, the consoleTestReporter outputs stuff, and this output actually gets mixed in with the output of the last few quickcheck tests. I suspect that tasty is being asynchronous and/or buffering.

  prop_read_show_TrustLevel:                      OK
    +++ OK, passed 1000 tests.
  prop_parse_show_TrustLog:                       OK
    +I+n+i tO KT,e sptass
  se d  i1n0i0t0:  tests.
      prop_hashes_stable:                             OK

I think it would make sense for tasty to ensure it's finished outputting anything to the console before running resource aquistion actions, which could have arbitrary output.

(It would also be nice if there were a quietTestReporter. But if I were wishing for a pony, I guess I'd instead wish that tasty had dependencies between tests..)

thread blocked indefinitely in an STM transaction

import Test.Tasty
import Test.Tasty.HUnit

main = defaultMain $ testCase "foo" $ let x = x in x

This is probably related to asynchronous exceptions... (The test throws a NonTermination exception asynchrnouosly.)

Compilation failure

Configuring tasty-0.5.1...
Flags chosen: colors=True
Dependency ansi-terminal ==0.6: using ansi-terminal-0.6
Dependency base ==4.3.1.0: using base-4.3.1.0
Dependency containers ==0.4.0.0: using containers-0.4.0.0
Dependency deepseq ==1.3.0.2: using deepseq-1.3.0.2
Dependency mtl ==2.0.1.0: using mtl-2.0.1.0
Dependency optparse-applicative ==0.6.0: using optparse-applicative-0.6.0
Dependency regex-posix ==0.94.4: using regex-posix-0.94.4
Dependency stm ==2.3: using stm-2.3
Dependency tagged ==0.5: using tagged-0.5
...

[ 1 of 13] Compiling Test.Tasty.Parallel ( Test/Tasty/Parallel.hs, dist/build/Test/Tasty/Parallel.o )
[ 2 of 13] Compiling Test.Tasty.Options ( Test/Tasty/Options.hs, dist/build/Test/Tasty/Options.o )

Test/Tasty/Options.hs:55:7: Not in scope: `<>'

Test/Tasty/Options.hs:56:7: Not in scope: `<>'

Test/Tasty/Options.hs:57:7: Not in scope: `<>'
Failed to install tasty-0.5.1
cabal: Error: some packages failed to install:
tasty-0.5.1 failed during the building phase. The exception was:
ExitFailure 1

UI: do not print empty group names

E.g.

Tests
  Engine tests
  Recognition vs parsing
  Tests for matching functions
    findFirstPrefix
      t1: OK
      t2: OK
      t3: OK
    findFirstInfix
    findLongestPrefix
    findLongestInfix
    findShortestPrefix
    findShortestInfix

Exceptions cause entire test suite to fail early

I'm trying to implement a combination of a lexer/parser for SQL, and as such was hoping to just stub out swaths of SQL that my parser can't currently handle, and gradually implement them all to green and then move on. As such, I have something like the following:

import Prelude hiding (lex)

import Test.Tasty
import Test.Tasty.HUnit

import Lexer (lex)
import Parser

tests = testGroup "PostgreSQL regression tests"
  [ testGroup "ALTER TABLE" $ statements
      [ ("ALTER TABLE tmp ADD COLUMN xmin integer;", AlterTable "tmp" (AddColumn (ColumnDefinition "xmin" "integer" [])))
      , ("ALTER TABLE tmp ADD COLUMN a int4 default 3;", AlterTable "tmp" (AddColumn (ColumnDefinition "a" "int4" [Default "3"])))
      , ("ALTER TABLE tmp ADD COLUMN b name;", AlterTable "tmp" (AddColumn (ColumnDefinition "b" "name" [])))
      , ("ALTER TABLE tmp RENAME TO tmp_new;", AlterTable "tmp" (RenameTo "tmp_new"))
      , ("ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1);", undefined)
      , ("ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo;", undefined)
      , ("ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0);", undefined)
      , ("ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo;", undefined)
      , ("ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT;", undefined)
      , ("ALTER TABLE IF EXISTS constraint_rename_test ADD CONSTRAINT con4 UNIQUE (a);", undefined)
      , ("ALTER TABLE tmp3 add constraint tmpconstr foreign key(c) references tmp2 match full;", undefined)
      , ("ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full NOT VALID;", undefined)
      , ("ALTER TABLE tmp3 validate constraint tmpconstr;", undefined)
      , ("ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;", undefined)
      , ("ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);", undefined)
      ]
  ]

statements = map (\(q, expected) -> testCase q (parse q @?= [expected]))

parse = sql . lex

main = defaultMain tests

However, the first test that fails:

    ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1);:                       FAIL
      Tests2: lexical error

causes the entire test executable to stop - no summary, no further tests.

I would expect each test to be bracketed for exceptions, so that one exception doesn't prevent everything from running.

Add an option for ignoring tests matching a pattern

It'd be useful to have an option for selectively ignoring tests matching a pattern. Example:

# Run all tests except 'some-test':
$ test --ignore some-test

# Run all tests in 'test-group' except 'test-group/test-3':
$ test --pattern test-group/** --ignore test-group/test-3

IIUC, this can't be achieved with only --pattern since it's not possible to chain patterns with &&.

Separate between status and description

Description may be empty.

In case of failure, it may give the reason.

In case of success, it may give some status information (e.g. number of test cases generated by QC/SC).

In any case, it shouldn't contain OK/Fail — that should be implied automatically from the status.

Optionally Treat Timeouts as Success

I would like to set a maximum time to run for smallcheck. The jump in time between levels can be large, and sometimes the smaller level does not provide sufficient testing.

Tasty tests are irrelevant to the code base

The unit tests just test some Regex stuff, unless I'm mistaken. It seems more fitting for them to be in a samples folder.

Furthermore, the build passing icon should really not depend on irrelevant unit tests and should (hopefully) have some relevant tests.

Just my 2 cents though.

Richer pattern language

Including &&, || , and !.

Things to think about:

  • syntax and escaping
  • do we want to be able to set options based by regex? E.g. for everything matching foo set the depth to 20. Not sure it's worth the effort.

See also #36.

tasty-hunit documentation does not build

Building tasty-hunit-0.8...
Preprocessing library tasty-hunit-0.8...
[1 of 1] Compiling Test.Tasty.SmallCheck ( Test/Tasty/SmallCheck.hs, dist/build/Test/Tasty/SmallCheck.o )
[1 of 1] Compiling Test.Tasty.QuickCheck ( Test/Tasty/QuickCheck.hs, dist/build/Test/Tasty/QuickCheck.o )
[1 of 1] Compiling Test.Tasty.HUnit ( Test/Tasty/HUnit.hs, dist/build/Test/Tasty/HUnit.o )
In-place registering tasty-hunit-0.8...
Running Haddock for tasty-hunit-0.8...
Preprocessing library tasty-hunit-0.8...
Warning: The documentation for the following packages are not installed. No
links will be generated to these packages: rts-1.0

dist/build/tmp-8206/Test/Tasty/HUnit.hs:54:5:
    parse error on input `hunitResult'
Haddock coverage:
builder for `/nix/store/5pbg70gmgs2x5gz7yj1aqii76q6cm96z-haskell-tasty-hunit-ghc7.6.3-0.8.drv' failed with exit code 1
cannot build derivation `/nix/store/llbs5ihy9fi8j37ada6lv7g05sahlkx4-haskell-tasty-rerun-ghc7.6.3-1.0.0.drv': 1 dependencies couldn't be built
error: build of `/nix/store/llbs5ihy9fi8j37ada6lv7g05sahlkx4-haskell-tasty-rerun-ghc7.6.3-1.0.0.drv' failed

Tests pass after a crash

You will please excuse the output, it's in the wrong byte order. I made a typo that I know should have caused the tests to fail (I realized it right after pressing return). To my surprise, the test suite passed anyway:

Test suite testsuite: RUNNING...
All tests
  Heartbeat tests
    pickle composed with unpickle is the identity: OK
  Injuries tests
    pickle composed with unpickle is the identity: OK
  InjuriesDetail tests
    pickle composed with unpickle is the identity: OK
  News tests
    news fie
lfadtsa lg eetr rcoorr:r edcotc udmaetnatb ausnep incakmleisn:g   f a i l e d 
OxKp
E l e m :p igcoktl ee lceommepnots enda mwe "imtshg _uindp"i,c kbluet  iesx ptehcet eidd e"ncatteigtoyr:y "O
Kc
o n tOedxdts:  t e s tesl
e m e n tp i"cmkelses acgoem"p
coosnetd entwsi:t h   u<cnaptiecgkolrey >iNse wtsh</cea tiedgeonrtyi>t<ys:p ort>NBA</sport><url>/nba/news/ACN4650108.htm</url><t...

fatal error: document unpickling failed
xpElem: got element name "msg_id", but expected "category"
context:    element "message"
contents:   <category>News</category><sport>NBA</sport><url>/nba/news/ACN4650108.htm</url><t...
OK

All 6 tests passed
Test suite testsuite: PASS

The crash is during HXT's unpickling if it helps.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.