blob: be82ef44b6f753466ee7cc819ee70b4a68af8d64 [file] [log] [blame]
#+OPTIONS: ^:nil
#+TITLE: Triq
* [[https://gitlab.com/triq/triq][Triq]] QuickCheck for Erlang
** Introduction
:PROPERTIES:
:CUSTOM_ID: introduction
:END:
Triq (Term Reductive Invariant Questant) is an Apache licensed
QuickCheck library for Erlang. It is a continuation and community fork
of [[https://github.com/krestenkrab/triq][Trifork QuickCheck]]. Unlike the original project, this fork is in
*no way* affiliated with or a product of Trifork.
By and large, the Triq API is modeled closely after QuviQ =eqc=,
except you want to replace any occurrence of =eqc= with =triq=. The
main supporting module is called =triq_dom=, corresponding to eqc's
=eqc_gen=.
#+BEGIN_EXPORT html
<a href="https://gitlab.com/triq/triq/pipelines"><img src="https://gitlab.com/triq/triq/badges/master/pipeline.svg"></a>
#+END_EXPORT
** Writing QuickCheck properties with Triq
:PROPERTIES:
:CUSTOM_ID: writing-properties-with-triq
:END:
To write properties with =triq=, include the =triq.hrl= header file:
#+BEGIN_EXAMPLE erlang
-include_lib("triq/include/triq.hrl").
#+END_EXAMPLE
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. Further, adding
the attribute =-triq(eunit)= will generate EUnit tests for all
properties, turning the module into a regular EUnit test suite.
If you use erlang.mk, you will typically want to use [[https://erlang.mk/guide/triq.html][the built-in Triq
plugin]] to check properties. Otherwise we highly recommend letting Triq
generate EUnit tests, thus arriving at a demo module like this:
#+BEGIN_EXAMPLE erlang
-module(triq_demo).
-include_lib("triq/include/triq.hrl").
-triq(eunit).
prop_append() ->
?FORALL({Xs,Ys},{list(int()),list(int())},
lists:reverse(Xs++Ys)
==
lists:reverse(Ys) ++ lists:reverse(Xs)).
#+END_EXAMPLE
Now, all you have to do is run =rebar3 eunit=:
#+BEGIN_EXAMPLE sh
$ rebar3 eunit -v
===> Verifying dependencies...
===> Compiling triq_demo
===> Performing EUnit tests...
======================== EUnit ========================
file "triq_demo.app"
application 'triq_demo'
triq_demo:5: append_test_ (module 'triq_demo')...[0.262 s] ok
[done in 0.269 s]
[done in 0.274 s]
=======================================================
Test passed.
#+END_EXAMPLE
If you use =-triq({eunit, [{runs, N}]})=, then Triq will do =N= runs for each
property in the module, which is equivalent to calling =triq:check(Module, N)=.
This can be useful to make Triq try more (or less) cases than the default.
For advanced features, please consult the API docs.
** Obtaining Triq
:PROPERTIES:
:CUSTOM_ID: obtaining-triq
:END:
*** Installation via package manager
:PROPERTIES:
:CUSTOM_ID: installation-via-package-manager
:END:
To use =triq=, you can add it as a project dependency and let your
package manager of choice handle it:
| rebar.config | ={deps, [triq]}= |
| erlang.mk | =DEPS = triq= |
| mix.exs | ={:triq, "~> 1.*"}= |
*** Installation from source into =$ERL_LIBS=
:PROPERTIES:
:CUSTOM_ID: installation-from-source-into-erl_libs
:END:
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/lib/erlang/lib= or =$HOME/.erl=.
You can either download a [[https://gitlab.com/triq/triq/tags][tagged release]]
and extract that or clone the [[https://gitlab.com/triq/triq][git repo]] in the
target directory. Once that's done, cd into the directory and run =make=.
Now, if you start =erl=, you should be able to call functions from the
=triq= module.
#+BEGIN_EXAMPLE
$ erl
1> code:which(triq).
"/usr/lib/erlang/lib/triq/ebin/triq.beam"
2>
#+END_EXAMPLE