Write a Component Test

Turn one public compatibility claim into focused, discoverable, source-owned evidence.

ContributorGoogleTestSerial commands

Locate the owning test tree

Every physical component declares its production sources and any test sources through current CMake registration. Place behavior tests under the owning module’s tests/ tree and include public headers the same way a consumer does.

modules/io-hashing/
├── include/System/IO/Hashing/...
├── CMakeLists.txt
└── tests/System/IO/HashingTests.cpp

Do not add a source to a central hand-maintained test list. The component registration collects its test tree and gives it the owning target plus declared test dependencies.

Write one observable contract

#include <gtest/gtest.h>
#include <cstdint>
#include <vector>

#include "System/IO/Hashing/Crc32.hpp"

TEST(HashingDocumentationExample, StandardVector) {
    const std::vector<std::uint8_t> input{
        '1', '2', '3', '4', '5', '6', '7', '8', '9'};

    EXPECT_EQ(
        System::IO::Hashing::Crc32::HashToUInt32(
            input.data(), static_cast<std::int32_t>(input.size())),
        0xCBF43926u);
}

Name the behavior rather than the implementation strategy. The standard vector proves a public result; a test named UsesPolynomialTable would unnecessarily freeze a private technique.

Cover boundary and failure behavior

A useful compatibility slice normally needs more than a happy path:

  • empty, one-element, minimum, and maximum valid input;
  • invalid values and the exact public exception family/parameter name when contractual;
  • copy, move, close/dispose, repeated-call, and post-failure state;
  • overlap, aliasing, mutation, and invalidation for contiguous storage;
  • callback reentrancy, removal, exceptions, and concurrent use for event/threaded APIs;
  • platform-specific branches with honest skips rather than unconditional green assertions.

Configure the narrow component

cmake -S /path/to/sharp-runtime -B build-io-hashing \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DSHARP_RUNTIME_COMPONENTS=IO.Hashing \
  -DSHARP_RUNTIME_BUILD_TESTS=ON

Use the selected pinned checkout, not whichever branch happens to be current elsewhere. A component build tests its declared closure and catches dependency leaks earlier than an All build.

Build and run serially when memory is constrained

cmake --build build-io-hashing \
  --target SharpRuntimeTests_IO_Hashing \
  --parallel 1

./build-io-hashing/SharpRuntimeTests_IO_Hashing \
  --gtest_filter=HashingDocumentationExample.StandardVector

ctest --test-dir build-io-hashing \
  --output-on-failure \
  -R '^IO\.Hashing::HashingDocumentationExample\.StandardVector$'

CMake converts dots in a physical component name to underscores for the executable target. GoogleTest discovery prefixes CTest names with the original dotted component. Use ctest -N to inspect actual discovery rather than guessing a count from TEST macros.

Distinguish discovery from execution

EvidenceClaim it supports
ctest -N after built discoveryCases currently discovered in that build tree.
Focused executable/filter resultOne suite/case actually ran in this environment.
Complete CTest gate resultAll discovered cases were attempted, with measured pass/skip/fail totals.
Source test file existsOnly that source coverage was authored—not that discovery or execution succeeded.

Add special fixtures where positive tests cannot prove the rule

A normal unit test cannot prove that a private header is unreachable, a forbidden conversion fails, or a template constraint rejects a type. Use a negative consumer fixture for those compile-time contracts. Use the module-boundary validator for dependency visibility. Use an integration test only when the behavior genuinely crosses component boundaries.

Finish the contributor loop

  1. Run the focused test and its neighboring suite.
  2. Run the owning component target from a clean enough build to exercise discovery.
  3. Run boundary and catalogue validation.
  4. Run the full gate when the environment and resource budget allow it.
  5. Update API deviations, limitations, tutorials, and generated catalogue inputs when public behavior changed.
  6. Record measured results with SHA, toolchain, platform, date, and exact terminology.