Skip to content

Property API Reference

New to property-based testing? Start with the Walkthrough for a step-by-step guide to creating your first property test. This page provides the complete API reference.

Overview

cppproptest provides a property-based testing framework where you define properties (invariants) that should hold for all inputs in a domain, rather than testing specific examples. The framework automatically generates random inputs and verifies your properties.

Kroki

Quick Reference

Functions

Function Description Returns
proptest::property(callable, ...generators) Create a Property object from a callable Property
proptest::forAll(callable, ...) Create and run a property immediately Property
proptest::matrix(callable, ...lists) Create and run a matrix test immediately Property

Property Class Methods

Method Description Returns
.forAll(...generators) Run property with random inputs Property
.example(...args) Run property with specific inputs Property
.matrix(...lists) Run property with Cartesian product of inputs Property

See Chaining for immutable chaining, failure propagation, short-circuiting, and config preservation.

Configuration Methods

All configuration methods return a reference to Property, allowing method chaining.

Method Description Parameters
.setSeed(seed) Set random seed for reproducibility uint64_t seed
.setNumRuns(runs) Set number of test runs uint32_t runs (default: 1000)
.setMaxDurationMs(duration) Set maximum test duration in milliseconds uint32_t durationMs
.setOnStartup(callback) Set callback called before each test run Function<void()> callback
.setOnCleanup(callback) Set callback called after each test run Function<void()> callback
.setShrinkMaxRetries(retries) Max retries per candidate; total trials = 1 + retries (0 = deterministic, 1 trial) uint32_t retries
.setShrinkTimeoutMs(ms) Total shrink phase timeout in ms (0 = no limit) uint32_t ms
.setShrinkRetryTimeoutMs(ms) Per-candidate timeout in ms (0 = no limit) uint32_t ms
.setConfig(config) Configure multiple options at once ForAllConfig (designated initializers)

Macros

Assertion Macros

Macro Type Description
PROP_ASSERT_EQ(A, B) Fatal Assert equality
PROP_ASSERT_NE(A, B) Fatal Assert not equal
PROP_ASSERT_LT(A, B) Fatal Assert less than
PROP_ASSERT_LE(A, B) Fatal Assert less than or equal
PROP_ASSERT_GT(A, B) Fatal Assert greater than
PROP_ASSERT_GE(A, B) Fatal Assert greater than or equal
PROP_EXPECT_EQ(A, B) Non-fatal Expect equality (continues on failure)
PROP_EXPECT_NE(A, B) Non-fatal Expect not equal
PROP_EXPECT_LT(A, B) Non-fatal Expect less than
PROP_EXPECT_LE(A, B) Non-fatal Expect less than or equal
PROP_EXPECT_GT(A, B) Non-fatal Expect greater than
PROP_EXPECT_GE(A, B) Non-fatal Expect greater than or equal

Statistics and Tagging Macros

Macro Description
PROP_STAT(expr) Collect statistics about expression values
PROP_TAG(key, value) Categorize test cases with custom labels
PROP_CLASSIFY(cond, key, value) Conditionally tag test cases
PROP_STAT_ASSERT_GE(expr, bound) Assert ratio of expr true ≥ bound (0–1)
PROP_STAT_ASSERT_LE(expr, bound) Assert ratio of expr true ≤ bound (0–1)
PROP_STAT_ASSERT_IN_RANGE(expr, min, max) Assert ratio of expr true in [min, max]

Test Control Macros

Macro Description
PROP_DISCARD() Skip current test iteration (input doesn't meet preconditions)
PROP_SUCCESS() Mark current test iteration as passed and skip remaining checks

Google Test Integration Macros

Macro Description
EXPECT_FOR_ALL(...) Run forAll() with EXPECT_TRUE (non-fatal)
ASSERT_FOR_ALL(...) Run forAll() with ASSERT_TRUE (fatal)
EXPECT_MATRIX(...) Run matrix() with EXPECT_TRUE (non-fatal)
ASSERT_MATRIX(...) Run matrix() with ASSERT_TRUE (fatal)

 


Functions

proptest::property(callable, ...generators)

Creates a Property object from a callable (function, functor, or lambda).

Parameters:

  • callable: A callable that defines the property. Can return bool or void (using assertions).
  • ...generators: Optional generators for property parameters. If not provided, uses default generators (Arbi<T>) for each parameter type.

Returns: Property object

Example:

auto prop = property([](int a, int b) -> bool {
    return a + b == b + a;
});

// With custom generators
auto prop2 = property([](int a, int b) -> bool {
    return a + b == b + a;
}, gen::interval(0, 100), gen::interval(0, 100));

See also: Generators, Arbitrary, Custom Generator

Chaining

proptest::property(), proptest::forAll(), proptest::matrix(), return Property objects. The run methods (.forAll(), .example(), .matrix()) also return Property, enabling fluent chaining. Chaining lets you to test various subdomains for a property in one go:

// Chain run methods
EXPECT_TRUE(property([](int a, int b) { return a + b == b + a; })
    .forAll(gen::interval(0, 10))
    .matrix({1, 2}, {3, 4})
    .example(5, 6));

// Chain free functions
EXPECT_TRUE(forAll([](int x) { return x >= 0; }, gen::interval(0, 100)).example(42));

// Config flows through the chain
prop.setSeed(0).setNumRuns(10).forAll().example(42);

Behavior:

Aspect Description
Immutable Each step returns a copy; the original is unchanged. p1.example(5); p1.example(6); — each call uses the same p1.
Failure propagates Once a step fails, later steps cannot overturn it.
Short-circuiting When a step fails, subsequent steps are skipped (no execution).
Configuration preserved setSeed, setNumRuns, etc. flow through the chain.

proptest::forAll(callable, ...)

Shorthand for property(callable).forAll(). Creates and immediately runs a property test.

Parameters:

  • callable: A callable that defines the property
  • ...: Optional configuration (C++20 designated initializers) and/or generators

Returns: Property - for chaining (e.g. forAll(...).example(42)). Also provides operator bool() for test result.

Example:

// Simple usage
forAll([](int a, int b) -> bool {
    return a + b == b + a;
});

// With configuration
forAll([](int a, int b) -> bool {
    return a + b == b + a;
}, {
    .seed = 12345,
    .numRuns = 500
});

// With generators
forAll([](int a, int b) -> bool {
    return a + b == b + a;
}, gen::interval(0, 100), gen::interval(0, 100));

// Chainable: forAll().example(...)
EXPECT_TRUE(forAll([](int x) -> bool { return x >= 0; }, gen::interval(0, 100)).example(42));

proptest::matrix(callable, ...lists)

Shorthand for property(callable).matrix(...). Creates and immediately runs a matrix test (Cartesian product).

Parameters:

  • callable: A callable that defines the property
  • ...lists: initializer_list for each parameter, representing all values to test

Returns: Property - for chaining (e.g. matrix(...).example(42)).

Example:

matrix([](int a, int b) -> bool {
    return a + b == b + a;
}, {1, 2, 3}, {4, 5, 6});

 


Property Class

The Property class represents a property test with configurable execution options.

Property::forAll(...generators)

Runs the property with randomly generated inputs.

Parameters:

  • ...generators: Optional generators to override or supplement those specified at property creation

Returns: Property copy with accumulated test result (immutable; original unchanged).

Example:

auto prop = property([](int a, int b) -> bool {
    return a + b == b + a;
});

prop.forAll();  // Use default generators
prop.forAll(gen::interval(0, 100), gen::interval(0, 100));  // Override generators

// Chainable: forAll().matrix().example() — returns new Property
EXPECT_TRUE(prop.forAll().matrix({1, 2}, {3, 4}).example(5, 6));

See also: Property::forAll, Configuration

Property::example(...args)

Runs the property once with specific input values.

Parameters:

  • ...args: Arguments matching the property function's parameters

Returns: Property copy with accumulated test result (immutable; original unchanged).

Example:

auto prop = property([](int a, int b) -> bool {
    return a + b == b + a;
});

prop.example(5, 10);
prop.example(INT_MIN, INT_MAX);  // Independent of previous call
EXPECT_TRUE(prop.forAll().example(42));  // Chaining and bool coercion

Property::matrix(...lists)

Runs the property for all combinations of input values (Cartesian product).

Parameters:

  • ...lists: initializer_list for each parameter

Returns: Property copy with accumulated test result (immutable; original unchanged).

Example:

auto prop = property([](int a, int b) -> bool {
    return a + b == b + a;
});

// Tests all 9 combinations: (1,4), (1,5), (1,6), (2,4), (2,5), (2,6), (3,4), (3,5), (3,6)
EXPECT_TRUE(prop.matrix({1, 2, 3}, {4, 5, 6}));

Property::operator bool()

Returns the accumulated test result. Enables EXPECT_TRUE(prop.forAll()) and if (forAll(...)) via implicit conversion. Used on the returned Property from forAll/example/matrix. Failure propagates: once any step fails, later steps cannot overturn it and are skipped (no execution). Configuration preserved: setSeed, setNumRuns, etc. flow through the chain (each step returns a copy that includes the config).

 


Configuration

All configuration methods return a reference to Property, allowing method chaining.

Property::setSeed(seed)

Sets the random seed for test execution. Useful for reproducibility.

Parameters:

  • seed: uint64_t - Random seed value

Returns: Property&

Example:

prop.setSeed(12345).forAll();

You can also use Seed values generated by gen::seed() in outer properties:

forAll([](Seed seed) {
    auto result = property([](int x) {
        PROP_ASSERT_EQ(x, x);
    }).setSeed(seed).forAll();

    PROP_ASSERT(result);
}, gen::seed());
Seed type is a thin wrapper around a uint64_t value which is commonly used as random seeds. Shrinking is skipped for the generated Seed, as 'size' of a random seed does not mean anything. In output, Seed values are shown as Seed(<n>) to make seed-driven runs easier to read.

Note: If no seed is specified, current timestamp in milliseconds is used. You can also set it via environment variable PROPTEST_SEED.

Property::setNumRuns(runs)

Sets the number of test runs to execute.

Parameters:

  • runs: uint32_t - Number of runs (default: 1000)

Returns: Property&

Example:

prop.setNumRuns(500).forAll();

Note: You can set a global default using PropertyBase::setDefaultNumRuns(num).

Property::setMaxDurationMs(duration)

Sets the maximum duration for test execution in milliseconds. Test stops when either the number of runs or duration limit is reached (whichever comes first).

Parameters:

  • duration: uint32_t - Maximum duration in milliseconds

Returns: Property&

Example:

prop.setMaxDurationMs(5000).forAll();  // Run for at most 5 seconds

Property::setOnStartup(callback)

Sets a callback function called before each test run.

Parameters:

  • callback: Function<void()> - Callback function

Returns: Property&

Example:

prop.setOnStartup([]() {
    std::cout << "Starting test run" << std::endl;
}).forAll();

Property::setOnCleanup(callback)

Sets a callback function called after each test run.

Parameters:

  • callback: Function<void()> - Callback function

Returns: Property&

Example:

prop.setOnCleanup([]() {
    std::cout << "Test run complete" << std::endl;
}).forAll();

Property::setConfig(config)

Configures multiple options at once using designated initializers.

Parameters:

  • config: ForAllConfig - Configuration struct with optional fields:
  • .seed: uint64_t
  • .numRuns: uint32_t
  • .maxDurationMs: uint32_t
  • .onStartup: Function<void()>
  • .onCleanup: Function<void()>
  • .shrinkMaxRetries: uint32_t (max retries; total trials = 1 + n; 0 = deterministic)
  • .shrinkTimeoutMs: uint32_t (0 = no limit)
  • .shrinkRetryTimeoutMs: uint32_t (0 = no limit)

Returns: Property&

Example:

prop.setConfig({
    .seed = 12345,
    .numRuns = 1000,
    .maxDurationMs = 5000
}).forAll();

Note: All fields are optional. This is equivalent to chaining individual setters.

Shrinking with Retry (Flaky Tests)

When tests are flaky (e.g., component has random or external factors that can succeed or fail a test), shrinking may need multiple runs per candidate to explore the case more reliably. Use these methods:

Method Description
.setShrinkMaxRetries(retries) Max retries per candidate. Total trials = 1 + retries (e.g. 10 → 11 trials). 0 = deterministic (1 trial only).
.setShrinkTimeoutMs(ms) Total shrink phase timeout in ms. 0 = no limit.
.setShrinkRetryTimeoutMs(ms) Per-candidate timeout in ms. 0 = no limit.

When shrinkMaxRetries > 0, the framework runs an assessment phase on each failure to measure reproduction rate (e.g., reproduction: 5/10 in 0.12s). You can access these stats programmatically:

  • optional<ReproductionStats> getLastReproductionStats() const — Returns stats from the last shrink assessment, or nullopt if no assessment ran (e.g., deterministic shrink, or property passed).
  • setOnReproductionStats(callback) — Callback invoked after each assessment with ReproductionStats.

ReproductionStats fields: numReproduced, totalRuns, elapsedSec, argsAsString.

Example:

auto result = prop.setShrinkMaxRetries(10).forAll(gen);
if (!result) {
    auto stats = result.getLastReproductionStats();
    if (stats) {
        std::cout << "Failure reproduced " << stats->numReproduced << "/" << stats->totalRuns << std::endl;
    }
}

See also: Shrinking

 


Assertion Macros

Assertion macros verify conditions within property functions. Fatal assertions (PROP_ASSERT_*) stop test execution on failure, while non-fatal expectations (PROP_EXPECT_*) continue testing.

Fatal Assertions:

  • PROP_ASSERT(condition) - Assert condition is true
  • PROP_ASSERT_TRUE(condition) - Assert condition is true
  • PROP_ASSERT_FALSE(condition) - Assert condition is false
  • PROP_ASSERT_EQ(A, B) - Assert equality
  • PROP_ASSERT_NE(A, B) - Assert not equal
  • PROP_ASSERT_LT(A, B) - Assert less than
  • PROP_ASSERT_LE(A, B) - Assert less than or equal
  • PROP_ASSERT_GT(A, B) - Assert greater than
  • PROP_ASSERT_GE(A, B) - Assert greater than or equal
  • PROP_ASSERT_STREQ(A, B, N) - Assert string equality (first N characters)

Non-fatal Expectations:

  • PROP_EXPECT(condition) - Expect condition is true
  • PROP_EXPECT_TRUE(condition) - Expect condition is true
  • PROP_EXPECT_FALSE(condition) - Expect condition is false
  • PROP_EXPECT_EQ(A, B) - Expect equality
  • PROP_EXPECT_NE(A, B) - Expect not equal
  • PROP_EXPECT_LT(A, B) - Expect less than
  • PROP_EXPECT_LE(A, B) - Expect less than or equal
  • PROP_EXPECT_GT(A, B) - Expect greater than
  • PROP_EXPECT_GE(A, B) - Expect greater than or equal
  • PROP_EXPECT_STREQ(A, B, N) - Expect string equality (first N characters)

Example:

forAll([](int a, int b) {
    PROP_ASSERT_EQ(a + b, b + a);  // Fatal - stops on failure
    PROP_EXPECT_GE(a + b, a);      // Non-fatal - continues on failure
});

See also: Test Control Macros

 

Statistics and Tagging Macros

PROP_STAT(expression)

Collects statistics about expression values. The expression is evaluated for each test run, and a summary is printed at the end showing the distribution of results.

Example:

forAll([](float f) {
    PROP_STAT(std::isfinite(f));
    PROP_STAT(f > 0);
    PROP_STAT(f < 0);
}, gen::float32(0.05, 0.05, 0.05));

See also: Test Strategies

PROP_TAG(key, value)

Categorizes test cases with custom key-value pairs. Both key and value are expressions that are evaluated.

Example:

forAll([](int x) {
    if (x < 0) {
        PROP_TAG("sign", "negative");
    } else if (x > 0) {
        PROP_TAG("sign", "positive");
    } else {
        PROP_TAG("sign", "zero");
    }
});

PROP_CLASSIFY(condition, key, value)

Convenience macro that conditionally applies a tag. Equivalent to if (condition) PROP_TAG(key, value).

Example:

forAll([](int x, int y) {
    PROP_CLASSIFY(x == y, "relationship", "equal");
    PROP_CLASSIFY(x > y, "relationship", "greater");
    PROP_CLASSIFY(x < y, "relationship", "less");
});

Stat assertion macros

Assert that the ratio of runs where an expression is true falls within bounds. Bounds are ratios in [0, 1]. Assertions are evaluated after the main loop.

Macro Condition
PROP_STAT_ASSERT_GE(expr, bound) ratio ≥ bound
PROP_STAT_ASSERT_LE(expr, bound) ratio ≤ bound
PROP_STAT_ASSERT_IN_RANGE(expr, min, max) min ≤ ratio ≤ max

Failure output: When a stat assertion fails, the message includes the source location (file:line) for easy debugging, e.g.:

Stat assertion failed: PROP_STAT_ASSERT_GE(a > 0, 0.5) failed: ratio 0 < 0.5 (0/1000) (/path/to/test.cpp:42)

Example:

forAll([](int a) {
    PROP_STAT_ASSERT_GE(a > 0, 0.5); // a > 0 case must be greater or equal to 50%
}, gen::interval(1, 100));

forAll([](int a) {
    PROP_STAT_ASSERT_IN_RANGE(a > 0, 0.5, 1.0);  // Ratio must be in [0.5, 1.0]
}, gen::interval(1, 100));

 

Test Control Macros

PROP_DISCARD()

Skips the current test iteration. The iteration doesn't count toward the total number of runs, and the test will generate additional inputs to meet the configured number of successful runs.

Use case: When generated inputs don't meet preconditions for your property test.

Example:

forAll([](int x, int y) {
    if (y == 0) {
        PROP_DISCARD();  // Skip division by zero cases
    }
    int result = x / y;
    PROP_ASSERT(result * y <= x);
});

Note: If too many cases are discarded, consider using gen::filter() at the generator level instead. See Combinators.

PROP_SUCCESS()

Immediately marks the current test iteration as successful and skips any remaining assertions or checks in the property function.

Use case: Early exit for trivial cases that you know will pass, optimizing test execution time.

Example:

forAll([](int x, int y) {
    if (x == 0 || y == 0) {
        PROP_SUCCESS();  // Skip expensive checks for trivial cases
    }
    PROP_ASSERT(complexProperty(x, y));
});

 

Google Test Integration Macros

EXPECT_FOR_ALL(...)

Shorthand for EXPECT_TRUE(proptest::forAll(...)). Non-fatal - continues testing on failure.

Example:

TEST(Arithmetic, Commutativity)
{
    EXPECT_FOR_ALL([](int a, int b) {
        PROP_ASSERT_EQ(a + b, b + a);
    });
}

ASSERT_FOR_ALL(...)

Shorthand for ASSERT_TRUE(proptest::forAll(...)). Fatal - stops test execution on failure.

Example:

TEST(Arithmetic, Commutativity)
{
    ASSERT_FOR_ALL([](int a, int b) {
        PROP_ASSERT_EQ(a + b, b + a);
    });
}

EXPECT_MATRIX(...)

Shorthand for EXPECT_TRUE(proptest::matrix(...)). Takes a callable and initializer_list arguments (same as the matrix free function). Runs the property over the Cartesian product of the given lists. Non-fatal - continues testing on failure.

Example:

TEST(Arithmetic, MatrixExample)
{
    EXPECT_MATRIX([](int a, int b) -> bool {
        return a + b == b + a;
    }, {1, 2, 3}, {4, 5, 6});
}

ASSERT_MATRIX(...)

Shorthand for ASSERT_TRUE(proptest::matrix(...)). Takes a callable and initializer_list arguments (same as the matrix free function). Runs the property over the Cartesian product of the given lists. Fatal - stops test execution on failure.

Example:

TEST(Arithmetic, MatrixExample)
{
    ASSERT_MATRIX([](int a, int b) -> bool {
        return a + b == b + a;
    }, {1, 2, 3}, {4, 5, 6});
}

 


Usage Examples

Basic Property Test

#include "proptest/proptest.hpp"
#include <gtest/gtest.h>

using namespace proptest;

TEST(Arithmetic, AdditionIsCommutative)
{
    forAll([](int a, int b) -> bool {
        return a + b == b + a;
    });
}

Using Assertions

TEST(Arithmetic, AdditionIsCommutativeWithAssertions)
{
    forAll([](int a, int b) {
        PROP_ASSERT_EQ(a + b, b + a);
    });
}

Custom Generators

TEST(Arithmetic, AdditionWithCustomRange)
{
    forAll([](int a, int b) {
        PROP_ASSERT_EQ(a + b, b + a);
    }, gen::interval(0, 100), gen::interval(0, 100));
}

Configuration

TEST(StringUtils, ReverseWithConfiguration)
{
    auto prop = property([](const std::string& original) {
        std::string reversed = reverseString(original);
        std::string reversedTwice = reverseString(reversed);
        PROP_ASSERT_EQ(original, reversedTwice);
    });

    prop.setNumRuns(500)
        .setSeed(12345)
        .setMaxDurationMs(5000)
        .forAll();
}

Batch Configuration

TEST(StringUtils, ReverseWithBatchConfig)
{
    auto prop = property([](const std::string& original) {
        std::string reversed = reverseString(original);
        std::string reversedTwice = reverseString(reversed);
        PROP_ASSERT_EQ(original, reversedTwice);
    });

    prop.setConfig({
        .seed = 12345,
        .numRuns = 500,
        .maxDurationMs = 5000
    }).forAll();
}

Testing Specific Examples

TEST(StringUtils, ReverseEdgeCases)
{
    auto prop = property([](const std::string& s) {
        PROP_ASSERT_EQ(s.length(), reverseString(s).length());
    });

    prop.example("");
    prop.example("a");
    prop.example("hello world");
}

Matrix Testing

TEST(Arithmetic, BoundaryCases)
{
    auto prop = property([](int a, int b) -> bool {
        return a + b == b + a;
    });

    prop.matrix({INT_MIN, 0, INT_MAX}, {INT_MIN, 0, INT_MAX});
}

Statistics Collection

TEST(Statistics, InputDistribution)
{
    forAll([](int value) {
        PROP_STAT(value > 0);
        PROP_STAT(value < 0);
        PROP_STAT(value == 0);
        PROP_TAG("magnitude", value > 100 ? "large" : "small");

        PROP_ASSERT_GE(value * value, 0);
    });
}

Discarding Invalid Inputs

TEST(Division, NonZeroDenominator)
{
    forAll([](int x, int y) {
        if (y == 0) {
            PROP_DISCARD();  // Skip division by zero
        }
        int result = x / y;
        PROP_ASSERT(result * y <= x);
    });
}