Generates **property-based tests** that use randomized input generation to validate invariants and contracts (rather than hand-picked examples). Triggers when the conversation involves: PBT frameworks (Hypothesis library for Python, fast-check for TypeScript, proptest for Rust, rapid for Go, RapidCheck for C++); concepts like invariants, contracts, round-trip symmetry, encode/decode, serialize/deserialize, generative testing, or shrinking; or requests to find edge cases that example-based tests miss — e.g., "find edge cases automatically", "test all possible inputs", "verify this property holds". Does NOT trigger for: writing regular example-based unit tests, debugging, CI/CD setup, UI/component testing, or integration/E2E testing. Identifies up to 7 property patterns (round-trip, idempotence, invariance, metamorphic, inverse, ordering, no-crash), designs input generators, writes property tests, and extracts regression tests from failures.
91
90%
Does it follow best practices?
Impact
94%
1.11xAverage score across 5 eval scenarios
Passed
No known issues
Installation:
vcpkg install rapidcheck#include <rapidcheck.h>*rc::gen::arbitrary<int>() // Any int
rc::gen::inRange(0, 100) // Int in range [0, 100)
rc::gen::arbitrary<float>() // Any float
rc::gen::arbitrary<std::string>() // Any string (including empty)
rc::gen::string() // Any string
rc::gen::string(std::regex("[a-z]+")) // Regex-constrained string
rc::gen::arbitrary<bool>() // true or false
rc::gen::arbitrary<char>() // Any char
rc::gen::container<std::vector<int>>(rc::gen::arbitrary<int>()) // Vector of ints
rc::gen::container<std::map<std::string, int>>(...) // Map
rc::gen::pair(rc::gen::arbitrary<int>(), rc::gen::arbitrary<std::string>()) // Pairs
rc::gen::oneOf(rc::gen::value(0), rc::gen::value(1)) // One of several values#include <rapidcheck.h>
#include <rapidcheck/gtest.h>
#include <algorithm>
#include <vector>
RC_GTEST_PROP(sort, length_invariant, (std::vector<int> v)) {
auto original_len = v.size();
std::sort(v.begin(), v.end());
RC_ASSERT(v.size() == original_len);
}
RC_GTEST_PROP(sort, is_ordered, (std::vector<int> v)) {
std::sort(v.begin(), v.end());
for (size_t i = 0; i + 1 < v.size(); i++) {
RC_ASSERT(v[i] <= v[i + 1]);
}
}RC_ASSERT(expr); // Like assert, but with proper failure reporting
RC_ASSERT(expr == expected); // Equality check with nice output
RC_ASSERT_THROWS(expr); // Assert that expression throwsRC_GTEST_PROP(divide, properties, (int a, int b)) {
RC_PRE(b != 0); // Skip when b is zero
int result = a / b;
// At minimum, this shouldn't crash
(void)result;
}struct User {
std::string name;
int age;
};
// Custom generator using rc::gen::apply
auto genUser = rc::gen::apply([](const std::string& name, int age) {
return User{name, age};
}, rc::gen::string<std::string>(),
rc::gen::inRange(0, 150));
RC_GTEST_PROP(user, has_name, ()) {
auto user = *genUser;
RC_ASSERT(!user.name.empty());
}
// Or using rc::gen::exec
auto genUser2 = rc::gen::exec([](User& u) {
u.name = *rc::gen::string<std::string>();
u.age = *rc::gen::inRange(0, 150);
});
// Or simpler: define a generator function
User genUser3() {
return User{
*rc::gen::string<std::string>(),
*rc::gen::inRange(0, 150)
};
}* to Unpack GeneratorsInside property tests, * unpacks/draws from a generator:
RC_GTEST_PROP(my_test, property, ()) {
// Inside a property body, * unpacks a generator
auto x = *rc::gen::arbitrary<int>();
// For parameterized tests, parameters are automatically drawn
}TEST(MySuite, SortProperties) {
rc::check("length is invariant",
[](const std::vector<int>& v) {
auto original_len = v.size();
auto sorted = v;
std::sort(sorted.begin(), sorted.end());
RC_ASSERT(sorted.size() == original_len);
});
rc::check("result is ordered",
[](const std::vector<int>& v) {
auto sorted = v;
std::sort(sorted.begin(), sorted.end());
for (size_t i = 0; i + 1 < sorted.size(); i++) {
RC_ASSERT(sorted[i] <= sorted[i + 1]);
}
});
}// Per-test configuration
RC_GTEST_PROP(sort, heavy_test, (std::vector<int> v)) {
RC_DISCARD(v.size() > 1000); // Skip large inputs for performance
// ...
}
// Set number of test cases globally:
// Pass --rc-params "{\"numTests\": 1000}" on command line
// Or set via RC_PARAMS environment variable# With GTest
cmake --build . && ./tests --gtest_filter="*sort*"
# Pass RapidCheck parameters via environment
RC_PARAMS='{"numTests":500}' ./tests* operator to "draw" values from generators (like Rust's ? but for generators)RC_GTEST_PROP integrates directly with Google TestRC_ASSERT is critical — regular assert won't give you proper shrinking reportsRC_GTEST_PROP(name, desc, (params)) are automatically drawn from default generators — you don't need to call anything