Skip to main content

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

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.
#include <roboticks_cpp/confirms.hpp>
#include <roboticks_cpp/assertions.hpp>

CMake

The package exports two targets via ament_cmake:
TargetUse when
roboticks_cpp::roboticks_cppHeader-only — you provide your own gtest_main
roboticks_cpp::gtest_mainHeader + a main() that dumps ConfirmsRegistry at exit
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

#define ROBOTICKS_CONFIRMS(token, ...) /* ... */
ArgumentDescription
tokenIdentifier 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:
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:
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

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

MethodBehaviour
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

{
  "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.

Assertion helpers

Templated free functions in roboticks_cpp:::
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

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:
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.
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.

Manual registry dump

If you bring your own main():
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

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

HeaderProvides
<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

Writing tests in C++

Tutorial with full examples.

Wire contract

The schema the stitcher targets.

Pytest plugin

The Python-side equivalent.

Coverage

gcov/lcov wiring inside colcon.