Skip to content

Commit f72ef68

Browse files
committed
Extensive testing
1 parent 8c02519 commit f72ef68

File tree

2 files changed

+193
-6
lines changed

2 files changed

+193
-6
lines changed

src/IO/JSON/JSONIOHandlerImpl.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -648,12 +648,8 @@ void JSONIOHandlerImpl::createDataset(
648648
default:
649649
break;
650650
}
651-
if (parameter.extent.size() == 1 &&
652-
parameter.extent[0] == Dataset::UNDEFINED_EXTENT)
653-
{
654-
dset["data"] = std::vector<int>(0);
655-
}
656-
else
651+
if (parameter.extent.size() != 1 ||
652+
parameter.extent[0] != Dataset::UNDEFINED_EXTENT)
657653
{
658654
// TOML does not support nulls, so initialize with zero
659655
dset["data"] = initializeNDArray(

test/JSONTest.cpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "openPMD/auxiliary/JSON.hpp"
22
#include "openPMD/Error.hpp"
33
#include "openPMD/auxiliary/JSON_internal.hpp"
4+
#include "openPMD/helper/list_series.hpp"
45
#include "openPMD/openPMD.hpp"
56

67
#include <catch2/catch.hpp>
@@ -9,6 +10,7 @@
910
#include <fstream>
1011
#include <sstream>
1112
#include <string>
13+
#include <tuple>
1214
#include <variant>
1315
#include <vector>
1416

@@ -306,3 +308,192 @@ TEST_CASE("variableBasedModifiedSnapshot", "[auxiliary]")
306308

307309
testRead(std::vector<size_t>{1, 2, 3, 4, 5});
308310
}
311+
312+
namespace auxiliary
313+
{
314+
template <typename Callable, typename AccumulatorTuple>
315+
void test_matrix_impl(Callable &callable, AccumulatorTuple tuple)
316+
{
317+
std::apply(callable, std::move(tuple));
318+
}
319+
320+
template <
321+
typename Callable,
322+
typename AccumulatorTuple,
323+
typename Arg,
324+
typename... Args>
325+
void test_matrix_impl(
326+
Callable &callable,
327+
AccumulatorTuple tuple,
328+
std::vector<Arg> const &arg,
329+
std::vector<Args> const &...args)
330+
{
331+
for (auto &val : arg)
332+
{
333+
test_matrix_impl(
334+
callable, std::tuple_cat(tuple, std::tuple<Arg>{val}), args...);
335+
}
336+
}
337+
338+
template <typename Callable, typename... Args>
339+
void test_matrix(Callable &&callable, std::vector<Args> const &...matrix)
340+
{
341+
test_matrix_impl(callable, std::tuple<>(), matrix...);
342+
}
343+
} // namespace auxiliary
344+
345+
void json_short_modes(
346+
std::optional<bool> short_attributes,
347+
std::optional<bool> template_datasets,
348+
std::string const &standardVersion,
349+
std::string const &backend,
350+
unsigned int *name_counter)
351+
{
352+
nlohmann::json config = nlohmann::json::object();
353+
if (short_attributes.has_value())
354+
{
355+
config[backend]["attribute"]["mode"] =
356+
*short_attributes ? "short" : "long";
357+
}
358+
if (template_datasets.has_value())
359+
{
360+
config[backend]["dataset"]["mode"] =
361+
*template_datasets ? "template" : "dataset";
362+
}
363+
std::string name = "../samples/json_short_modes/test" +
364+
std::to_string((*name_counter)++) + "." + backend;
365+
366+
auto config_str = [&]() {
367+
std::stringstream res;
368+
res << config;
369+
return res.str();
370+
}();
371+
Series output(name, Access::CREATE, config_str);
372+
output.setOpenPMD(standardVersion);
373+
auto iteration = output.writeIterations()[0];
374+
375+
auto default_configured = iteration.meshes["default_configured"];
376+
Dataset ds1(Datatype::INT, {5});
377+
default_configured.resetDataset(ds1);
378+
379+
auto explicitly_templated = iteration.meshes["explicitly_templated"];
380+
Dataset ds2 = ds1;
381+
ds2.options = backend + R"(.dataset.mode = "template")";
382+
explicitly_templated.resetDataset(ds2);
383+
384+
auto explicitly_not_templated =
385+
iteration.meshes["explicitly_not_templated"];
386+
Dataset ds3 = ds1;
387+
ds3.options = backend + R"(.dataset.mode = "dataset")";
388+
explicitly_not_templated.resetDataset(ds3);
389+
390+
auto undefined_dataset = iteration.meshes["undefined_dataset"];
391+
Dataset d4(Datatype::UNDEFINED, {Dataset::UNDEFINED_EXTENT});
392+
undefined_dataset.resetDataset(d4);
393+
394+
output.close();
395+
396+
bool expect_template_datasets = template_datasets.value_or(false);
397+
bool expect_short_attributes = short_attributes.value_or(
398+
backend == "toml" || standardVersion == "2.0.0");
399+
400+
nlohmann::json resulting_dataset = [&]() {
401+
std::fstream handle;
402+
handle.open(name, std::ios_base::binary | std::ios_base::in);
403+
if (backend == "json")
404+
{
405+
nlohmann::json res;
406+
handle >> res;
407+
return res;
408+
}
409+
else
410+
{
411+
auto toml_val = toml::parse(handle, name);
412+
return json::tomlToJson(toml_val);
413+
}
414+
}();
415+
416+
if (expect_short_attributes)
417+
{
418+
REQUIRE(
419+
resulting_dataset["attributes"]["openPMD"] ==
420+
nlohmann::json::string_t{standardVersion});
421+
REQUIRE(
422+
resulting_dataset["__openPMD_internal"]["attribute_mode"] ==
423+
nlohmann::json::string_t{"short"});
424+
}
425+
else
426+
{
427+
REQUIRE(
428+
resulting_dataset["attributes"]["openPMD"] ==
429+
nlohmann::json{{"datatype", "STRING"}, {"value", standardVersion}});
430+
REQUIRE(
431+
resulting_dataset["__openPMD_internal"]["attribute_mode"] ==
432+
nlohmann::json::string_t{"long"});
433+
}
434+
435+
auto verify_full_dataset = [&](nlohmann::json const &j) {
436+
REQUIRE(j["datatype"] == "INT");
437+
if (backend == "json")
438+
{
439+
nlohmann::json null;
440+
REQUIRE(
441+
j["data"] ==
442+
nlohmann::json::array_t{null, null, null, null, null});
443+
}
444+
else
445+
{
446+
REQUIRE(j["data"] == nlohmann::json::array_t{0, 0, 0, 0, 0});
447+
}
448+
REQUIRE(j.size() == 3);
449+
};
450+
auto verify_template_dataset = [](nlohmann::json const &j) {
451+
REQUIRE(j["datatype"] == "INT");
452+
REQUIRE(j["extent"] == nlohmann::json::array_t{5});
453+
REQUIRE(j.size() == 3);
454+
};
455+
456+
// Undefined datasets write neither `extent` nor `data` key, so they are
457+
// not distinguished between template and nontemplate mode.
458+
REQUIRE(
459+
resulting_dataset["data"]["0"]["meshes"]["undefined_dataset"]
460+
["datatype"] == nlohmann::json::string_t{"UNDEFINED"});
461+
REQUIRE(
462+
resulting_dataset["data"]["0"]["meshes"]["undefined_dataset"].size() ==
463+
2);
464+
if (expect_template_datasets)
465+
{
466+
REQUIRE(
467+
resulting_dataset["__openPMD_internal"]["dataset_mode"] ==
468+
nlohmann::json::string_t{"template"});
469+
verify_template_dataset(
470+
resulting_dataset["data"]["0"]["meshes"]["default_configured"]);
471+
}
472+
else
473+
{
474+
REQUIRE(
475+
resulting_dataset["__openPMD_internal"]["dataset_mode"] ==
476+
nlohmann::json::string_t{"dataset"});
477+
verify_full_dataset(
478+
resulting_dataset["data"]["0"]["meshes"]["default_configured"]);
479+
}
480+
verify_template_dataset(
481+
resulting_dataset["data"]["0"]["meshes"]["explicitly_templated"]);
482+
verify_full_dataset(
483+
resulting_dataset["data"]["0"]["meshes"]["explicitly_not_templated"]);
484+
485+
Series read(name, Access::READ_ONLY);
486+
helper::listSeries(read);
487+
}
488+
489+
TEST_CASE("json_short_modes")
490+
{
491+
unsigned int name_counter = 0;
492+
::auxiliary::test_matrix(
493+
&json_short_modes,
494+
std::vector<std::optional<bool>>{std::nullopt, true, false},
495+
std::vector<std::optional<bool>>{std::nullopt, true, false},
496+
std::vector<std::string>{getStandardDefault(), getStandardMaximum()},
497+
std::vector<std::string>{"json", "toml"},
498+
std::vector<unsigned int *>{&name_counter});
499+
}

0 commit comments

Comments
 (0)