From 7f81e62400bb426edf153745c67b999bb6a7e197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20P=C3=B6schel?= Date: Fri, 13 Dec 2024 19:16:19 +0100 Subject: [PATCH] Extensive testing --- src/IO/JSON/JSONIOHandlerImpl.cpp | 8 +- test/JSONTest.cpp | 191 ++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 6 deletions(-) diff --git a/src/IO/JSON/JSONIOHandlerImpl.cpp b/src/IO/JSON/JSONIOHandlerImpl.cpp index 0cf82ebd5e..a432737188 100644 --- a/src/IO/JSON/JSONIOHandlerImpl.cpp +++ b/src/IO/JSON/JSONIOHandlerImpl.cpp @@ -653,12 +653,8 @@ void JSONIOHandlerImpl::createDataset( default: break; } - if (parameter.extent.size() == 1 && - parameter.extent[0] == Dataset::UNDEFINED_EXTENT) - { - dset["data"] = std::vector(0); - } - else + if (parameter.extent.size() != 1 || + parameter.extent[0] != Dataset::UNDEFINED_EXTENT) { // TOML does not support nulls, so initialize with zero dset["data"] = initializeNDArray( diff --git a/test/JSONTest.cpp b/test/JSONTest.cpp index 161f1fa3a3..78ffc6e01e 100644 --- a/test/JSONTest.cpp +++ b/test/JSONTest.cpp @@ -1,6 +1,7 @@ #include "openPMD/auxiliary/JSON.hpp" #include "openPMD/Error.hpp" #include "openPMD/auxiliary/JSON_internal.hpp" +#include "openPMD/helper/list_series.hpp" #include "openPMD/openPMD.hpp" #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include @@ -306,3 +308,192 @@ TEST_CASE("variableBasedModifiedSnapshot", "[auxiliary]") testRead(std::vector{1, 2, 3, 4, 5}); } + +namespace auxiliary +{ +template +void test_matrix_impl(Callable &callable, AccumulatorTuple tuple) +{ + std::apply(callable, std::move(tuple)); +} + +template < + typename Callable, + typename AccumulatorTuple, + typename Arg, + typename... Args> +void test_matrix_impl( + Callable &callable, + AccumulatorTuple tuple, + std::vector const &arg, + std::vector const &...args) +{ + for (auto &val : arg) + { + test_matrix_impl( + callable, std::tuple_cat(tuple, std::tuple{val}), args...); + } +} + +template +void test_matrix(Callable &&callable, std::vector const &...matrix) +{ + test_matrix_impl(callable, std::tuple<>(), matrix...); +} +} // namespace auxiliary + +void json_short_modes( + std::optional short_attributes, + std::optional template_datasets, + std::string const &standardVersion, + std::string const &backend, + unsigned int *name_counter) +{ + nlohmann::json config = nlohmann::json::object(); + if (short_attributes.has_value()) + { + config[backend]["attribute"]["mode"] = + *short_attributes ? "short" : "long"; + } + if (template_datasets.has_value()) + { + config[backend]["dataset"]["mode"] = + *template_datasets ? "template" : "dataset"; + } + std::string name = "../samples/json_short_modes/test" + + std::to_string((*name_counter)++) + "." + backend; + + auto config_str = [&]() { + std::stringstream res; + res << config; + return res.str(); + }(); + Series output(name, Access::CREATE, config_str); + output.setOpenPMD(standardVersion); + auto iteration = output.writeIterations()[0]; + + auto default_configured = iteration.meshes["default_configured"]; + Dataset ds1(Datatype::INT, {5}); + default_configured.resetDataset(ds1); + + auto explicitly_templated = iteration.meshes["explicitly_templated"]; + Dataset ds2 = ds1; + ds2.options = backend + R"(.dataset.mode = "template")"; + explicitly_templated.resetDataset(ds2); + + auto explicitly_not_templated = + iteration.meshes["explicitly_not_templated"]; + Dataset ds3 = ds1; + ds3.options = backend + R"(.dataset.mode = "dataset")"; + explicitly_not_templated.resetDataset(ds3); + + auto undefined_dataset = iteration.meshes["undefined_dataset"]; + Dataset d4(Datatype::UNDEFINED, {Dataset::UNDEFINED_EXTENT}); + undefined_dataset.resetDataset(d4); + + output.close(); + + bool expect_template_datasets = template_datasets.value_or(false); + bool expect_short_attributes = short_attributes.value_or( + backend == "toml" || standardVersion == "2.0.0"); + + nlohmann::json resulting_dataset = [&]() { + std::fstream handle; + handle.open(name, std::ios_base::binary | std::ios_base::in); + if (backend == "json") + { + nlohmann::json res; + handle >> res; + return res; + } + else + { + auto toml_val = toml::parse(handle, name); + return json::tomlToJson(toml_val); + } + }(); + + if (expect_short_attributes) + { + REQUIRE( + resulting_dataset["attributes"]["openPMD"] == + nlohmann::json::string_t{standardVersion}); + REQUIRE( + resulting_dataset["__openPMD_internal"]["attribute_mode"] == + nlohmann::json::string_t{"short"}); + } + else + { + REQUIRE( + resulting_dataset["attributes"]["openPMD"] == + nlohmann::json{{"datatype", "STRING"}, {"value", standardVersion}}); + REQUIRE( + resulting_dataset["__openPMD_internal"]["attribute_mode"] == + nlohmann::json::string_t{"long"}); + } + + auto verify_full_dataset = [&](nlohmann::json const &j) { + REQUIRE(j["datatype"] == "INT"); + if (backend == "json") + { + nlohmann::json null; + REQUIRE( + j["data"] == + nlohmann::json::array_t{null, null, null, null, null}); + } + else + { + REQUIRE(j["data"] == nlohmann::json::array_t{0, 0, 0, 0, 0}); + } + REQUIRE(j.size() == 3); + }; + auto verify_template_dataset = [](nlohmann::json const &j) { + REQUIRE(j["datatype"] == "INT"); + REQUIRE(j["extent"] == nlohmann::json::array_t{5}); + REQUIRE(j.size() == 3); + }; + + // Undefined datasets write neither `extent` nor `data` key, so they are + // not distinguished between template and nontemplate mode. + REQUIRE( + resulting_dataset["data"]["0"]["meshes"]["undefined_dataset"] + ["datatype"] == nlohmann::json::string_t{"UNDEFINED"}); + REQUIRE( + resulting_dataset["data"]["0"]["meshes"]["undefined_dataset"].size() == + 2); + if (expect_template_datasets) + { + REQUIRE( + resulting_dataset["__openPMD_internal"]["dataset_mode"] == + nlohmann::json::string_t{"template"}); + verify_template_dataset( + resulting_dataset["data"]["0"]["meshes"]["default_configured"]); + } + else + { + REQUIRE( + resulting_dataset["__openPMD_internal"]["dataset_mode"] == + nlohmann::json::string_t{"dataset"}); + verify_full_dataset( + resulting_dataset["data"]["0"]["meshes"]["default_configured"]); + } + verify_template_dataset( + resulting_dataset["data"]["0"]["meshes"]["explicitly_templated"]); + verify_full_dataset( + resulting_dataset["data"]["0"]["meshes"]["explicitly_not_templated"]); + + Series read(name, Access::READ_ONLY); + helper::listSeries(read); +} + +TEST_CASE("json_short_modes") +{ + unsigned int name_counter = 0; + ::auxiliary::test_matrix( + &json_short_modes, + std::vector>{std::nullopt, true, false}, + std::vector>{std::nullopt, true, false}, + std::vector{getStandardDefault(), getStandardMaximum()}, + std::vector{"json", "toml"}, + std::vector{&name_counter}); +}