Testing

Perseid uses two testing frameworks:

boost::ut is used for the unit tests, which construct objects in memory and verify SQL output without connecting to a database.

Catch2 is used for integration tests, which connect to an actual PostgreSQL database and verify end-to-end behavior.

Running the tests

cmake --build build
ctest --test-dir build

ctest runs the unit tests first and then the integration suite. The integration suite requires PostgreSQL running locally.

createdb perseid_test
createdb perseid_test_src

Most suites share the perseid_test database. The functional migration tests use perseid_test_src as its source database and perseid_test as its target. Every database-backed test starts by dropping all user schemas (including the public schema that createdb creates), cascading to the objects they contain, so each test observes an identical, empty database regardless of what earlier runs left behind.

The database names are configurable, so the tests can run against differently named databases. The integration and functional suites read the PERSEID_TEST_DB and PERSEID_TEST_DB_SRC (functional only) environment variables, defaulting to perseid_test and perseid_test_src respectively when unset.

Smoke test: running against alternate databases

To verify that the environment-variable override works properly, you can create two throwaway databases, run the whole suite against them, then drop them:

createdb perseid_alt
createdb perseid_alt_src
PERSEID_TEST_DB=perseid_alt PERSEID_TEST_DB_SRC=perseid_alt_src \
    ctest --test-dir build
dropdb perseid_alt
dropdb perseid_alt_src

The databases need no preparation beyond createdb; the tests reset them on their own.

Unit tests

The unit tests live in src/dbobject and use boost::ut. They are registered with CTest as test_schema, test_column, test_constraint, and test_table.

# Run all unit tests
ctest --test-dir build -R "test_schema|test_column|test_constraint|test_table"

# Run a single unit test
ctest --test-dir build -R test_schema

# Or run a unit test binary directly
./build/src/dbobject/schema_test

Integration tests

The integration tests live in tests/ and use Catch2. They connect to the test database through Rel_db: connection and statement-execution tests verify execute/fetchone/commit/rollback semantics, and table tests create an isolated schema (reldb_test_schema) to exercise table loading and tuple queries end-to-end.

# Ensure the test database exists
createdb perseid_test

# Run all integration tests
ctest --test-dir build -R "_integration"

# Run specific integration suites
ctest --test-dir build -R test_reldb_integration
ctest --test-dir build -R test_schema_integration
ctest --test-dir build -R test_table_integration
ctest --test-dir build -R test_column_integration
ctest --test-dir build -R test_constraint_integration

# Or run binaries directly (with optional filters)
./build/tests/reldb_integration
./build/tests/reldb_integration "commit persists writes"

Functional tests

The functional tests are ports of Pyrseas’ functional test suite. The first one, test_filmversions, executes SQL scripts against a source database to build successive schema versions (0.1, 0.2, 0.3), mirrors each version into a target database by applying the differences between the two YAML descriptions, and after each step—and after reverting to each earlier version—verifies that the two databases are identical by diffing pg_dump output and YAML files. It uses the Db_migrate_testcase base class from tests/testutils.cppm.

# Run the functional test
ctest --test-dir build -R test_filmversions

# Or run the binary directly (optionally with Catch2 tags or filters)
./build/tests/test_filmversions
./build/tests/test_filmversions "[film]"

In addition to both test databases, the test requires pg_dump and diff to be available on PATH.

The SQL scripts live in tests/scripts/, separate from the test sources. Temporary files (dumps, YAML and generated SQL) are written to a perseid_test directory under the system temporary directory. The directory is emptied at the start of each test run.

The suites share the same databases and temporary files, so test executables should not be run concurrently; CTest runs them serially by default. Note also that test_filmversions does not match the _integration pattern, so it is not included in ctest -R "_integration".

Test organization

File

Framework

Coverage

src/dbobject/schema_test.cpp

boost::ut

Schema create/drop/diff (unit)

src/dbobject/column_test.cpp

boost::ut

Column add/alter/drop (unit)

src/dbobject/constraint_test.cpp

boost::ut

FK, PK, check, unique constraints (unit)

src/dbobject/table_test.cpp

boost::ut

Table create/drop/diff, topo sort (unit)

tests/test_schema.cpp

Catch2

Schema integration against live DB

tests/test_table.cpp

Catch2

Table integration against live DB

tests/test_column.cpp

Catch2

Column integration against live DB

tests/test_constraint.cpp

Catch2

Constraint integration against live DB

tests/test_reldb.cpp

Catch2

Rel_db integration (connection/execute/fetch/txn)

tests/test_filmversions.cpp

Catch2

Functional test: film schema version migration and reversion