Newer
Older

Sylvester Joosten
committed
#ifndef BENCHMARK_LOADED
#define BENCHMARK_LOADED
#include "exception.hh"
#include <fmt/core.h>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
// Bookkeeping of test data to store data of one or more tests in a json file to
// facilitate future accounting.
//
// Usage Example 1 (single test):
// ==============================
// 1. define our test

Sylvester Joosten
committed
// eic::util::Test test1{

Sylvester Joosten
committed
// {{"name", "example_test"},
// {"title", "Example Test"},
// {"description", "This is an example of a test definition"},
// {"quantity", "efficiency"},
// {"target", "1"}}};
// 2. set pass/fail/error status and return value (in this case .99)
// test1.pass(0.99)
// 3. write our test data to a json file
// eic::util::write_test(test1, "test1.json");

Sylvester Joosten
committed
//
// Usage Example 2 (multiple tests):
// =================================
// 1. define our tests

Sylvester Joosten
committed
// eic::util::Test test1{

Sylvester Joosten
committed
// {{"name", "example_test"},
// {"title", "Example Test"},
// {"description", "This is an example of a test definition"},
// {"quantity", "efficiency"},
// {"target", "1"}}};

Sylvester Joosten
committed
// eic::util::Test test2{

Sylvester Joosten
committed
// {{"name", "another_test"},
// {"title", "Another example Test"},
// {"description", "This is a second example of a test definition"},
// {"quantity", "resolution"},
// {"target", "3."}}};
// 2. set pass/fail/error status and return value (in this case .99)
// test1.fail(10)
// 3. write our test data to a json file
// eic::util::write_test({test1, test2}, "test.json");

Sylvester Joosten
committed
// Namespace for utility scripts, FIXME this should be part of an independent
// library

Sylvester Joosten
committed

Sylvester Joosten
committed
struct TestDefinitionError : exception {
TestDefinitionError(std::string_view msg)

Sylvester Joosten
committed
: exception(msg, "test_definition_error") {}
};
// Wrapper for our test data json, with three methods to set the status
// after test completion (to pass, fail or error). The default value
// is error.
// The following fields should be defined in the definitions json
// for the test to make sense:
// - name: unique identifier for this test
// - title: Slightly more verbose identifier for this test
// - description: Concise description of what is tested
// - quantity: What quantity is tested? Unites of value/target
// - target: Target value of <quantity> that we want to reach
// - value: Actual value of <quantity>
// - weight: Weight for this test (this is defaulted to 1.0 if not specified)
// - result: pass/fail/error

Sylvester Joosten
committed
struct Test {

Sylvester Joosten
committed
test(nlohmann::json definition) : json{std::move(definition)} {
// initialize with error (as we don't have a value yet)
error();
// Check that all required fields are present
for (const auto& field : {"name", "title", "description", "quantity",
"target", "value", "result"}) {

Sylvester Joosten
committed
if (json.find(field) == json.end()) {

Sylvester Joosten
committed
throw TestDefinitionError{

Sylvester Joosten
committed
fmt::format("Error in test definition: field '{}' missing", field)};
}
}
// Default "weight" to 1 if not set
if (json.find("weight") == json.end()) {
json["weight"] = 1.0;
}

Sylvester Joosten
committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
}
// Set this test to pass/fail/error
void pass(double value) { update_result("pass", value); }
void fail(double value) { update_result("fail", value); }
void error(double value = 0) { update_result("error", value); }
nlohmann::json json;
private:
void update_result(std::string_view status, double value) {
json["result"] = status;
json["value"] = value;
}
};
void write_test(const std::vector<test>& data, const std::string& fname) {
nlohmann::json test;
for (auto& entry : data) {
test.push_back(entry.json);
}
std::cout << fmt::format("Writing test data to {}\n", fname);
std::ofstream output_file(fname);
output_file << std::setw(4) << test << "\n";
}
void write_test(const test& data, const std::string& fname) {
std::vector<test> vtd{data};
write_test(vtd, fname);
}