#pragma once #include #include #include #include #include "McZapkie/MOVER.h" #include "figures.h" #include "invariants.h" namespace test { // one value of the vehicle a trace follows struct channel { std::string name; std::function value; }; // sets of channels for the usual subjects of a test, which can be put together namespace channels { std::vector motion(); // speed, distance, forces std::vector traction(); // controllers, current, voltage, engine std::vector brakes(); // pressures of the brake pipe, cylinders and reservoirs std::vector air(); // compressor and main reservoir std::vector handles(); // the driver's brake handle and the local brake handle, with their sounds std::vector doors(); // both sides' doors and steps, their permits and the lock std::vector parameters(); // what the vehicle definition sets, as the loader read it std::vector operator+(std::vector Left, std::vector const &Right); } // namespace channels // characterisation of the simulation: the values of the channels over a run of a vehicle, compared with the // ones the code gave when the trace got recorded, in tests/unit/data/golden/.csv (spaces as underscores). a difference fails the // test, naming the channel and the time it shows up first. the samples are tens of megabytes and only mean // something against the code before a change, so they stay out of the repository: running the tests with // EU07_UNIT_TESTS_UPDATE_GOLDEN=1 records them on the code before the change, and after it they're compared. // a trace with nothing recorded checks only the invariants and its test's own CHECKs, as the CI does. // // values are compared within a relative tolerance of 1e-9 (the CI builds with GCC and glibc, whose maths // functions can differ from MSVC's in the last bits), or exactly with EU07_UNIT_TESTS_GOLDEN_EXACT=1, which is the check to // run for a change which shouldn't alter anything at all, and which fails a trace with nothing recorded. // // besides the samples, a trace records the key figures of the run (figures.h) in .figures, the few // lines a person reads of what a change altered, and checks the invariants (invariants.h) on every step // // test::trace trace{"eu07 notch up", test::channels::motion() + test::channels::traction()}; // eu07.record(trace); // ... run the vehicle ... // trace.check(); class trace { public: // samples every Every-th step of the vehicle: 100, a second at the usual step, is plenty for a run of minutes, // as a difference stays once the simulation has taken it in // Figures: whether to keep the key figures, which a trace sampled by hand, at times of its own, has no use for trace(std::string Name, std::vector Channels, int Every = 10, bool Figures = true); // called by the vehicle after every step void sample(double Time, TMoverParameters const &Vehicle); // adds an event of the test to the trace, so a difference can be told apart from the moment of the action void mark(std::string const &Event); // compares the trace and its key figures (figures.h) with the recorded ones, or records them, and reports the // invariants broken void check() const; // the invariants broken in the trace (see invariants.h), the first time each, excused or not std::vector const &violations() const { return m_violations; } private: void check_figures(std::filesystem::path const &Path, bool Exact) const; // writes the samples and the key figures, as recorded on the code before a change void record(std::filesystem::path const &Path, std::filesystem::path const &FiguresPath, std::string const &Header) const; // compares the samples with the recorded ones void check_samples(std::filesystem::path const &path, std::string const &header, bool exact) const; std::string m_name; std::vector m_channels; int m_every; long m_step{0}; std::vector m_rows; // formatted, as in the file std::string m_event; // marked since the last row std::string m_last_event; // the last one marked, for the invariants broken after it snapshot m_before{}; bool m_sampled{false}; std::vector m_broken; // the names of the invariants broken so far std::vector m_violations; bool m_keep_figures; figures m_figures; }; } // namespace test