Skip to content

Latest commit

 

History

History

cpp

README.md

Important

We're excited you're checking out Hegel! Hegel is in beta, and we'd love for you to try it and report any feedback.

As part of our beta, we may make breaking changes if it makes Hegel a better property-based testing library. If that instability bothers you, please check back in a few months for a stable release!

See https://hegel.dev/compatibility for more details.

Hegel for C++

Hegel is a property-based testing library for C++. Hegel is based on Hypothesis, using the Hegel protocol.

Installation

Hegel requires C++20.

To install with CMake, add this to your CMakeLists.txt (CMake 3.14+ required):

include(FetchContent)
FetchContent_Declare(
    hegel
    GIT_REPOSITORY https://github.com/hegeldev/hegel.git
    GIT_TAG frontends/cpp/0.13.1
    SOURCE_SUBDIR frontends/cpp
)
FetchContent_MakeAvailable(hegel)

target_link_libraries(your_target PRIVATE hegel)

The library lives in the hegeldev/hegel repository next to libhegel, Hegel's native engine, which the build compiles with cargo (a Rust toolchain from rustup) and links. To link a libhegel built elsewhere instead, so that no Rust toolchain is needed, pass -DHEGEL_LIBHEGEL_LIBRARY=/path/to/libhegel_c.<ext>. See https://hegel.dev/reference/installation for details.

Quickstart

Here's a quick example of how to write a Hegel test:

#include <hegel/hegel.h>
#include <algorithm>
#include <stdexcept>
#include <vector>

namespace gs = hegel::generators;

std::vector<int> my_sort(std::vector<int> ls) {
    std::sort(ls.begin(), ls.end());
    ls.erase(std::unique(ls.begin(), ls.end()), ls.end());
    return ls;
}

HEGEL_TEST(sort_agrees_with_std_sort)(hegel::TestCase& tc) {
    auto vec1 = tc.draw("vec1", gs::vectors(gs::integers<int>()));
    auto vec2 = my_sort(vec1);
    std::sort(vec1.begin(), vec1.end());
    if (vec1 != vec2) {
        throw std::runtime_error("sort mismatch");
    }
}

int main() {
    sort_agrees_with_std_sort();
    return 0;
}

HEGEL_TEST defines the test as a plain function you can invoke from main() or from any test framework, and names the test in Hegel's example database so failures found in one run are replayed first in the next. (You can also call hegel::test(callback, settings) directly.)

This test will fail! Hegel will produce a minimal failing test case for us:

--- Failure: sort_agrees_with_std_sort (sort_test.cpp:9) ----------------
Falsified after 8 test cases (0 discarded):

  auto vec1 = std::vector<int>{0, 0};

Exception: std::runtime_error: sort mismatch
rerun with: HEGEL_REPRODUCE_FAILURE(sort_agrees_with_std_sort, "AXicY2VgYGBkZOBiZEBhMAAAAd8AIQ==")

The report names the test and its source line, says how many cases it took to find the failure, and shows the minimal example.

Each draw is replayed and printed as a C++ declaration. tc.draw("vec1", gen) names the draw with vec1 as above. An unnamed tc.draw(gen) prints (auto draw_1 = ...;) instead.

The last line replays this exact failure. Put it above the test to rerun the counterexample instead of generating new cases:

HEGEL_REPRODUCE_FAILURE(sort_agrees_with_std_sort, "AXicY2VgYGBkZOBiZEBhMAAAAd8AIQ==")
HEGEL_TEST(sort_agrees_with_std_sort)(hegel::TestCase& tc) {
    // ...
}