> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roboticks.io/llms.txt
> Use this file to discover all available pages before exploring further.

# C++ Reference

> Full reference for roboticks_cpp - ROBOTICKS_CONFIRMS macro, ConfirmsRegistry API, gtest assertion helpers, ament_cmake INTERFACE setup.

# C++ reference

`roboticks_cpp` is a header-only `ament_cmake` `INTERFACE` library. It ships:

* The `ROBOTICKS_CONFIRMS` macro.
* A thread-safe `ConfirmsRegistry`.
* gtest-compatible rclcpp assertion helpers.
* An optional `gtest_main` target that wires the registry dump into the standard gtest exit.

```cpp theme={null}
#include <roboticks_cpp/confirms.hpp>
#include <roboticks_cpp/assertions.hpp>
```

## CMake

The package exports two targets via `ament_cmake`:

| Target                         | Use when                                                  |
| ------------------------------ | --------------------------------------------------------- |
| `roboticks_cpp::roboticks_cpp` | Header-only — you provide your own `gtest_main`           |
| `roboticks_cpp::gtest_main`    | Header + a `main()` that dumps `ConfirmsRegistry` at exit |

```cmake theme={null}
find_package(roboticks_cpp REQUIRED)

# Option A: bring your own main()
ament_add_gtest(my_tests test/my_tests.cpp)
target_link_libraries(my_tests roboticks_cpp::roboticks_cpp)

# Option B: use the bundled main()
ament_add_gtest_executable(my_tests test/my_tests.cpp)
target_link_libraries(my_tests roboticks_cpp::gtest_main)
```

## `ROBOTICKS_CONFIRMS`

```cpp theme={null}
#define ROBOTICKS_CONFIRMS(token, ...) /* ... */
```

| Argument | Description                                                                                |
| -------- | ------------------------------------------------------------------------------------------ |
| `token`  | Identifier matching `SuiteName_TestName` from the surrounding `TEST(...)` / `TEST_F(...)`. |
| `...`    | Comma-separated string literals of requirement IDs.                                        |

The macro expands to a `ConfirmsRegistry::instance().add(...)` call. It must appear **inside** a gtest test body. Place it as the first statement so the registry record is created before any assertion can short-circuit:

```cpp theme={null}
TEST(EmergencyStop, HaltsWithin100ms) {
  ROBOTICKS_CONFIRMS(EmergencyStop_HaltsWithin100ms, "REQ-001", "REQ-014");
  // ... test body
}
```

For typed tests or value-parameterised tests, the token mirrors gtest's full name:

```cpp theme={null}
TEST_P(SpeedFixture, ClampsWithinRange) {
  ROBOTICKS_CONFIRMS(SpeedFixture_ClampsWithinRange, "REQ-042");
  // ...
}
```

The registry stores `(token, [req_ids...], file, line)` — file and line are captured via `__FILE__` and `__LINE__`.

## `ConfirmsRegistry`

```cpp theme={null}
namespace roboticks_cpp {

class ConfirmsRegistry {
 public:
  static ConfirmsRegistry & instance() noexcept;

  void add(std::string token,
           std::vector<std::string> req_ids,
           const char * file,
           int line);

  void clear() noexcept;

  bool dump(const std::filesystem::path & path) const;

  std::size_t size() const noexcept;

 private:
  mutable std::mutex mutex_;
  std::vector<Entry> entries_;
};

} // namespace roboticks_cpp
```

### Methods

| Method                        | Behaviour                                                                                                       |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `instance()`                  | Returns the process-wide singleton. Thread-safe (Meyers singleton, C++11 magic statics).                        |
| `add(token, ids, file, line)` | Appends a record. Acquires the internal `std::mutex`. Idempotent: same token twice unions the requirement sets. |
| `clear()`                     | Empties the registry. Used by long-lived test processes between test sessions.                                  |
| `dump(path)`                  | Writes the registry as JSON to `path`. Returns `false` on I/O error.                                            |
| `size()`                      | Number of distinct tokens recorded.                                                                             |

### Thread safety

All mutating methods are guarded by an internal `std::mutex`. `instance()` is safe under C++11 magic statics. Read methods (`size`, `dump`) take a shared view under the same lock — concurrent dumps and adds serialise but don't deadlock.

### JSON dump shape

```json theme={null}
{
  "roboticks_schema_version": 1,
  "entries": [
    {
      "token": "EmergencyStop_HaltsWithin100ms",
      "req_ids": ["REQ-001", "REQ-014"],
      "file": "test/test_estop.cpp",
      "line": 14
    }
  ]
}
```

Consumed by the [JUnit stitcher](#stitching-into-junit).

## Assertion helpers

Templated free functions in `roboticks_cpp::`:

```cpp theme={null}
template <typename MsgT>
MsgT assert_topic_published(
  rclcpp::Node::SharedPtr node,
  const std::string & topic,
  std::chrono::nanoseconds within,
  std::function<bool(const MsgT &)> predicate = nullptr,
  const rclcpp::QoS & qos = rclcpp::QoS(10));

template <typename SrvT>
typename SrvT::Response::SharedPtr assert_service_response(
  rclcpp::Node::SharedPtr node,
  const std::string & service,
  typename SrvT::Request::SharedPtr request,
  std::chrono::nanoseconds within);

template <typename ActionT>
typename rclcpp_action::ClientGoalHandle<ActionT>::WrappedResult
assert_action_result(
  rclcpp::Node::SharedPtr node,
  const std::string & action,
  typename ActionT::Goal goal,
  std::chrono::nanoseconds within);
```

Failure modes use gtest's `FAIL()` macro so they appear in the standard gtest summary and stop the current test. Timeouts surface as `FAIL() << "timed out waiting for ...";`.

### Example

```cpp theme={null}
TEST(NavStack, PublishesCmdVel) {
  ROBOTICKS_CONFIRMS(NavStack_PublishesCmdVel, "REQ-007");
  rclcpp::init(0, nullptr);
  auto node = rclcpp::Node::make_shared("test_observer");
  auto msg = roboticks_cpp::assert_topic_published<geometry_msgs::msg::Twist>(
    node, "/cmd_vel", std::chrono::seconds(3));
  EXPECT_GT(msg.linear.x, 0.1);
  rclcpp::shutdown();
}
```

## Stitching into JUnit

`ament_cmake_gtest` writes per-test JUnit XML at `test_results/<package>/<test>.gtest.xml`. The Python-side stitcher merges `confirms.json` from the registry dump:

```bash theme={null}
roboticks-stitch-cpp-junit \
  --gtest-xml test_results/my_pkg/test_estop.gtest.xml \
  --confirms test_results/confirms.json \
  --out test_results/my_pkg/test_estop.junit.xml
```

The stitcher matches by `SuiteName.TestName` (gtest format) ↔ `SuiteName_TestName` (registry token). When you use `colcon test --event-handlers roboticks+`, this happens automatically.

<Info>
  **v0.1 is registry-only.** The C++ side records confirms IDs; the stitcher merges them into JUnit. Phase 11 will ship a native JUnit reporter so the macro writes properties directly — wire shape unchanged.
</Info>

## Manual registry dump

If you bring your own `main()`:

```cpp theme={null}
int main(int argc, char ** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  const int rc = RUN_ALL_TESTS();
  roboticks_cpp::ConfirmsRegistry::instance().dump("test_results/confirms.json");
  return rc;
}
```

## Linking with `colcon test`

```bash theme={null}
colcon build --packages-select my_pkg
colcon test --packages-select my_pkg --event-handlers roboticks+
colcon test-result --verbose
```

The `roboticks+` event handler ships in `roboticks_cpp` and:

1. Locates the JUnit XML colcon wrote.
2. Locates the `confirms.json` the test binary dumped.
3. Stitches and writes a side-by-side `*.junit.xml` for upload.

The handler is silent on success and logs a warning if it can't find either file.

## Headers

| Header                           | Provides                                                                    |
| -------------------------------- | --------------------------------------------------------------------------- |
| `<roboticks_cpp/confirms.hpp>`   | `ROBOTICKS_CONFIRMS`, `ConfirmsRegistry`                                    |
| `<roboticks_cpp/assertions.hpp>` | `assert_topic_published`, `assert_service_response`, `assert_action_result` |
| `<roboticks_cpp/version.hpp>`    | `ROBOTICKS_CPP_VERSION_MAJOR/MINOR/PATCH`                                   |

## Next

<CardGroup cols={2}>
  <Card title="Writing tests in C++" icon="code" href="/testing/writing-tests-cpp">
    Tutorial with full examples.
  </Card>

  <Card title="Wire contract" icon="file-code" href="/sdk/wire-contract">
    The schema the stitcher targets.
  </Card>

  <Card title="Pytest plugin" icon="puzzle-piece" href="/sdk/pytest-plugin">
    The Python-side equivalent.
  </Card>

  <Card title="Coverage" icon="percent" href="/testing/coverage">
    gcov/lcov wiring inside colcon.
  </Card>
</CardGroup>
