|
11 | 11 |
|
12 | 12 | #include "Framework/ConfigParamsHelper.h" |
13 | 13 | #include "Framework/ConfigParamSpec.h" |
| 14 | +#include "Framework/BoostOptionsRetriever.h" |
| 15 | +#include "Framework/ConfigParamRegistry.h" |
| 16 | +#include "Framework/ConfigParamStore.h" |
| 17 | +#include "Framework/DataProcessorSpec.h" |
14 | 18 | #include <boost/program_options.hpp> |
15 | 19 | #include <boost/program_options/parsers.hpp> |
16 | 20 | #include <catch_amalgamated.hpp> |
| 21 | +#include <sstream> |
17 | 22 | #include <vector> |
18 | 23 |
|
19 | 24 | using namespace o2::framework; |
@@ -70,3 +75,133 @@ TEST_CASE("TrivialBoostOptionsRetrieverTest") |
70 | 75 | REQUIRE(vm["someFloat"].as<float>() == 0.5); |
71 | 76 | REQUIRE(vm["someDouble"].as<double>() == 0.5); |
72 | 77 | } |
| 78 | + |
| 79 | +namespace |
| 80 | +{ |
| 81 | +constexpr char const* fullLabeledJSON = R"({"labels_rows":["a","b"],"labels_cols":["x","y"],"values":[[5,6],[7,8]]})"; |
| 82 | + |
| 83 | +LabeledArray<int> defaultLabeledArray() |
| 84 | +{ |
| 85 | + int m[2][2] = {{1, 2}, {3, 4}}; |
| 86 | + return LabeledArray<int>{&m[0][0], 2, 2, {"r1", "r2"}, {"c1", "c2"}}; |
| 87 | +} |
| 88 | + |
| 89 | +std::unique_ptr<ConfigParamRegistry> registryFromCommandLine(std::vector<ConfigParamSpec> const& specs, std::vector<char const*> args) |
| 90 | +{ |
| 91 | + args.insert(args.begin(), "test"); |
| 92 | + std::vector<std::unique_ptr<ParamRetriever>> retrievers; |
| 93 | + retrievers.emplace_back(std::make_unique<BoostOptionsRetriever>(true, args.size(), const_cast<char**>(args.data()))); |
| 94 | + auto store = std::make_unique<ConfigParamStore>(specs, std::move(retrievers)); |
| 95 | + store->preload(); |
| 96 | + store->activate(); |
| 97 | + return std::make_unique<ConfigParamRegistry>(std::move(store)); |
| 98 | +} |
| 99 | +} // namespace |
| 100 | + |
| 101 | +TEST_CASE("LabeledArrayBoostOptionsTest") |
| 102 | +{ |
| 103 | + namespace bpo = boost::program_options; |
| 104 | + auto specs = std::vector<ConfigParamSpec>{ |
| 105 | + {"someLabeledArray", VariantType::LabeledArrayInt, defaultLabeledArray(), {"some labeled array option"}}}; |
| 106 | + |
| 107 | + // the option is registered as a string holding the JSON representation |
| 108 | + bpo::options_description opts; |
| 109 | + ConfigParamsHelper::populateBoostProgramOptions(opts, specs); |
| 110 | + const char* args[] = {"test", "--someLabeledArray", fullLabeledJSON}; |
| 111 | + bpo::variables_map vm; |
| 112 | + bpo::store(parse_command_line(sizeof(args) / sizeof(char*), args, opts), vm); |
| 113 | + bpo::notify(vm); |
| 114 | + REQUIRE(vm["someLabeledArray"].as<std::string>() == fullLabeledJSON); |
| 115 | + |
| 116 | + // the default is the JSON representation of the default value |
| 117 | + bpo::variables_map vmDefault; |
| 118 | + const char* noArgs[] = {"test"}; |
| 119 | + bpo::store(parse_command_line(1, noArgs, opts), vmDefault); |
| 120 | + REQUIRE(vmDefault["someLabeledArray"].as<std::string>() == specs[0].defaultValue.asString()); |
| 121 | +} |
| 122 | + |
| 123 | +TEST_CASE("LabeledArrayBoostOptionsRetrieverTest") |
| 124 | +{ |
| 125 | + auto specs = std::vector<ConfigParamSpec>{ |
| 126 | + {"someLabeledArray", VariantType::LabeledArrayInt, defaultLabeledArray(), {"some labeled array option"}}}; |
| 127 | + |
| 128 | + // full JSON on the command line, its labels are kept |
| 129 | + auto registry = registryFromCommandLine(specs, {"--someLabeledArray", fullLabeledJSON}); |
| 130 | + auto la = registry->get<LabeledArray<int>>("someLabeledArray"); |
| 131 | + REQUIRE(la.getLabelsRows() == std::vector<std::string>{"a", "b"}); |
| 132 | + REQUIRE(la.getLabelsCols() == std::vector<std::string>{"x", "y"}); |
| 133 | + REQUIRE(la.get("b", "y") == 8); |
| 134 | + |
| 135 | + // absent from the command line: the default value |
| 136 | + registry = registryFromCommandLine(specs, {}); |
| 137 | + la = registry->get<LabeledArray<int>>("someLabeledArray"); |
| 138 | + REQUIRE(la.get("r2", "c2") == 4); |
| 139 | + |
| 140 | + // only values on the command line: the default labels are used |
| 141 | + registry = registryFromCommandLine(specs, {"--someLabeledArray", R"({"values":[[5,6],[7,8]]})"}); |
| 142 | + la = registry->get<LabeledArray<int>>("someLabeledArray"); |
| 143 | + REQUIRE(la.getLabelsRows() == std::vector<std::string>{"r1", "r2"}); |
| 144 | + REQUIRE(la.getLabelsCols() == std::vector<std::string>{"c1", "c2"}); |
| 145 | + REQUIRE(la.get("r2", "c1") == 7); |
| 146 | + |
| 147 | + // values which do not match the default labels |
| 148 | + REQUIRE_THROWS(registryFromCommandLine(specs, {"--someLabeledArray", R"({"values":[[5,6,7]]})"})); |
| 149 | +} |
| 150 | + |
| 151 | +TEST_CASE("DefaultValueForHelpTest") |
| 152 | +{ |
| 153 | + auto const max = ConfigParamsHelper::MaxHelpDefaultLength; |
| 154 | + REQUIRE(ConfigParamsHelper::defaultValueForHelp("") == ""); |
| 155 | + REQUIRE(ConfigParamsHelper::defaultValueForHelp("short") == "short"); |
| 156 | + std::string atLimit(max, 'x'); |
| 157 | + REQUIRE(ConfigParamsHelper::defaultValueForHelp(atLimit) == atLimit); |
| 158 | + |
| 159 | + std::string longValue = std::string("BEGIN") + std::string(100, '-') + "END"; |
| 160 | + auto shown = ConfigParamsHelper::defaultValueForHelp(longValue); |
| 161 | + REQUIRE(shown.size() == max); |
| 162 | + REQUIRE(shown.starts_with("BEGIN")); |
| 163 | + REQUIRE(shown.ends_with("END")); |
| 164 | + REQUIRE(shown.find("...") != std::string::npos); |
| 165 | + REQUIRE(ConfigParamsHelper::defaultValueForHelp(std::string(max + 1, 'x')).size() == max); |
| 166 | +} |
| 167 | + |
| 168 | +TEST_CASE("LongDefaultInHelpTest") |
| 169 | +{ |
| 170 | + namespace bpo = boost::program_options; |
| 171 | + std::vector<int> values(30, 12345); |
| 172 | + std::vector<std::string> rows{"row"}; |
| 173 | + std::vector<std::string> cols; |
| 174 | + for (auto i = 0U; i < values.size(); ++i) { |
| 175 | + cols.push_back("column" + std::to_string(i)); |
| 176 | + } |
| 177 | + LabeledArray<int> la{values.data(), 1, static_cast<uint32_t>(values.size()), rows, cols}; |
| 178 | + auto workflowOptions = std::vector<ConfigParamSpec>{ |
| 179 | + {"longLabeledArray", VariantType::LabeledArrayInt, la, {"a labeled array option with a long default"}}}; |
| 180 | + auto full = workflowOptions[0].defaultValue.asString(); |
| 181 | + REQUIRE(full.size() > ConfigParamsHelper::MaxHelpDefaultLength); |
| 182 | + |
| 183 | + // the help shows the abbreviated default only |
| 184 | + auto description = ConfigParamsHelper::prepareOptionDescriptions(std::vector<DataProcessorSpec>{}, workflowOptions); |
| 185 | + std::stringstream help; |
| 186 | + help << description; |
| 187 | + REQUIRE(help.str().find(ConfigParamsHelper::defaultValueForHelp(full)) != std::string::npos); |
| 188 | + REQUIRE(help.str().find(full) == std::string::npos); |
| 189 | + |
| 190 | + // the default value used when parsing is still the full one |
| 191 | + bpo::options_description forwarded; |
| 192 | + ConfigParamsHelper::dpl2BoostOptions(workflowOptions, forwarded); |
| 193 | + const char* noArgs[] = {"test"}; |
| 194 | + bpo::variables_map vm; |
| 195 | + bpo::store(parse_command_line(1, noArgs, forwarded), vm); |
| 196 | + REQUIRE(vm["longLabeledArray"].as<std::string>() == full); |
| 197 | + |
| 198 | + // also for the options registered for the devices |
| 199 | + bpo::options_description deviceOptions; |
| 200 | + ConfigParamsHelper::populateBoostProgramOptions(deviceOptions, workflowOptions); |
| 201 | + std::stringstream deviceHelp; |
| 202 | + deviceHelp << deviceOptions; |
| 203 | + REQUIRE(deviceHelp.str().find(full) == std::string::npos); |
| 204 | + bpo::variables_map deviceVm; |
| 205 | + bpo::store(parse_command_line(1, noArgs, deviceOptions), deviceVm); |
| 206 | + REQUIRE(deviceVm["longLabeledArray"].as<std::string>() == full); |
| 207 | +} |
0 commit comments