• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

doc/H04-May-2020-1,5391,013

examples/H03-May-2022-971751

ext/H03-May-2022-64

extras/H03-May-2022-620479

include/H04-May-2020-9,2746,565

src/H04-May-2020-2,7852,150

test/H03-May-2022-12,63410,414

.clang-formatH A D04-May-20201.4 KiB5049

.dir-locals.elH A D04-May-202033 21

.gitignoreH A D04-May-2020103 1110

.gitmodulesH A D04-May-2020186 76

.travis.ymlH A D04-May-20202.4 KiB8677

LICENSE.mdH A D04-May-20201.3 KiB116

README.mdH A D04-May-20204.9 KiB8957

appveyor.ymlH A D04-May-2020725 3025

README.md

1# RapidCheck [![Build Status](https://travis-ci.org/emil-e/rapidcheck.svg?branch=master)](https://travis-ci.org/emil-e/rapidcheck) [![Build status](https://ci.appveyor.com/api/projects/status/8hms56ghn27agpcj/branch/master?svg=true)](https://ci.appveyor.com/project/emil-e/rapidcheck/branch/master)
2
3RapidCheck is a C++ framework for property based testing inspired by QuickCheck and other similar frameworks. In property based testing, you state facts about your code that given certain precondition should always be true. RapidCheck then generates random test data to try and find a case for which the property doesn't hold. If such a case is found, RapidCheck tries to find the smallest case (for some definition of smallest) for which the property is still false and then displays this as a counterexample. For example, if the input is an integer, RapidCheck tries to find the smallest integer for which the property is false.
4
5Sounds interesting? Why don't you read the **[User Guide](doc/user_guide.md)** to learn more!
6
7## Why RapidCheck?
8
9There are existing implementations of property based testing but the ones that I have found are either (in my humble opinion) a bit clunky or are missing essential features such as test case shrinking.
10
11Let's throw together a list of features:
12
13- Write your properties in an imperative way that makes sense for C++
14- Test case shrinking
15- Great support for STL types, including maps and sets
16- Advanced combinators for creating your own generators
17- Stateful based on commands in the vein of Erlang QuickCheck
18- Integration with popular testing frameworks such as Boost Test, Google Test and Google Mock
19
20## Prerequisites and installation
21
22RapidCheck makes extensive use of C++11 and thus requires a compliant compiler. RapidCheck continuous integration builds using Clang 3.5, GCC 4.9 and Visual Studio 2015 so any later versions should also work.
23
24RapidCheck uses CMake and is built like any other CMake project. If your own project uses CMake you can simply have RapidCheck as a subdirectory and add the following to your `CMakeLists.txt`:
25
26    add_subdirectory("path/to/rapidcheck")
27    target_link_libraries(my_target rapidcheck)
28
29This will give you both linking and include directories.
30
31## Quick introduction
32
33A common first example is testing a reversal function. For such a function, double reversal should always result in the original list. In this example we will use the standard C++ `std::reverse` function:
34
35```C++
36#include <rapidcheck.h>
37
38#include <vector>
39#include <algorithm>
40
41int main() {
42  rc::check("double reversal yields the original value",
43            [](const std::vector<int> &l0) {
44              auto l1 = l0;
45              std::reverse(begin(l1), end(l1));
46              std::reverse(begin(l1), end(l1));
47              RC_ASSERT(l0 == l1);
48            });
49
50  return 0;
51}
52```
53
54The `check` function is used to check properties. The first parameter is an optional string which describes the property. The second parameter is a callable object that implements the property, in this case a lambda. Any parameters to the callable (in our case the `l0` parameter) will be randomly generated. The `RC_ASSERT` macro works just like any other assert macro. If the given condition is false, the property has been falsified.
55
56The property above also forms part of a specification of the reversal function: "For any list of integers A, reversing and then reversing again should result in A".
57
58If we were to run this, RapidCheck would (hopefully) output the following:
59
60```text
61Using configuration: seed=9928307433081493900
62
63- double reversal yields the original value
64OK, passed 100 tests
65```
66
67Here, RapidCheck tells us that it ran 100 test cases and all of them passed. It also tells us the configuration that was used, in particular the random seed. If there was a bug in the implementation of `std::reverse` we could get the following output instead:
68
69```text
70Falsifiable after 12 tests and 10 shrinks
71
72std::tuple<std::vector<int>>:
73([1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
74
75main.cpp:17:
76RC_ASSERT(l0 == l1)
77
78Expands to:
79[1, 0, 0, 0, 0, 0, 0, 0, 0, 0] == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
80```
81
82Here RapidCheck tells us that it found a case for which the property does not hold after running 12 tests. When it found this case, it shrunk it 10 times to arrive at the counterexample in the output. The counterexample contains each input value that was used for the failing case along with its type. Since RapidCheck views property arguments as tuples, the type is shown here as `std::tuple<std::vector<int>>`.
83
84Can you guess what the bug is? The fact that there are exactly 10 items should give a clue. In this case, the bug is that the implementation sets the first element to `0` when `l0.size() >= 10`. This is also the reason for the initial `0`, the problem doesn't manifest when all elements are zero. How did this bug happen? Who knows!
85
86## Thanks
87
88Big thanks to my employer, Spotify, for making it possible for me to spend work time improving RapidCheck.
89