├── .clang-format ├── .dir-locals.el ├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── appveyor.yml ├── doc ├── Gen.md ├── Seq.md ├── Shrinkable.md ├── assertions.md ├── boost.md ├── boost_test.md ├── catch.md ├── configuration.md ├── debugging.md ├── displaying.md ├── distribution.md ├── doctest.md ├── generators.md ├── generators_ref.md ├── gmock.md ├── gtest.md ├── properties.md ├── state.md ├── state_ref.md └── user_guide.md ├── examples ├── CMakeLists.txt ├── boost_test │ ├── CMakeLists.txt │ └── main.cpp ├── classify │ ├── CMakeLists.txt │ └── main.cpp ├── counter │ ├── CMakeLists.txt │ └── main.cpp ├── database │ ├── CMakeLists.txt │ ├── Database.cpp │ ├── Database.h │ ├── DatabaseConnection.cpp │ ├── DatabaseConnection.h │ ├── Generators.h │ ├── User.cpp │ ├── User.h │ └── main.cpp ├── gtest │ ├── CMakeLists.txt │ └── main.cpp └── mapparser │ ├── CMakeLists.txt │ ├── MapParser.cpp │ ├── MapParser.h │ └── main.cpp ├── ext ├── CMakeLists.txt └── get_boost.sh ├── extras ├── CMakeLists.txt ├── boost │ ├── CMakeLists.txt │ ├── include │ │ └── rapidcheck │ │ │ ├── boost.h │ │ │ └── gen │ │ │ └── boost │ │ │ ├── Optional.h │ │ │ └── Optional.hpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── OptionalTests.cpp │ │ └── main.cpp ├── boost_test │ ├── CMakeLists.txt │ └── include │ │ └── rapidcheck │ │ └── boost_test.h ├── catch │ ├── CMakeLists.txt │ └── include │ │ └── rapidcheck │ │ └── catch.h ├── doctest │ ├── CMakeLists.txt │ └── include │ │ └── rapidcheck │ │ └── doctest.h ├── gmock │ ├── CMakeLists.txt │ ├── include │ │ └── rapidcheck │ │ │ └── gmock.h │ └── test │ │ ├── CMakeLists.txt │ │ └── main.cpp └── gtest │ ├── CMakeLists.txt │ └── include │ └── rapidcheck │ └── gtest.h ├── include ├── rapidcheck.h └── rapidcheck │ ├── Assertions.h │ ├── Assertions.hpp │ ├── BeforeMinimalTestCase.h │ ├── Check.h │ ├── Check.hpp │ ├── Classify.h │ ├── Classify.hpp │ ├── Compat.h │ ├── Compat.hpp │ ├── Gen.h │ ├── Gen.hpp │ ├── GenerationFailure.h │ ├── Log.h │ ├── Log.hpp │ ├── Maybe.h │ ├── Maybe.hpp │ ├── Nothing.h │ ├── Random.h │ ├── Random.hpp │ ├── Seq.h │ ├── Seq.hpp │ ├── Show.h │ ├── Show.hpp │ ├── Shrinkable.h │ ├── Shrinkable.hpp │ ├── Traits.h │ ├── detail │ ├── AlignedUnion.h │ ├── Any.h │ ├── Any.hpp │ ├── ApplyTuple.h │ ├── BitStream.h │ ├── BitStream.hpp │ ├── Capture.h │ ├── Configuration.h │ ├── ExecFixture.h │ ├── FrequencyMap.h │ ├── FunctionTraits.h │ ├── ImplicitParam.h │ ├── ImplicitParam.hpp │ ├── IntSequence.h │ ├── Platform.h │ ├── Property.h │ ├── Property.hpp │ ├── PropertyContext.h │ ├── Results.h │ ├── Results.hpp │ ├── Serialization.h │ ├── Serialization.hpp │ ├── ShowType.h │ ├── ShowType.hpp │ ├── TestListener.h │ ├── TestListenerAdapter.h │ ├── TestMetadata.h │ ├── TestParams.h │ ├── Traits.h │ ├── TypeList.h │ ├── Utility.h │ ├── Variant.h │ └── Variant.hpp │ ├── fn │ ├── Common.h │ └── Common.hpp │ ├── gen │ ├── Arbitrary.h │ ├── Arbitrary.hpp │ ├── Build.h │ ├── Build.hpp │ ├── Chrono.h │ ├── Chrono.hpp │ ├── Container.h │ ├── Container.hpp │ ├── Create.h │ ├── Create.hpp │ ├── Exec.h │ ├── Exec.hpp │ ├── Maybe.h │ ├── Maybe.hpp │ ├── Numeric.h │ ├── Numeric.hpp │ ├── Predicate.h │ ├── Predicate.hpp │ ├── Select.h │ ├── Select.hpp │ ├── Text.h │ ├── Text.hpp │ ├── Transform.h │ ├── Transform.hpp │ ├── Tuple.h │ ├── Tuple.hpp │ └── detail │ │ ├── ExecHandler.h │ │ ├── ExecRaw.h │ │ ├── ExecRaw.hpp │ │ ├── GenerationHandler.h │ │ ├── Recipe.h │ │ ├── ScaleInteger.h │ │ ├── ShrinkValueIterator.h │ │ └── ShrinkValueIterator.hpp │ ├── seq │ ├── Create.h │ ├── Create.hpp │ ├── Operations.h │ ├── Operations.hpp │ ├── SeqIterator.h │ ├── SeqIterator.hpp │ ├── Transform.h │ └── Transform.hpp │ ├── shrink │ ├── Shrink.h │ └── Shrink.hpp │ ├── shrinkable │ ├── Create.h │ ├── Create.hpp │ ├── Operations.h │ ├── Operations.hpp │ ├── Transform.h │ └── Transform.hpp │ ├── state.h │ └── state │ ├── Command.h │ ├── Command.hpp │ ├── Commands.h │ ├── Commands.hpp │ ├── State.h │ ├── State.hpp │ └── gen │ ├── Commands.h │ ├── Commands.hpp │ ├── ExecCommands.h │ └── ExecCommands.hpp ├── pkg-config.pc.cmake ├── src ├── BeforeMinimalTestCase.cpp ├── Check.cpp ├── Classify.cpp ├── GenerationFailure.cpp ├── Log.cpp ├── Random.cpp ├── Show.cpp ├── detail │ ├── Any.cpp │ ├── Assertions.cpp │ ├── Base64.cpp │ ├── Base64.h │ ├── Configuration.cpp │ ├── DefaultTestListener.cpp │ ├── DefaultTestListener.h │ ├── FrequencyMap.cpp │ ├── ImplicitParam.cpp │ ├── LogTestListener.cpp │ ├── LogTestListener.h │ ├── MapParser.cpp │ ├── MapParser.h │ ├── MulticastTestListener.cpp │ ├── MulticastTestListener.h │ ├── ParseException.cpp │ ├── ParseException.h │ ├── Platform.cpp │ ├── Property.cpp │ ├── PropertyContext.cpp │ ├── ReproduceListener.cpp │ ├── ReproduceListener.h │ ├── Results.cpp │ ├── Serialization.cpp │ ├── StringSerialization.cpp │ ├── StringSerialization.h │ ├── TestMetadata.cpp │ ├── TestParams.cpp │ ├── Testing.cpp │ └── Testing.h └── gen │ ├── Numeric.cpp │ ├── Text.cpp │ └── detail │ ├── ExecHandler.cpp │ ├── GenerationHandler.cpp │ ├── Recipe.cpp │ └── ScaleInteger.cpp └── test ├── AssertionsTests.cpp ├── CMakeLists.txt ├── CheckTests.cpp ├── ClassifyTests.cpp ├── GenTests.cpp ├── LogTests.cpp ├── MaybeTests.cpp ├── RandomTests.cpp ├── SeqTests.cpp ├── ShowTests.cpp ├── ShrinkableTests.cpp ├── detail ├── AnyTests.cpp ├── ApplyTupleTests.cpp ├── Base64Tests.cpp ├── BitStreamTests.cpp ├── CaptureTests.cpp ├── ConfigurationTests.cpp ├── DefaultTestListenerTests.cpp ├── FrequencyMapTests.cpp ├── ImplicitParamTests.cpp ├── LogTestListenerTests.cpp ├── MapParserTests.cpp ├── MulticastTestListenerTests.cpp ├── PropertyTests.cpp ├── ReproduceListenerTests.cpp ├── ResultsTests.cpp ├── SerializationTests │ ├── CompactIntegers.cpp │ ├── CompactRanges.cpp │ ├── Integers.cpp │ └── Misc.cpp ├── ShowTypeTests.cpp ├── StringSerializationTests.cpp ├── TestMetadataTests.cpp ├── TestParamsTests.cpp ├── TestingTests.cpp └── VariantTests.cpp ├── fn └── CommonTests.cpp ├── gen ├── BuildTests.cpp ├── ChronoTests.cpp ├── ContainerTests │ ├── Common.h │ ├── Fixed.cpp │ ├── NonFixed.cpp │ └── Unique.cpp ├── CreateTests.cpp ├── ExecTests.cpp ├── MaybeTests.cpp ├── NumericTests.cpp ├── PredicateTests.cpp ├── SelectTests.cpp ├── TextTests.cpp ├── TransformTests.cpp ├── TupleTests.cpp └── detail │ ├── ExecRawTests.cpp │ ├── RecipeTests.cpp │ ├── ScaleIntegerTests.cpp │ └── ShrinkValueIteratorTests.cpp ├── main.cpp ├── seq ├── CreateTests.cpp ├── OperationsTests.cpp ├── SeqIteratorTests.cpp └── TransformTests.cpp ├── shrink └── ShrinkTests.cpp ├── shrinkable ├── CreateTests.cpp ├── OperationsTests.cpp └── TransformTests.cpp ├── state ├── CommandTests.cpp ├── CommandsTests.cpp ├── IntegrationTests.cpp ├── StateTests.cpp └── gen │ ├── CommandsTests.cpp │ └── ExecCommandsTests.cpp └── util ├── AppleOrange.h ├── ArbitraryRandom.cpp ├── ArbitraryRandom.h ├── Box.h ├── DestructNotifier.h ├── GenUtils.cpp ├── GenUtils.h ├── Generators.h ├── IntVec.h ├── Logger.h ├── Meta.h ├── MockTestListener.h ├── NonCopyableModel.h ├── Predictable.h ├── SeqUtils.h ├── Serialization.h ├── ShowTypeTestUtils.h ├── ShrinkableUtils.cpp ├── ShrinkableUtils.h ├── TemplateProps.h ├── ThrowOnCopy.h ├── TypeListMacros.h └── Util.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: true 5 | AlignEscapedNewlinesLeft: false 6 | AlignOperands: false 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: All 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakAfterDefinitionReturnType: false 15 | AlwaysBreakBeforeMultilineStrings: true 16 | AlwaysBreakTemplateDeclarations: true 17 | BinPackArguments: false 18 | BinPackParameters: false 19 | BreakBeforeBinaryOperators: None 20 | BreakBeforeBraces: Attach 21 | BreakBeforeTernaryOperators: true 22 | BreakConstructorInitializersBeforeComma: true 23 | ColumnLimit: 80 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 4 26 | ContinuationIndentWidth: 4 27 | Cpp11BracedListStyle: true 28 | DerivePointerAlignment: false 29 | DisableFormat: false 30 | IndentCaseLabels: false 31 | IndentWidth: 2 32 | IndentWrappedFunctionNames: false 33 | KeepEmptyLinesAtTheStartOfBlocks: true 34 | Language: Cpp 35 | MaxEmptyLinesToKeep: 1 36 | NamespaceIndentation: None 37 | PointerAlignment: Right 38 | SpaceAfterCStyleCast: false 39 | SpaceBeforeAssignmentOperators: true 40 | SpaceBeforeParens: ControlStatements 41 | SpaceInEmptyParentheses: false 42 | SpacesBeforeTrailingComments: 1 43 | SpacesInAngles: false 44 | SpacesInCStyleCastParentheses: false 45 | SpacesInContainerLiterals: true 46 | SpacesInParentheses: false 47 | SpacesInSquareBrackets: false 48 | Standard: Cpp11 49 | TabWidth: 2 50 | UseTab: Never -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil . ((c-basic-offset . 2)))) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build* 2 | GPATH 3 | GRTAGS 4 | GTAGS 5 | TAGS 6 | ext/gmock 7 | ext/boost 8 | **/Makefile 9 | librapidcheck.a 10 | rapidcheckConfig.cmake 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/catch"] 2 | path = ext/catch 3 | url = https://github.com/philsquared/Catch.git 4 | [submodule "ext/googletest"] 5 | path = ext/googletest 6 | url = https://github.com/google/googletest 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015, Emil Eriksson 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. 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. 9 | 10 | 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. 11 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: Visual Studio 2015 3 | 4 | branches: 5 | only: 6 | - master 7 | 8 | environment: 9 | matrix: 10 | - CMAKE_BUILD_TYPE: Debug 11 | ARCH: amd64 12 | - CMAKE_BUILD_TYPE: Release 13 | ARCH: amd64 14 | - CMAKE_BUILD_TYPE: Debug 15 | ARCH: x86 16 | - CMAKE_BUILD_TYPE: Release 17 | ARCH: x86 18 | 19 | install: 20 | - git submodule update --init --recursive 21 | 22 | build_script: 23 | - md build 24 | - cd build 25 | - "\"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" %ARCH%" 26 | - cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DRC_ENABLE_TESTS=ON -DRC_ENABLE_EXAMPLES=ON -DRC_ENABLE_GTEST=ON -DRC_ENABLE_GMOCK=ON -DRC_ENABLE_BOOST=ON -DRC_ENABLE_BOOST_TEST=ON -DRC_ENABLE_RTTI=ON -G "NMake Makefiles" .. 27 | - nmake 28 | 29 | test_script: 30 | - ctest --output-on-failure -------------------------------------------------------------------------------- /doc/Gen.md: -------------------------------------------------------------------------------- 1 | # `Gen` 2 | 3 | _This section is incomplete._ 4 | -------------------------------------------------------------------------------- /doc/Seq.md: -------------------------------------------------------------------------------- 1 | # `Seq` 2 | 3 | _This section is incomplete._ 4 | 5 | `Seq` implements a lazy sequence (often called a "stream") of values of type `T`. It has a super simple interface for retrieving these values consisting only of the method `Maybe next()`. As can be seen, it returns a `Maybe` which is similar to `boost::optional`, Haskell's `Maybe` or other similar types that either contain a value or be empty. `next` successively returns the values in the sequence until the sequence is exhausted after which it will return an empty `Maybe` to signal that there are no more values. 6 | 7 | `Seq`s are mutable since calling `next` will modify the `Seq` by advancing it. They also have value semantics since you can copy them and pass them around like any other value. 8 | -------------------------------------------------------------------------------- /doc/Shrinkable.md: -------------------------------------------------------------------------------- 1 | # `Shrinkable` 2 | 3 | _This section is incomplete._ 4 | 5 | `Shrinkable` is a fundamental template class in RapidCheck. An instance of `Shrinkable` represents some value of type `T` and provides a way to access all the ways in which this value can be shrunk. It has value semantics which means that it can be copied and passed around just like any other value. It has two member functions: 6 | 7 | - `T value() const` returns the represented value of this `Shrinkable`. 8 | - `Seq> shrinks() const` returns a `Seq` (see [the documentation for `Seq`](Seq.md) for more information) of all the possible ways of shrinking the value from the smallest to the largest. 9 | 10 | There are two important things to note here: 11 | 12 | - `value()` is a member function, not a member variable. This means that the way that the `Shrinkable` obtains the value `T` that it returns is abstracted away. If this wasn't the case, we would have to impose the following restrictions on `T`: 13 | - `T` would need to have a copy constructor. Otherwise, we would only be able to retrieve `T` once. This means we couldn't generate, for example, `std::unique_ptr`s to objects. Non-copyable objects are very common in mainstream C++ code so this would be undesirable. 14 | - `T`'s copy constructor would have to produce copies that shared no state with the original value. Without this guarantee, we would not be able to repeatedly provide semantically equivalent objects since the consumer of `T` might modify the copy which could also modify the original. The obvious example of a type which certainly doesn't provide the non-shared-state guarantee is `std::shared_ptr` whose entire purpose is having a copy constructor that yields copies with shared state. 15 | - `shrinks()` returns a `Seq` of `Shrinkable` and not just `T`. This means that a `Shrinkable` is a value of `T` combined with a tree of possible ways of shrinking it, not just a list. This allows RapidCheck to _recursively_ search this for the smallest value value satisfying some condition (usually failing the property). 16 | -------------------------------------------------------------------------------- /doc/boost.md: -------------------------------------------------------------------------------- 1 | # Boost type support 2 | 3 | RapidCheck comes with support for (currently, a very limited set of) common Boost library types. This support is available through the `extras/boost` module. You can either directly add the `extras/boost/include` directory to your include path or link against the `rapidcheck_boost` target in your `CMakeLists.txt`. You can then simply `#include `. 4 | 5 | The Boost support is currently very limited so if you feel that you're missing some very essential type, please file an issue. Even better, submit a pull request complete with tests! 6 | 7 | ## Arbitrary 8 | 9 | The following types currently have `Arbitrary` specializations: 10 | 11 | - `boost::optional` 12 | 13 | ## Generators reference 14 | 15 | All the Boost generators are located in the `rc::gen::boost` namespace. 16 | 17 | ### `Gen> optional(Gen gen)` 18 | 19 | Equivalent to `gen::maybe` but for `boost::optional` instead. 20 | 21 | ```C++ 22 | // Example: 23 | const auto optionalSmallInt = *gen::boost::optional(gen::inRange(0, 100)); 24 | ``` 25 | -------------------------------------------------------------------------------- /doc/catch.md: -------------------------------------------------------------------------------- 1 | # Catch test integration 2 | 3 | rapidcheck comes with some basic integrations for the catch test library. 4 | 5 | ## Usage 6 | 7 | This support is available throught the `extras/catch` module. You can either 8 | directly add the `extras/gtest/inclode` directory to your include path: 9 | 10 | ```cmake 11 | add_subdirectory(rapidcheck) 12 | set include_directories(rapidcheck/extras/gtest/include) 13 | add_executable(MyTest main.cpp) 14 | ``` 15 | 16 | Or link against the `rapidcheck_catch` cmake target: 17 | 18 | ```cmake 19 | add_subdirectory(rapidcheck) 20 | add_executable(MyTest main.cpp) 21 | target_link_libraries(MyTest rapidcheck_catch) 22 | ``` 23 | 24 | Once you've done one of these, you can simply: 25 | 26 | ```cpp 27 | #include 28 | #include "rapidcheck.h" 29 | #include "rapidcheck/catch.h' 30 | ``` 31 | 32 | ## Reference 33 | 34 | ### `rc::prop("My test description", []{return true;}, /*verbose=*/true)` 35 | 36 | The `rc::prop` can be used in place of `SECTION` for convenient checking of 37 | properties. The third parameter is optional and defaults to `false`. 38 | 39 | ```cpp 40 | TEST_CASE("001: My first test case") 41 | { 42 | rc::prop("My property description", 43 | [](int a, int b) 44 | { 45 | // rapidcheck will produce the `a` and `b` 46 | return (a + b) == (b + a); // return true for passed test, false for 47 | // failed test 48 | }); 49 | 50 | // no problem mixing rapidcheck tests with regular catch assertions 51 | SECTION("Normal catch stuff") 52 | { 53 | WHEN("Something happens") 54 | { 55 | THEN("assert a result") 56 | { 57 | REQUIRE(1 == 1); 58 | } 59 | } 60 | } 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /doc/displaying.md: -------------------------------------------------------------------------------- 1 | # Displaying values 2 | 3 | RapidCheck often needs to display values as strings, such as when printing assertion messages or counterexamples. To do this, RapidCheck calls the `rc::show(const T &, std::ostream &)` template function. This template takes a value to display and a stream to output the string representation to. Given a value `v` and an output stream `os`, calling this template will do one of the following 4 | 5 | - If there is a valid overload for a call to `showValue(v, os)`, calls this overload. 6 | - If there is a valid stream insertion operator (i.e. `std::ostream &operator<<(std::ostream &, const T &)`) defined, this is used. 7 | - Otherwise, `` is printed. 8 | 9 | In essence, this means that you simply have to have a valid stream insertion operator available for RapidCheck to be able to display values of your type. If you don't want to define such an operator or simply want RapidCheck to display values differently than stream insertion would have done, you can provide an overload of `showValue` like this: 10 | 11 | ```C++ 12 | void showValue(const Person &person, std::ostream &os) { 13 | os << "First name: " << person.firstName << std::endl; 14 | os << "Last name: " << person.lastName << std::endl; 15 | os << "Age: " << person.age << std::endl; 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /doc/distribution.md: -------------------------------------------------------------------------------- 1 | # Reporting distribution 2 | 3 | To have the confidence that your properties are testing the right thing, it can be important to know how the input data is distributed. RapidCheck provides functionality to collect this information and report it to the console. 4 | 5 | To do this, RapidCheck uses the concept of test case "tags". Tags are a sequence of strings associated with a test case and every test case with the same tags are grouped together. When RapidCheck has run all its tests, it prints the distribution of the different categories. To add tags to a test case, use the tagging macros described below. 6 | 7 | ## Tagging macros 8 | 9 | ### `RC_TAG(values...)` 10 | 11 | Tags the current test case with the given values. The values are converted to strings using `rc::toString`. 12 | 13 | Example: 14 | 15 | ```C++ 16 | rc::check([](const User &user) { 17 | RC_TAG(user.gender); 18 | }); 19 | ``` 20 | 21 | When run: 22 | 23 | ```text 24 | OK, passed 100 tests 25 | 54.00% - Female 26 | 46.00% - Male 27 | ``` 28 | 29 | ### `RC_CLASSIFY(condition, values...)` 30 | 31 | If `condition` is true, tags the current test case with the given values in the same manner as `RC_TAG`. If no tags are given, a stringified version of the condition will be used as the tag. 32 | 33 | Example: 34 | 35 | ```C++ 36 | rc::check([](const User &user) { 37 | RC_CLASSIFY(user.username.empty()); 38 | }); 39 | ``` 40 | 41 | When run: 42 | 43 | ```text 44 | OK, passed 100 tests 45 | 8.00% - user.username.empty() 46 | ``` 47 | 48 | ## Notes 49 | 50 | Tags are not treated as sets meaning that there can be duplicate tags and the order is significant. The following are not equivalent: 51 | 52 | ```C++ 53 | RC_TAG("foo", "bar"); // <- This... 54 | RC_TAG("bar", "foo"); // <- is not the same as this 55 | ``` 56 | 57 | Also, you can use multiple tagging macros, you do not have to add all tags in a single macro. The following are equivalent: 58 | 59 | ```C++ 60 | // This: 61 | RC_TAG("foo"); 62 | RC_TAG("bar"); 63 | 64 | // ...is equivalent to: 65 | RC_TAG("foo", "bar"); 66 | ``` 67 | -------------------------------------------------------------------------------- /doc/doctest.md: -------------------------------------------------------------------------------- 1 | # Doctest integration 2 | 3 | rapidcheck comes with a basic integration for the [doctest](https://github.com/doctest/doctest) library. 4 | 5 | ## Usage 6 | 7 | This support is available through the `extras/doctest` module. You can either 8 | add the `extras/doctest/include` directory directly to your include path: 9 | 10 | ```cmake 11 | add_subdirectory(rapidcheck) 12 | set include_directories(rapidcheck/extras/doctest/include) 13 | add_executable(MyTest main.cpp) 14 | ``` 15 | 16 | ...or else link against the `rapidcheck_doctest` cmake target: 17 | 18 | ```cmake 19 | add_subdirectory(rapidcheck) 20 | add_executable(MyTest main.cpp) 21 | target_link_libraries(MyTest rapidcheck_doctest) 22 | ``` 23 | 24 | Either way, you can then write: 25 | 26 | ```cpp 27 | #include 28 | #include "rapidcheck.h" 29 | #include "rapidcheck/doctest.h' 30 | ``` 31 | 32 | ## Reference 33 | 34 | ### `rc::doctest::check("My test description", []{return true;}, /*verbose=*/true)` 35 | 36 | The `rc::doctest::check` function is a drop-in replacement for `rc::check` that reports its success or failure to the `doctest` test runner for inclusion in the statistics gathered for a test run. 37 | 38 | The third parameter is optional and defaults to `false`. 39 | 40 | ```cpp 41 | TEST_CASE("001: My first test case") 42 | { 43 | rc::doctest::check("integer addition is commutative", 44 | [](int a, int b) 45 | { 46 | return a + b == b + a); // true for success, false for failure 47 | }); 48 | 49 | // no problem mixing rapidcheck tests with other doctest assertions 50 | SUB_CASE("Normal doctest stuff") 51 | { 52 | REQUIRE(1 == 1); 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /doc/gmock.md: -------------------------------------------------------------------------------- 1 | # Google Mock integration 2 | 3 | RapidCheck support integration with Google Mock by making it possible for mock failures to make the current RapidCheck test case fail. For RapidCheck, you can most likely not use the `throw_on_failure` flag. This flag causes throws from mock destructors, something which is likely to make the program crash. In traditional unit testing, this might be okay but this prevents RapidCheck from shrinking the test case once it has failed. 4 | 5 | ## Usage 6 | 7 | Google Mock integration is not part of RapidCheck core so you need to add `extras/gmock/include` to your include path. You then need to include the `rapidcheck/gmock.h` header and call `rc::gmock::RapidCheckListener::install()` in your main file after Google Mock initialization. 8 | 9 | **Example:** 10 | 11 | ```C++ 12 | #include 13 | 14 | // Here is where Google Mock integration lives 15 | #include 16 | 17 | int main(int argc, char **argv) { 18 | ::testing::InitGoogleMock(&argc, argv); 19 | 20 | // This installs the RapidCheck listener. 21 | rc::gmock::RapidCheckListener::install(); 22 | 23 | return RUN_ALL_TESTS(); 24 | } 25 | ``` 26 | 27 | This will install a Google Test test event listener which will translate mock failures in to RapidCheck failures. 28 | 29 | ## Caveats 30 | 31 | RapidCheck replaces the default test listener with its own and wraps it so that the original listener gets the callbacks as usual when not in a property. However, even when in a property, there is no way for RapidCheck to prevent mock failures and Google Test assertion failures from being reported as errors to Google Test. This is usually not a problem since a single mock failure or assertion failure in a property usually means an actual failure. However, if you see weird behavior when you use Google Test together with RapidCheck, this might be the cause. 32 | -------------------------------------------------------------------------------- /doc/user_guide.md: -------------------------------------------------------------------------------- 1 | # RapidCheck User Guide 2 | 3 | The following document is a work in progress and some parts are still missing. There is more documentation to read in the form of source code comments if something is missing here. 4 | 5 | **Also, please note that the API has not stabilized yet and may change at any time.** 6 | 7 | ## Basics 8 | 9 | - [Properties](properties.md) 10 | - [Generators](generators.md) 11 | - [Displaying values](displaying.md) 12 | - [Assertions](assertions.md) 13 | - [Reporting distribution](distribution.md) 14 | - [Configuration](configuration.md) 15 | - [Debugging failures](debugging.md) 16 | - [Stateful testing](state.md) 17 | 18 | ## Extras 19 | 20 | - [Catch Test integratio](catch.md) 21 | - [Google Test integration](gtest.md) 22 | - [Google Mock integration](gmock.md) 23 | - [Boost support](boost.md) 24 | - [Boost Test integration](boost_test.md) 25 | 26 | ## Reference 27 | 28 | - [Generators](generators_ref.md) 29 | - [Stateful testing](state_ref.md) 30 | 31 | ## Advanced topics 32 | 33 | - [Gen\](Gen.md) 34 | - [Shrinkable\](Shrinkable.md) 35 | - [Seq\](Seq.md) 36 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(counter) 2 | add_subdirectory(mapparser) 3 | add_subdirectory(database) 4 | add_subdirectory(classify) 5 | 6 | if (RC_ENABLE_GTEST) 7 | add_subdirectory(gtest) 8 | endif() 9 | 10 | if (RC_ENABLE_BOOST_TEST) 11 | add_subdirectory(boost_test) 12 | endif() 13 | -------------------------------------------------------------------------------- /examples/boost_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(boost_test_integration main.cpp) 2 | target_link_libraries(boost_test_integration rapidcheck_boost_test boost) 3 | if (MSVC) 4 | target_compile_options(boost_test_integration PRIVATE "/EHa") 5 | else() 6 | # Boost uses auto_ptr which causes warnings on (at least) GCC 7 | target_compile_options(boost_test_integration PRIVATE "-Wno-deprecated-declarations") 8 | endif() 9 | -------------------------------------------------------------------------------- /examples/boost_test/main.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE main 2 | #include 3 | #include 4 | 5 | BOOST_AUTO_TEST_SUITE(RapidCheckExample) 6 | 7 | // Should succeed: 8 | RC_BOOST_PROP(copyOfStringIsIdenticalToOriginal, (const std::string &str)) { 9 | RC_CLASSIFY(str.empty()); 10 | const auto strCopy = str; 11 | RC_ASSERT(strCopy == str); 12 | } 13 | 14 | // Should obviously fail: 15 | RC_BOOST_PROP(dividingByTenMakesAllNumbersEqual, (int a, int b)) { 16 | RC_ASSERT((a / 10) == (b / 10)); 17 | } 18 | 19 | // If you don't have any arguments, you have to have an empty paren: 20 | RC_BOOST_PROP(inRangeValueIsInRange, ()) { 21 | const auto range = *rc::gen::arbitrary>(); 22 | const auto x = *rc::gen::inRange(range.first, range.second); 23 | RC_ASSERT(x >= range.first); 24 | RC_ASSERT(x < range.second); 25 | } 26 | 27 | // You can also create fixtures... 28 | class MyFixture { 29 | protected: 30 | MyFixture() 31 | : counter(0) {} 32 | 33 | void increment() { counter++; } 34 | 35 | std::size_t counter; 36 | }; 37 | 38 | // ...and use them like this: 39 | RC_BOOST_FIXTURE_PROP(shouldInstantiateFixtureOnEachRun, 40 | MyFixture, 41 | (const std::vector &ints)) { 42 | for (std::size_t i = 0; i < ints.size(); i++) { 43 | increment(); 44 | } 45 | 46 | RC_ASSERT(counter == ints.size()); 47 | } 48 | 49 | // A normal Boost test can use the same fixture: 50 | BOOST_FIXTURE_TEST_CASE(incrementIncrementsByOne, MyFixture) { 51 | BOOST_REQUIRE_EQUAL(0U, counter); 52 | increment(); 53 | BOOST_REQUIRE_EQUAL(1U, counter); 54 | } 55 | 56 | BOOST_AUTO_TEST_SUITE_END() 57 | -------------------------------------------------------------------------------- /examples/classify/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(classify main.cpp) 2 | target_link_libraries(classify rapidcheck) -------------------------------------------------------------------------------- /examples/classify/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace rc; 4 | 5 | enum class Gender { Male, Female }; 6 | 7 | std::ostream &operator<<(std::ostream &os, Gender gender) { 8 | os << ((gender == Gender::Male) ? "Male" : "Female"); 9 | return os; 10 | } 11 | 12 | struct User { 13 | std::string username; 14 | Gender gender; 15 | }; 16 | 17 | namespace rc { 18 | 19 | template <> 20 | struct Arbitrary { 21 | static Gen arbitrary() { 22 | return gen::build( 23 | gen::set(&User::username), 24 | gen::set(&User::gender, gen::element(Gender::Male, Gender::Female))); 25 | } 26 | }; 27 | 28 | } // namespace rc 29 | 30 | int main() { 31 | rc::check("RC_TAG", [](const User &user) { RC_TAG(user.gender); }); 32 | 33 | rc::check("RC_CLASSIFY", 34 | [](const User &user) { RC_CLASSIFY(user.username.empty()); }); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/counter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(counter main.cpp) 2 | 3 | target_link_libraries(counter rapidcheck) 4 | target_include_directories(counter PRIVATE ../../ext/catch/include) -------------------------------------------------------------------------------- /examples/counter/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace rc; 5 | 6 | class Counter { 7 | public: 8 | void inc() { m_value++; } 9 | 10 | void dec() { 11 | assert(m_value > 0); 12 | // Broken! 13 | if (m_value != 10) { 14 | m_value--; 15 | } 16 | } 17 | 18 | int get() { return m_value; } 19 | 20 | private: 21 | int m_value = 0; 22 | }; 23 | 24 | struct CounterModel { 25 | int value = 0; 26 | }; 27 | 28 | struct Inc : public state::Command { 29 | void apply(CounterModel &s0) const override { s0.value++; } 30 | 31 | void run(const CounterModel &s0, Counter &counter) const override { 32 | counter.inc(); 33 | RC_ASSERT(counter.get() == (s0.value + 1)); 34 | } 35 | }; 36 | 37 | struct Dec : public state::Command { 38 | void checkPreconditions(const CounterModel &s0) const override { 39 | RC_PRE(s0.value > 0); 40 | } 41 | 42 | void apply(CounterModel &s0) const override { s0.value--; } 43 | 44 | void run(const CounterModel &state, Counter &counter) const override { 45 | counter.dec(); 46 | RC_ASSERT(counter.get() == (state.value - 1)); 47 | } 48 | }; 49 | 50 | int main() { 51 | check([] { 52 | CounterModel state; 53 | Counter sut; 54 | state::check(state, sut, state::gen::execOneOfWithArgs()); 55 | }); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/database/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(database main.cpp 2 | Database.cpp 3 | DatabaseConnection.cpp 4 | User.cpp) 5 | 6 | target_link_libraries(database rapidcheck) -------------------------------------------------------------------------------- /examples/database/Database.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "User.h" 9 | 10 | class IDatabaseConnection; 11 | 12 | class Database { 13 | public: 14 | explicit Database(std::unique_ptr connection); 15 | 16 | void open(); 17 | void close(); 18 | void beginWrite(); 19 | void executeWrite(); 20 | void put(User user); 21 | bool get(const std::string &username, User &user); 22 | 23 | private: 24 | bool m_open; 25 | std::unique_ptr m_connection; 26 | std::map m_cache; 27 | bool m_hasBlock; 28 | std::vector m_queue; 29 | std::size_t m_hash; 30 | }; 31 | -------------------------------------------------------------------------------- /examples/database/DatabaseConnection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct Message { 8 | Message() = default; 9 | Message(std::string t, 10 | std::vector p = std::vector()); 11 | 12 | std::string type; 13 | std::vector params; 14 | }; 15 | 16 | class IDatabaseConnection { 17 | public: 18 | virtual Message sendMessage(const Message &msg) = 0; 19 | virtual ~IDatabaseConnection() = default; 20 | }; 21 | 22 | std::unique_ptr connectToDatabase(const std::string &id); 23 | -------------------------------------------------------------------------------- /examples/database/Generators.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "User.h" 4 | 5 | rc::Gen genFirstName() { 6 | return rc::gen::weightedOneOf( 7 | {{4, rc::gen::arbitrary()}, 8 | {8, rc::gen::element("John", "Chuck", "Kevin", "Oscar")}, 9 | {8, 10 | rc::gen::element("Jane", "Sarah", "Kate", "Elizabeth")}}); 11 | } 12 | 13 | rc::Gen genLastName() { 14 | return rc::gen::weightedOneOf({ 15 | {4, rc::gen::arbitrary()}, 16 | {16, rc::gen::element("Johnson", "Smith", "Cook", "Jobs")}, 17 | }); 18 | } 19 | 20 | rc::Gen genTown() { 21 | return rc::gen::weightedOneOf({ 22 | {4, rc::gen::arbitrary()}, 23 | {16, 24 | rc::gen::element( 25 | "Stockholm", "New York", "San Francisco", "Gothenburg")}, 26 | }); 27 | } 28 | 29 | namespace rc { 30 | 31 | template <> 32 | struct Arbitrary { 33 | static Gen arbitrary() { 34 | return gen::build( 35 | gen::set(&User::username, gen::nonEmpty()), 36 | gen::set(&User::firstName, genFirstName()), 37 | gen::set(&User::lastName, genLastName()), 38 | gen::set(&User::age, gen::inRange(0, 100)), 39 | gen::set(&User::gender, gen::element(Gender::Male, Gender::Female)), 40 | gen::set(&User::hometown, genTown())); 41 | } 42 | }; 43 | 44 | } // namespace rc 45 | -------------------------------------------------------------------------------- /examples/database/User.cpp: -------------------------------------------------------------------------------- 1 | #include "User.h" 2 | 3 | #include 4 | 5 | bool operator==(const User &lhs, const User &rhs) { 6 | return (lhs.username == rhs.username) && (lhs.firstName == rhs.firstName) && 7 | (lhs.lastName == rhs.lastName) && (lhs.age == rhs.age) && 8 | (lhs.gender == rhs.gender) && (lhs.hometown == rhs.hometown); 9 | } 10 | 11 | bool operator!=(const User &lhs, const User &rhs) { 12 | return !(lhs == rhs); 13 | } 14 | 15 | bool operator!=(const User &lhs, const User &rhs); 16 | 17 | std::ostream &operator<<(std::ostream &os, const Gender &gender) { 18 | os << ((gender == Gender::Male) ? "male" : "female"); 19 | return os; 20 | } 21 | 22 | std::ostream &operator<<(std::ostream &os, const User &user) { 23 | os << "{username='" << user.username << "', firstName='" << user.firstName 24 | << "', lastName='" << user.lastName << "', age=" << user.age 25 | << ", gender=" << user.gender << ", hometown='" << user.hometown << "'}"; 26 | return os; 27 | } 28 | 29 | void serialize(const User &user, std::vector &out) { 30 | out.push_back(user.username); 31 | out.push_back(user.firstName); 32 | out.push_back(user.lastName); 33 | out.push_back(std::to_string(user.age)); 34 | out.push_back((user.gender == Gender::Male) ? "male" : "female"); 35 | out.push_back(user.hometown); 36 | } 37 | 38 | std::vector::const_iterator 39 | deserialize(std::vector::const_iterator start, 40 | std::vector::const_iterator end, 41 | User &user) { 42 | if ((end - start) < 6) { 43 | return start; 44 | } 45 | 46 | user.username = start[0]; 47 | user.firstName = start[1]; 48 | user.lastName = start[2]; 49 | try { 50 | user.age = std::stoi(start[3]); 51 | } catch (const std::logic_error &) { 52 | return start; 53 | } 54 | user.gender = (start[4] == "male") ? Gender::Male : Gender::Female; 55 | user.hometown = start[5]; 56 | 57 | return start + 6; 58 | } 59 | -------------------------------------------------------------------------------- /examples/database/User.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Gender { Male, Female }; 8 | 9 | struct User { 10 | std::string username; 11 | std::string firstName; 12 | std::string lastName; 13 | int age; 14 | Gender gender; 15 | std::string hometown; 16 | }; 17 | 18 | bool operator==(const User &lhs, const User &rhs); 19 | bool operator!=(const User &lhs, const User &rhs); 20 | std::ostream &operator<<(std::ostream &os, const Gender &gender); 21 | std::ostream &operator<<(std::ostream &os, const User &user); 22 | 23 | void serialize(const User &user, std::vector &out); 24 | 25 | std::vector::const_iterator 26 | deserialize(std::vector::const_iterator start, 27 | std::vector::const_iterator end, 28 | User &user); 29 | 30 | namespace std { 31 | 32 | template <> 33 | struct hash { 34 | typedef User argument_type; 35 | typedef std::size_t result_type; 36 | 37 | result_type operator()(const User &user) const { 38 | std::size_t h = 0; 39 | // Yeah I know, this is broken but it's just an example 40 | h ^= std::hash()(user.username); 41 | h ^= std::hash()(user.firstName); 42 | h ^= std::hash()(user.lastName); 43 | h ^= std::hash()(user.age); 44 | h ^= std::hash()((user.gender == Gender::Male) ? true : false); 45 | h ^= std::hash()(user.hometown); 46 | 47 | return h; 48 | } 49 | }; 50 | 51 | } // namespace std 52 | -------------------------------------------------------------------------------- /examples/gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(gtest_integration main.cpp) 2 | target_link_libraries(gtest_integration rapidcheck_gtest gtest) 3 | target_include_directories(gtest_integration PRIVATE 4 | ${CMAKE_SOURCE_DIR}/ext/gmock/gtest/include) 5 | -------------------------------------------------------------------------------- /examples/mapparser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mapparser main.cpp MapParser.cpp) 2 | target_link_libraries(mapparser rapidcheck) -------------------------------------------------------------------------------- /examples/mapparser/MapParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class ParseException : public std::exception { 8 | public: 9 | ParseException(std::string::size_type pos, const std::string &msg); 10 | std::string::size_type position() const; 11 | std::string message() const; 12 | const char *what() const noexcept override; 13 | 14 | private: 15 | std::string::size_type m_pos; 16 | std::string m_msg; 17 | std::string m_what; 18 | }; 19 | 20 | std::map parseMap(const std::string &str); 21 | 22 | std::string mapToString(const std::map &map, 23 | bool doubleQuote = false); 24 | -------------------------------------------------------------------------------- /examples/mapparser/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "MapParser.h" 4 | 5 | using namespace rc; 6 | 7 | int main() { 8 | rc::check("serializing and then parsing should yield original map", 9 | [](const std::map &map) { 10 | RC_PRE(map.find("") == map.end()); 11 | RC_ASSERT(parseMap(mapToString(map)) == map); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /ext/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (RC_ENABLE_TESTS OR RC_ENABLE_CATCH) 2 | add_subdirectory(catch) 3 | endif() 4 | 5 | if ((RC_ENABLE_GMOCK OR RC_ENABLE_GTEST) AND RC_ENABLE_TESTS) 6 | # On Windows, gmock/gtest defaults to static CRT which is not compatible 7 | # with the way RapidCheck is currently built 8 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 9 | add_subdirectory(googletest) 10 | endif() 11 | 12 | if (RC_ENABLE_BOOST AND RC_ENABLE_TESTS) 13 | if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/boost") 14 | execute_process( 15 | COMMAND "sh" "get_boost.sh" 16 | WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") 17 | endif() 18 | add_library(boost INTERFACE) 19 | target_include_directories(boost INTERFACE boost) 20 | endif() 21 | -------------------------------------------------------------------------------- /ext/get_boost.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | curl -s -L -o boost_1_68_0.tar.bz2 https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2 3 | tar xjfp boost_1_68_0.tar.bz2 4 | mv boost_1_68_0 boost 5 | rm boost_1_68_0.tar.bz2 6 | -------------------------------------------------------------------------------- /extras/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Since 2 | option(RC_INSTALL_ALL_EXTRAS "Add all possible integrations without 3 | requiring the initialization of all the submodules in ext." OFF) 4 | 5 | option(RC_ENABLE_CATCH "Build Catch.hpp support" OFF) 6 | if (RC_ENABLE_CATCH OR RC_ENABLE_TESTS OR RC_INSTALL_ALL_EXTRAS) 7 | add_subdirectory(catch) 8 | endif() 9 | 10 | option(RC_ENABLE_DOCTEST "Build DocTest support" OFF) 11 | if (RC_ENABLE_DOCTEST OR RC_ENABLE_TESTS OR RC_INSTALL_ALL_EXTRAS) 12 | add_subdirectory(doctest) 13 | endif() 14 | 15 | option(RC_ENABLE_GMOCK "Build Google Mock integration" OFF) 16 | if (RC_ENABLE_GMOCK OR RC_INSTALL_ALL_EXTRAS) 17 | add_subdirectory(gmock) 18 | endif() 19 | 20 | option(RC_ENABLE_GTEST "Build Google Test integration" OFF) 21 | if (RC_ENABLE_GTEST OR RC_INSTALL_ALL_EXTRAS) 22 | add_subdirectory(gtest) 23 | endif() 24 | 25 | option(RC_ENABLE_BOOST "Build Boost support" OFF) 26 | if (RC_ENABLE_BOOST OR RC_INSTALL_ALL_EXTRAS) 27 | add_subdirectory(boost) 28 | endif() 29 | 30 | option(RC_ENABLE_BOOST_TEST "Build Boost Test support" OFF) 31 | if (RC_ENABLE_BOOST_TEST OR RC_INSTALL_ALL_EXTRAS) 32 | add_subdirectory(boost_test) 33 | endif() 34 | -------------------------------------------------------------------------------- /extras/boost/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_boost CXX) 2 | 3 | add_library(rapidcheck_boost INTERFACE) 4 | target_link_libraries(rapidcheck_boost INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_boost INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_boost EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | if (RC_ENABLE_TESTS) 16 | add_subdirectory(test) 17 | endif() 18 | 19 | set(PKG_CONFIG_REQUIRES "rapidcheck") 20 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "boost headers for rapidcheck") 21 | set(PKG_CONFIG_VERSION) 22 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 23 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 24 | set(PKG_CONFIG_LIBS) 25 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 26 | 27 | configure_file( 28 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 29 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 30 | ) 31 | 32 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 33 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 34 | ) 35 | -------------------------------------------------------------------------------- /extras/boost/include/rapidcheck/boost.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "rapidcheck/gen/boost/Optional.h" 6 | -------------------------------------------------------------------------------- /extras/boost/include/rapidcheck/gen/boost/Optional.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rc { 6 | namespace gen { 7 | namespace boost { 8 | 9 | /// Generates a `boost::optional` of values generated by the given generator. 10 | template 11 | Gen<::boost::optional> optional(Gen gen); 12 | 13 | } // namespace boost 14 | } // namespace gen 15 | } // namespace rc 16 | 17 | #include "Optional.hpp" 18 | -------------------------------------------------------------------------------- /extras/boost/include/rapidcheck/gen/boost/Optional.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace rc { 4 | namespace gen { 5 | namespace boost { 6 | 7 | template 8 | Gen<::boost::optional> optional(Gen gen) { 9 | return gen::map>(gen::maybe(std::move(gen)), 10 | [](Maybe &&m) { 11 | return m ? ::boost::optional(std::move(*m)) 12 | : ::boost::optional(); 13 | }); 14 | } 15 | 16 | } // namespace boost 17 | } // namespace gen 18 | 19 | template 20 | struct Arbitrary> { 21 | static Gen> arbitrary() { 22 | return gen::boost::optional(gen::arbitrary()); 23 | } 24 | }; 25 | 26 | template 27 | void showValue(const boost::optional &x, std::ostream &os) { 28 | if (x) { 29 | show(*x, os); 30 | } else { 31 | os << "boost::none"; 32 | } 33 | } 34 | 35 | } // namespace rc 36 | -------------------------------------------------------------------------------- /extras/boost/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(rapidcheck_boost_tests 2 | main.cpp 3 | OptionalTests.cpp 4 | ) 5 | 6 | target_link_libraries(rapidcheck_boost_tests 7 | boost 8 | rapidcheck_boost 9 | rapidcheck_catch 10 | rapidcheck_test_utils 11 | Catch2::Catch2) 12 | 13 | add_test( 14 | NAME rapidcheck_boost_tests 15 | COMMAND rapidcheck_boost_tests) 16 | -------------------------------------------------------------------------------- /extras/boost/test/OptionalTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "util/ShrinkableUtils.h" 6 | #include "util/GenUtils.h" 7 | #include "util/Predictable.h" 8 | #include "util/Box.h" 9 | 10 | using namespace rc; 11 | using namespace rc::test; 12 | 13 | TEST_CASE("gen::boost::optional") { 14 | prop("equivalent to gen::maybe", 15 | [](const GenParams ¶ms) { 16 | const auto gen = gen::arbitrary(); 17 | const auto maybeShrinkable = 18 | gen::maybe(gen)(params.random, params.size); 19 | const auto optionalShrinkable = shrinkable::map( 20 | gen::boost::optional(gen)(params.random, params.size), 21 | [](const boost::optional &x) -> Maybe { 22 | if (x) { 23 | return std::move(*x); 24 | } else { 25 | return Nothing; 26 | } 27 | }); 28 | 29 | assertEquivalent(maybeShrinkable, optionalShrinkable); 30 | }); 31 | 32 | prop("chooses correct Arbitrary instance", 33 | [](const GenParams ¶ms) { 34 | const auto gen = gen::arbitrary>(); 35 | const auto value = gen(params.random, params.size).value(); 36 | RC_PRE(value); 37 | RC_ASSERT(isArbitraryPredictable(*value)); 38 | }); 39 | } 40 | 41 | TEST_CASE("showValue(boost::optional)") { 42 | prop("shows present value using rc::show", 43 | [](const Box &x) { 44 | std::ostringstream actual; 45 | showValue(boost::make_optional(x), actual); 46 | std::ostringstream expected; 47 | showValue(x, expected); 48 | RC_ASSERT(actual.str() == expected.str()); 49 | }); 50 | 51 | SECTION("shows non-present value as 'boost::none'") { 52 | std::ostringstream os; 53 | showValue(boost::optional(), os); 54 | REQUIRE(os.str() == "boost::none"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /extras/boost/test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #if (__GLIBCXX__ / 10000) == 2014 3 | 4 | namespace std { 5 | 6 | inline bool uncaught_exception() noexcept(true) { 7 | return current_exception() != nullptr; 8 | } 9 | 10 | } // namespace std 11 | 12 | #endif 13 | 14 | #define CATCH_CONFIG_MAIN 15 | #include 16 | -------------------------------------------------------------------------------- /extras/boost_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_boost_test CXX) 2 | 3 | add_library(rapidcheck_boost_test INTERFACE) 4 | target_link_libraries(rapidcheck_boost_test INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_boost_test INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_boost_test EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | set(PKG_CONFIG_REQUIRES "rapidcheck") 16 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "boost_test headers for rapidcheck") 17 | set(PKG_CONFIG_VERSION) 18 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 19 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 20 | set(PKG_CONFIG_LIBS) 21 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 22 | 23 | configure_file( 24 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 25 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 26 | ) 27 | 28 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 29 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 30 | ) 31 | -------------------------------------------------------------------------------- /extras/catch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_catch CXX) 2 | 3 | add_library(rapidcheck_catch INTERFACE) 4 | target_link_libraries(rapidcheck_catch INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_catch INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_catch EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | set(PKG_CONFIG_REQUIRES "rapidcheck") 16 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "catch headers for rapidcheck") 17 | set(PKG_CONFIG_VERSION) 18 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 19 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 20 | set(PKG_CONFIG_LIBS) 21 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 22 | 23 | configure_file( 24 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 25 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 26 | ) 27 | 28 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 29 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 30 | ) 31 | -------------------------------------------------------------------------------- /extras/catch/include/rapidcheck/catch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | // To support Catch2 v3 we check if the new header has already been included, 8 | // otherwise we include the old header. 9 | #ifndef CATCH_TEST_MACROS_HPP_INCLUDED 10 | #include 11 | #endif 12 | 13 | namespace rc { 14 | 15 | /// For use with `catch2/catch.hpp`. Use this function wherever you would use a 16 | /// `SECTION` for convenient checking of properties. 17 | /// 18 | /// @param description A description of the property. 19 | /// @param testable The object that implements the property. 20 | template 21 | void prop(const std::string &description, Testable &&testable, bool verbose=false) { 22 | using namespace detail; 23 | 24 | #ifdef CATCH_CONFIG_PREFIX_ALL 25 | CATCH_SECTION(description) { 26 | #else 27 | SECTION(description) { 28 | #endif 29 | 30 | const auto result = checkTestable(std::forward(testable)); 31 | 32 | if (result.template is()) { 33 | const auto success = result.template get(); 34 | if (verbose || !success.distribution.empty()) { 35 | std::cout << "- " << description << std::endl; 36 | printResultMessage(result, std::cout); 37 | std::cout << std::endl; 38 | } 39 | #ifdef CATCH_CONFIG_PREFIX_ALL 40 | CATCH_SUCCEED(); 41 | #else 42 | SUCCEED(); 43 | #endif 44 | } else { 45 | std::ostringstream ss; 46 | printResultMessage(result, ss); 47 | #ifdef CATCH_CONFIG_PREFIX_ALL 48 | CATCH_INFO(ss.str() << "\n"); 49 | CATCH_FAIL(); 50 | #else 51 | INFO(ss.str() << "\n"); 52 | FAIL(); 53 | #endif 54 | } 55 | } 56 | } 57 | 58 | } // namespace rc 59 | -------------------------------------------------------------------------------- /extras/doctest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_doctest CXX) 2 | 3 | add_library(rapidcheck_doctest INTERFACE) 4 | target_link_libraries(rapidcheck_doctest INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_doctest INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_doctest EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | set(PKG_CONFIG_REQUIRES "rapidcheck") 16 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "doctest headers for rapidcheck") 17 | set(PKG_CONFIG_VERSION) 18 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 19 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 20 | set(PKG_CONFIG_LIBS) 21 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 22 | 23 | configure_file( 24 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 25 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 26 | ) 27 | 28 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 29 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 30 | ) 31 | -------------------------------------------------------------------------------- /extras/gmock/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_gtest CXX) 2 | 3 | add_library(rapidcheck_gmock INTERFACE) 4 | target_link_libraries(rapidcheck_gmock INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_gmock INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_gmock EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | if (RC_ENABLE_TESTS) 16 | add_subdirectory(test) 17 | endif() 18 | 19 | set(PKG_CONFIG_REQUIRES "rapidcheck") 20 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "gmock headers for rapidcheck") 21 | set(PKG_CONFIG_VERSION) 22 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 23 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 24 | set(PKG_CONFIG_LIBS) 25 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 26 | 27 | configure_file( 28 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 29 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 30 | ) 31 | 32 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 33 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 34 | ) 35 | -------------------------------------------------------------------------------- /extras/gmock/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(rapidcheck_gmock_tests main.cpp) 2 | target_link_libraries(rapidcheck_gmock_tests 3 | rapidcheck_gmock 4 | rapidcheck_catch 5 | Catch2::Catch2 6 | gmock) 7 | target_include_directories(rapidcheck_gmock_tests PRIVATE 8 | ${CMAKE_SOURCE_DIR}/ext/googletest/googletest/include 9 | ${CMAKE_SOURCE_DIR}/ext/googletest/googlemock/include) 10 | 11 | # Prevent collision between Gmock and Catch 12 | target_compile_definitions(rapidcheck_gmock_tests PRIVATE 13 | CATCH_CONFIG_PREFIX_ALL) 14 | 15 | add_test( 16 | NAME rapidcheck_gmock_tests 17 | COMMAND rapidcheck_gmock_tests) 18 | -------------------------------------------------------------------------------- /extras/gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(rapidcheck_gtest CXX) 2 | 3 | add_library(rapidcheck_gtest INTERFACE) 4 | target_link_libraries(rapidcheck_gtest INTERFACE rapidcheck) 5 | target_include_directories(rapidcheck_gtest INTERFACE 6 | $ 7 | $ 8 | ) 9 | 10 | # An INTERFACE library does not need to install anything but its headers 11 | # and information on its targets. 12 | install(TARGETS rapidcheck_gtest EXPORT rapidcheckConfig) 13 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 14 | 15 | set(PKG_CONFIG_REQUIRES "rapidcheck") 16 | set(PKG_CONFIG_DESCRIPTION_SUMMARY "gtest headers for rapidcheck") 17 | set(PKG_CONFIG_VERSION) 18 | set(PKG_CONFIG_LIBDIR "\${prefix}/lib") 19 | set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include") 20 | set(PKG_CONFIG_LIBS) 21 | set(PKG_CONFIG_CFLAGS "-I\${includedir}") 22 | 23 | configure_file( 24 | "${CMAKE_CURRENT_SOURCE_DIR}/../../pkg-config.pc.cmake" 25 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 26 | ) 27 | 28 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" 29 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 30 | ) 31 | -------------------------------------------------------------------------------- /include/rapidcheck.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // MSVC HACK - Undefine stupid MS macros 4 | #undef min 5 | #undef max 6 | 7 | #include "rapidcheck/Seq.h" 8 | #include "rapidcheck/seq/Create.h" 9 | #include "rapidcheck/seq/Operations.h" 10 | #include "rapidcheck/seq/SeqIterator.h" 11 | #include "rapidcheck/seq/Transform.h" 12 | 13 | #include "rapidcheck/Shrinkable.h" 14 | #include "rapidcheck/shrinkable/Create.h" 15 | #include "rapidcheck/shrinkable/Operations.h" 16 | #include "rapidcheck/shrinkable/Transform.h" 17 | 18 | #include "rapidcheck/Gen.h" 19 | #include "rapidcheck/gen/Arbitrary.h" 20 | #include "rapidcheck/gen/Build.h" 21 | #include "rapidcheck/gen/Chrono.h" 22 | #include "rapidcheck/gen/Container.h" 23 | #include "rapidcheck/gen/Create.h" 24 | #include "rapidcheck/gen/Exec.h" 25 | #include "rapidcheck/gen/Maybe.h" 26 | #include "rapidcheck/gen/Numeric.h" 27 | #include "rapidcheck/gen/Predicate.h" 28 | #include "rapidcheck/gen/Select.h" 29 | #include "rapidcheck/gen/Text.h" 30 | #include "rapidcheck/gen/Transform.h" 31 | #include "rapidcheck/gen/Tuple.h" 32 | 33 | #include "rapidcheck/Assertions.h" 34 | #include "rapidcheck/Check.h" 35 | #include "rapidcheck/Classify.h" 36 | #include "rapidcheck/Log.h" 37 | #include "rapidcheck/Show.h" 38 | -------------------------------------------------------------------------------- /include/rapidcheck/Assertions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace rc { 4 | namespace detail { 5 | 6 | std::string makeMessage(const std::string &file, 7 | int line, 8 | const std::string &assertion, 9 | const std::string &extra = ""); 10 | 11 | std::string makeExpressionMessage(const std::string &file, 12 | int line, 13 | const std::string &assertion, 14 | const std::string &expansion); 15 | 16 | std::string makeUnthrownExceptionMessage(const std::string &file, 17 | int line, 18 | const std::string &assertion); 19 | 20 | std::string makeWrongExceptionMessage(const std::string &file, 21 | int line, 22 | const std::string &assertion, 23 | const std::string &expected); 24 | 25 | template 26 | void doAssert(const Expression &expression, 27 | bool expectedResult, 28 | CaseResult::Type type, 29 | const std::string &file, 30 | int line, 31 | const std::string &assertion) { 32 | if (static_cast(expression.value()) != expectedResult) { 33 | std::ostringstream ss; 34 | expression.show(ss); 35 | throw CaseResult(type, 36 | makeExpressionMessage(file, line, assertion, ss.str())); 37 | } 38 | } 39 | 40 | } // namespace detail 41 | } // namespace rc 42 | -------------------------------------------------------------------------------- /include/rapidcheck/BeforeMinimalTestCase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace rc { 4 | 5 | /// This is called before the final minimal test case is run when a property 6 | /// fails. Set a breakpoint here if you want to debug that test case. When the 7 | /// debugger breaks here, you can set up any further breakpoints or other tools 8 | /// before the test case is actually run. 9 | void beforeMinimalTestCase(); 10 | 11 | } // namespace rc 12 | -------------------------------------------------------------------------------- /include/rapidcheck/Check.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rc { 6 | 7 | /// Checks the given testable and returns `true` on success and `false` on 8 | /// failure. This method will also print information about the testing to 9 | /// stderr. 10 | template 11 | bool check(Testable &&testable); 12 | 13 | /// Same as `check(Testable &&)` but also takes a description of the property 14 | /// that is being tested as the first parameter. This will be used in the 15 | /// output. 16 | template 17 | bool check(const std::string &description, Testable &&testable); 18 | 19 | } // namespace rc 20 | 21 | #include "Check.hpp" 22 | -------------------------------------------------------------------------------- /include/rapidcheck/Classify.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// Tags the current test case if the specified condition is true. If any tags 4 | /// are specified after the condition, those will be used. Otherwise, a string 5 | /// version of the condition itself will be used as the tag. 6 | #define RC_CLASSIFY(condition, ...) \ 7 | do { \ 8 | if (condition) { \ 9 | ::rc::detail::classify(#condition, {__VA_ARGS__}); \ 10 | } \ 11 | } while (false) 12 | 13 | /// Tags the current test case with the given values which will be converted to 14 | /// strings. 15 | #define RC_TAG(...) ::rc::detail::tag({__VA_ARGS__}) 16 | 17 | #include "Classify.hpp" 18 | -------------------------------------------------------------------------------- /include/rapidcheck/Classify.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rc { 6 | namespace detail { 7 | 8 | struct Stringified { 9 | template 10 | Stringified(const T &value) 11 | : str(toString(value)) {} 12 | std::string str; 13 | }; 14 | 15 | void tag(std::initializer_list tags); 16 | void classify(std::string condition, std::initializer_list tags); 17 | 18 | } // namespace detail 19 | } // namespace rc 20 | -------------------------------------------------------------------------------- /include/rapidcheck/Compat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rapidcheck/Compat.hpp" 4 | -------------------------------------------------------------------------------- /include/rapidcheck/Compat.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rc { 6 | namespace compat { 7 | 8 | #if __cpp_lib_is_invocable >= 201703 9 | template 10 | using return_type = typename std::invoke_result; 11 | #else 12 | template 13 | using return_type = typename std::result_of; 14 | #endif 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/rapidcheck/GenerationFailure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rc { 6 | 7 | /// Thrown to indicate that an appropriate value couldn't be generated. 8 | class GenerationFailure : public std::runtime_error { 9 | public: 10 | explicit GenerationFailure(std::string msg); 11 | }; 12 | 13 | } // namespace rc 14 | -------------------------------------------------------------------------------- /include/rapidcheck/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /// Logs additional information about the run of a test case. Can be used either 6 | /// like a stream (`RC_LOG() << "foobar"`) or taking a string 7 | /// (`RC_LOG("foobar")`). When using the latter form, a newline will be appended 8 | /// automatically. 9 | #define RC_LOG(...) ::rc::detail::log(__VA_ARGS__) 10 | 11 | #include "Log.hpp" 12 | -------------------------------------------------------------------------------- /include/rapidcheck/Log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace rc { 4 | namespace detail { 5 | 6 | /// Returns the current logging stream. 7 | std::ostream &log(); 8 | 9 | /// Logs the given message. 10 | void log(const std::string &msg); 11 | 12 | } // namespace detail 13 | } // namespace rc 14 | -------------------------------------------------------------------------------- /include/rapidcheck/Nothing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace rc { 4 | 5 | /// Tag struct that can be used to construct different types to an uninitialized 6 | /// or empty state. 7 | struct NothingType { 8 | /// Explicit conversion to false. 9 | explicit operator bool() const { return false; } 10 | }; 11 | 12 | /// Singleton NothingType value. 13 | constexpr NothingType Nothing = NothingType(); 14 | 15 | } // namespace rc 16 | -------------------------------------------------------------------------------- /include/rapidcheck/Random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rapidcheck/detail/Serialization.h" 4 | 5 | namespace rc { 6 | 7 | template 8 | Iterator serialize(const Random &random, Iterator output) { 9 | using namespace rc::detail; 10 | auto oit = output; 11 | oit = serializeN(begin(random.m_key), random.m_key.size(), oit); 12 | oit = serializeCompact(random.m_bits, oit); 13 | oit = serializeCompact(random.m_counter, oit); 14 | *oit = random.m_bitsi; 15 | return ++oit; 16 | } 17 | 18 | template 19 | Iterator deserialize(Iterator begin, Iterator end, Random &output) { 20 | using namespace rc::detail; 21 | auto iit = begin; 22 | 23 | iit = deserializeN( 24 | iit, end, output.m_key.size(), output.m_key.begin()); 25 | iit = deserializeCompact(iit, end, output.m_bits); 26 | 27 | Random::Counter counter; 28 | iit = deserializeCompact(iit, end, counter); 29 | // Normally, the block is calculated lazily if counter is divisible by 4 so 30 | // let's simulate this. 31 | if (counter != 0) { 32 | const auto blki = 33 | ((counter - 1) % std::tuple_size::value) + 1; 34 | if (blki != 0) { 35 | // Calculate the block as if counter % 4 == 0 36 | output.m_counter = counter - blki; 37 | output.mash(output.m_block); 38 | } 39 | } 40 | output.m_counter = counter; 41 | 42 | output.m_bitsi = *iit; 43 | return ++iit; 44 | } 45 | 46 | } // namespace rc 47 | -------------------------------------------------------------------------------- /include/rapidcheck/Show.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace rc { 7 | 8 | /// Outputs a human readable representation of the given value to the given 9 | /// output stream. To do this, it tries the following methods in order until one 10 | /// works: 11 | /// 12 | /// 1. Use a suitable overload of `void showValue(T, std::ostream)´ 13 | /// 2. Use a suitable overload of `std::ostream &operator<<(...)` 14 | /// 3. Output a placeholder value. 15 | template 16 | void show(const T &value, std::ostream &os); 17 | 18 | /// Uses show(...) to convert argument to a string. 19 | template 20 | std::string toString(const T &value); 21 | 22 | /// Helper function for showing collections of values. 23 | /// 24 | /// @param prefix The prefix to the collection, for example "[" 25 | /// @param suffix The suffix to the collection, for example "]" 26 | /// @param collection The collection type. Must support `begin()` and `end()`. 27 | /// @param os The stream to output to. 28 | template 29 | void showCollection(const std::string &prefix, 30 | const std::string &suffix, 31 | const Collection &collection, 32 | std::ostream &os); 33 | 34 | } // namespace rc 35 | 36 | #include "Show.hpp" 37 | -------------------------------------------------------------------------------- /include/rapidcheck/Shrinkable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rapidcheck/Seq.h" 4 | 5 | namespace rc { 6 | 7 | /// A `Shrinkable` describes a value in addition to all the possible ways of 8 | /// shrinking that value. 9 | /// 10 | /// `Shrinkable` is backed by a type erased implementation object which must 11 | /// have the following: 12 | /// - A method `T value() const` which returns the value. 13 | /// - A method `Seq> shrinks() const` which returns a `Seq` of 14 | /// the possible shrinks. If this method throws, it is treated as if it had 15 | /// returned an empty `Seq`. 16 | /// 17 | /// A Shrinkable is immutable and the implementation object is shared when the 18 | /// shrinkable is copied which is why the implementation object needs no copy 19 | /// constructor. 20 | template 21 | class Shrinkable { 22 | template 23 | friend Shrinkable().value())>> 24 | makeShrinkable(Args &&... args); 25 | 26 | public: 27 | /// The type of the value in this `Shrinkable`. 28 | using ValueType = T; 29 | 30 | /// Returns the value. 31 | T value() const; 32 | 33 | /// Returns a `Seq` of all the possible shrinks of this `Shrinkable`. 34 | Seq> shrinks() const noexcept; 35 | 36 | Shrinkable(const Shrinkable &other) noexcept; 37 | Shrinkable(Shrinkable &&other) noexcept; 38 | Shrinkable &operator=(const Shrinkable &other) noexcept; 39 | Shrinkable &operator=(Shrinkable &&other) noexcept; 40 | ~Shrinkable() noexcept; 41 | 42 | private: 43 | Shrinkable() = default; 44 | 45 | class IShrinkableImpl; 46 | 47 | template 48 | class ShrinkableImpl; 49 | 50 | IShrinkableImpl *m_impl = nullptr; 51 | }; 52 | 53 | /// Two `Shrinkable`s are equal if the have the same value and the same shrinks. 54 | template 55 | bool operator==(const Shrinkable &lhs, const Shrinkable &rhs); 56 | 57 | template 58 | bool operator!=(const Shrinkable &lhs, const Shrinkable &rhs); 59 | 60 | } // namespace rc 61 | 62 | #include "Shrinkable.hpp" 63 | -------------------------------------------------------------------------------- /include/rapidcheck/Traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "rapidcheck/detail/IntSequence.h" 6 | 7 | namespace rc { 8 | 9 | /// Convenience wrapper over std::decay, shorter to type. 10 | template 11 | using Decay = typename std::decay::type; 12 | 13 | /// Checks that all the parameters are true. 14 | template 15 | struct AllTrue 16 | : public std::is_same, 17 | detail::IntSequence> {}; 18 | 19 | /// Checks that all the types in `Ts` conforms to type trait `F`. 20 | template