Running the unit tests locally

EBGeometry ships a Catch2 v3 unit test suite under Tests/. Catch2 is fetched automatically at CMake configure time via FetchContent — no manual installation is needed.

Quick start with CMake presets

The repository ships CMakePresets.json (requires CMake 3.22+) with pre-configured debug and release profiles. The debug preset is the recommended starting point: it enables assertions, disables SIMD (cleaner debugger output), and turns on both the test suite and the examples.

# 1. Configure (Catch2 is fetched automatically on the first run)
cmake --preset debug

# 2. Build
cmake --build --preset debug --parallel $(nproc)

# 3a. Run unit tests only  (< 1 s)
ctest --preset debug

# 3b. Run example programs (allow several minutes in Debug mode)
ctest --preset examples

A successful unit-test run looks like:

100% tests passed, 0 tests failed out of 220
Label Time Summary:
unit    =   1.43 sec*proc (220 tests)

Most test files are written with Catch2’s TEMPLATE_TEST_CASE so they can run under both float and double, but locally, by default, only double runs (fast iteration, matching whatever the CMake preset otherwise builds) – the count above is double-only. CI additionally configures with -DEBGEOMETRY_TEST_BOTH_PRECISIONS=ON to run the full suite under both precisions (422 tests). To do the same locally:

cmake --preset debug -DEBGEOMETRY_TEST_BOTH_PRECISIONS=ON
cmake --build --preset debug --parallel $(nproc)
ctest --preset debug

Running with sanitizers (AddressSanitizer + UBSan)

cmake --preset debug-san
cmake --build --preset debug-san --parallel $(nproc)
ctest --preset debug-san

Preset reference

Preset

Build type

Assertions

SIMD

Tests / Examples

debug

Debug

ON

none

Unit tests + examples (labelled separately)

debug-san

Debug

ON

none

Unit tests + examples with ASan/UBSan

release

Release

OFF

avx

OFF (library only)

release-test

Release

OFF

avx

Unit tests + examples

Manual CMake options (without presets)

If you cannot use presets (CMake < 3.22 or an IDE that does not support them), pass the variables directly:

cmake -B build \
      -DCMAKE_BUILD_TYPE=Debug \
      -DEBGEOMETRY_BUILD_TESTS=ON \
      -DEBGEOMETRY_ENABLE_ASSERTIONS=ON \
      -DEBGEOMETRY_SIMD=none
cmake --build build --parallel $(nproc)
cd build && ctest -L unit --output-on-failure

CMake options

Option

Default

Effect

EBGEOMETRY_BUILD_TESTS

OFF

Fetch Catch2 and build the Tests/ suite.

EBGEOMETRY_BUILD_EXAMPLES

OFF

Build the standalone examples under Examples/.

EBGEOMETRY_ENABLE_ASSERTIONS

OFF

Compile with EBGEOMETRY_EXPECT() guards active. Strongly recommended when running tests so that precondition violations abort with a clear message rather than silently producing wrong results.

EBGEOMETRY_ENABLE_SANITIZERS

OFF

Add -fsanitize=address,undefined to tests and examples.

EBGEOMETRY_SIMD

avx

avx512 enables -mavx512f -mavx2 -mavx -mfma -msse4.1; avx enables -mavx -mfma -msse4.1; sse41 enables -msse4.1; none uses the scalar fallback.

Selecting individual tests

Catch2 test cases are registered with CTest so you can filter by name or tag:

# Run only the Vec tests
ctest --output-on-failure -R "Vec3T"

# Run only the SFC tests
ctest --output-on-failure -R "SFC"

# Run a single test binary directly (all Catch2 options available).
# Each preset gets its own build directory (build/<preset-name>/...); adjust
# the path if you configured with a preset instead of the manual example above.
./Tests/TestVec --list-tests
./Tests/TestAnalyticSDF "[SphereSDF]"

Test coverage

Test binary

What is covered

TestVec

Vec2T and Vec3T: construction, arithmetic, dot/cross products, length, component-wise min/max, minDir/maxDir, lexicographic ordering, scalar-over-vector operator/.

TestBoundingVolumes

AABBT and SphereT: construction from corners and point clouds, volume, surface area, point distance, intersection predicate, overlapping volume.

TestAnalyticSDF

SphereSDF, BoxSDF, PlaneSDF, CylinderSDF, TorusSDF; CSG Union(), Intersection(), Complement().

TestDCEL

DCEL topology of a hardcoded tetrahedron (face/vertex/edge counts, half-edge pairing, unit normals, sanityCheck); signed-distance correctness for FlatMeshSDF; agreement between FlatMeshSDF (brute-force) and TriMeshSDF (SIMD BVH).

TestSFC

Morton and Nested space-filling curves: encode/decode roundtrip across the full valid coordinate range, monotonicity along one axis, injectivity, ValidSpan boundary regression.

TestTriangle

Triangle: face normal from vertex ordering, and signed-distance correctness for points closest to the face interior, an edge, and a vertex.

TestSTL

STL: construction, copy/move semantics; Parser::readSTL reading raw vertex/facet data from a test file; round-trip through convertToDCEL into a valid, watertight mesh.

TestPLY

PLY: construction, copy/move semantics; named vertex/face property storage and retrieval (including the out-of-range-name error path); round-trip through convertToDCEL.

TestOBJ

OBJ: construction, copy/move semantics; round-trip through convertToDCEL into a valid, watertight mesh.

TestVTK

VTK: construction, copy/move semantics; named point-data/cell-data scalar array storage and retrieval (including the out-of-range-name error path); round-trip through convertToDCEL.

TestBVH

A regular dodecahedron (20 vertices, 36 triangulated faces), read from disk in all four supported formats, used to verify: identical topology/geometry across formats; BVH::TreeBVH/BVH::PackedBVH signedDistance agreement with a brute-force scan across every partitioning strategy (top-down with the default and SAH partitioners, bottom-up with Morton and Nested space-filling curves); MeshSDF and TriMeshSDF agreement with FlatMeshSDF for every BVH::Build strategy; and MeshSDF::getClosestFaces() ordering.

TestCSG

SmoothMin()/SmoothMax()/ExpMin() blending primitives; sharp and smooth UnionIF/IntersectionIF/DifferenceIF (and their BVH-accelerated counterparts); FiniteRepetitionIF tiling and boundary clamping.

TestTransform

ComplementIF, TranslateIF, RotateIF, ScaleIF, OffsetIF, AnnularIF, BlurIF, MollifyIF, ElongateIF, ReflectIF: each transform’s free-function/class-constructor equivalence, and correctness against a hand-computable expected value.

TestOctree

Octree::Node: depth-first/breadth-first construction, traversal pruning and custom sort order; ImplicitFunction::approximateBoundingVolumeOctree() correctness (tightening bound with depth, degenerate/non-intersecting input fallback).

TestPolygon2D

Polygon2D: winding-number/crossing-number/subtended-angle containment algorithms, agreement between them on convex and concave (notched) polygons, and on a non-axis-aligned embedding plane.

TestTriangleSoA

TriangleSoAT: signedDistance agreement with the minimum over the individual packed Triangle instances (including padding when fewer than W triangles are packed), and bounding-volume construction from the packed data.

TestSimpleTimer

SimpleTimer: near-zero elapsed time on construction, measured duration against a requested sleep, restart-on-start() semantics, and relative ordering of two different sleep durations.

Tests/InstantiateAll.cpp is not itself a test binary and does not appear in the table above: it is a compile-only target (built by cmake --build, but never run by ctest) that explicitly instantiates every public class template for both float and double. Its purpose is to give clang-tidy and the project’s warning set (in particular -Wdouble-promotion) something to analyse for both precisions, regardless of what the Catch2 tests above happen to exercise – float support would otherwise only be checked by whichever public classes a test happens to instantiate. See Contribution guidelines for when to add a new class to it.

Note

All of the mesh- and BVH-related tests above rely on the sign convention (negative inside, positive outside) and face-normal computation described in Geometry representations and Half-edge meshes (DCEL) – see those pages rather than this one for the convention itself.