blob: b9646dd71b0e132473063145c2a2dfac00633b45 [file] [log] [blame]
# Welcome to Triq -- Trifork QuickCheck for Erlang
[![Travis-CI Build Status](https://travis-ci.org/triqng/triq.svg?branch=master)](https://travis-ci.org/triqng/triq)
[![GitLab-CI Build Status](https://gitlab.com/triqng/triq/badges/master/pipeline.svg)](https://gitlab.com/triqng/triq/pipelines)
This is a fork of Triq that is being run under the ZeroMQ Collaberation rules, http://rfc.zeromq.org/spec:22 with the one exception being that it is under the apache licence
Triq (pronounced "Trick Check") is a free alternative to [QuviQ
eqc](http://www.quviq.com/). Triq's API is modelled closely after
`eqc`, so I recommend their tutorials and slides for an introduction
to QuickCheck. Notice that QuviQ `eqc` has many features not found in
`triq`, but it is open source licensed under the Apache license. For
instance, `eqc` has features for reporting, management, probably a
much better shrinking mechanism, cool C integration, and
professional support.
## Using Triq
### Installation via package manager
To use `triq`, you can add it as a project dependency and let your
package manager of choice handle it:
rebar.config: `{triq, "1.*"}`
erlang.mk: `DEPS = triq`
mix.exs: `{:triq, "~> 1.*"}`
### Installation from source into `$ERL_LIBS`
If you want to make `triq` available globally, you can install it from source
into your Erlang installation by adding it in one of your `$ERL_LIBS` paths.
So, it's either somewhere like `/usr/local/lib/lib/erlang/lib` or `$HOME/.erl`.
You can either download a tagged release from
`https://github.com/triqng/triq/releases` and extract that or clone the git
repo `https://github.com/triqng/triq` in the target directory. Once that's
done, cd into the directory and run `./rebar compile` or just `make`.
Now, if you start `erl`, you should be able to call functions from the
`triq` module.
```
$ erl
1> code:which(triq).
"/usr/local/lib/erlang/lib/triq/ebin/triq.beam"
2>
```
### Writing properties with Triq
To write properties with `triq`, include the header file:
```
-include_lib("triq/include/triq.hrl").
```
And you're ready to write property tests. An example property could be:
```
prop_append() ->
?FORALL({Xs,Ys},{list(int()),list(int())},
lists:reverse(Xs++Ys)
==
lists:reverse(Ys) ++ lists:reverse(Xs)).
```
To test this property, run `triq:check/1`, thus:
```
1> triq:check(prop_append()).
......................................................................
..............................
Ran 100 tests
true
2>
```
If the test fails, it will try to shrink the result; here is an example:
```
prop_delete() ->
?FORALL(L,list(int()),
?IMPLIES(L /= [],
?FORALL(I,elements(L),
?WHENFAIL(io:format("L=~p, I=~p~n", [L,I]),
not lists:member(I,lists:delete(I,L)))))).
```
Which runs like this:
```
1> triq:check(triq_tests:prop_delete()).
x....Failed!
L=[4,5,5], I=5
Failed after 5 tests with false
Simplified:
L = [0,0]
I = 0
false
2>
```
You can get the values used for the failing test with `counterexample`,
and reuse the same test values with `check/2`:
```
3> A = triq:counterexample(triq_tests:xprop_delete()).
x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFailed!
L=[3,2,1,1,1], I=1
Failed after 101 tests with false
Simplified:
L = [0,0]
I = 0
[[0,0],0]
4> A.
[[0,0],0]
5> triq:check(triq_tests:xprop_delete(), A).
Failed!
L=[0,0], I=0
Failed after 1 tests with false
Simplified:
L = [0,0]
I = 0
false
6>
```
Modules compiled with the `triq.hrl` header, auto-export all functions named
`prop_*`, and have a function added called `check/0` which runs `triq:check/1`
on all the properties in the module.
```
1> mymodule:check().
```
You can also instruct `triq` to generate EUnit integration functions which allow
the module to be treated like an ordinary EUnit tests module. This avoids the need
for `triq` or generic `qc` support in your build/test tool of choice.
To achieve that, just make sure to include the attribute `-triq(eunit).` in the module.
So, the initial `triq.hrl` include would turn into this:
```
-include_lib("triq/include/triq.hrl").
-triq(eunit).
```
Good luck!