Testing in C++ Using Logs

General idea

  • one creates "test logs", that is single log files containing multiple streams that represent a pre-ordered input for the library
  • run these logs through the library code using test programs, that is a program that takes the log as input, feeds it to the library and verifies or visualizes the result.

Creating test logs

using export_to_single_file in export scripts (https://github.com/rock-core/tools-syskit-log/pull/41). E.g.

``` ruby require "syskit/log" require "syskit/log/dsl" extend Syskit::Log::DSL

dataset_select "SOME_DATASET_ID"

Can use the same means of interval selection or sub-sampling than in Jupyter notebooks,

# e.g. # interval_select roby.Seabots.Compositions.task_from_id(20) # interval_sample_every seconds: 1

export_to_single_file \ "sensor_fusion.0.log", pose_estimator_task.pose_samples_port, ais_task.vessel_position_port do |pose, ais| pose.add("pose") # copy the whole stream as a stream named 'pose' # You can transform the data to e.g. correct for faulty logs ais.add("ais_vessel_positions") { |s| s.mmsi = correct_mmsi(s.mssi) } end ```

Then run with ruby

Creating benchmarking / test programs in C++ libraries

The tools/pocolog_cpp package contains a class to streamline processing these log files, SequentialSampleReader

This class adds a dependency on framework packages (rtt and tools/rtt_typelib). Because of this, we recommend you make the benchmark/test programs dependent on tests being enabled, to allow using the library in production by itself.

```xml

```

To create the test program you have to - import types from the typekits that export it on the orogen side with importTypesFrom - declare the streams you are interested in, with add(stream_name, callback) - run

The dispatcher object will call each callback in the order of the samples in the log file, which means essentially in a time-ordered manner.

e.g.

``` cpp using namespace pocolog_cpp;

int main(int argc, char** argv) { if (argc < 2) { std::cerr « "usage: " « argv[0] « " LOGFILE\n"; return 1; } string logfile = argv[1]; SequentialReadDispatcher dispatcher;

/* NOTE: remember to add the corresponding orogen packages as test depend as well */
dispatcher.importTypesFrom("base");
dispatcher.importTypesFrom("ais_base");

DataFusionLibrary fusion;
dispatcher.add<base::samples::RigidBodyState>(
    /** name of the stream, same than during export. Use `pocolog <FILE>` to
     * list streams */
    "pose",
    [&fusion](auto const& value) { fusion.processPose(value); }
);

dispatcher.add<ais_base::VesselPosition>(
    "ais_vessel_positions",
    [&fusion](auto const& value) { fusion.processAISVesselPosition(value); }
);

dispatcher.run(); } ```