Skip to content

Commit

Permalink
Add JSON test comparator to improve testing reliability (celeritas-pr…
Browse files Browse the repository at this point in the history
…oject#1115)

* Add JSON comparer

* Replace string JSON comparison with smart comparison

* Add test for comparison output

* Use EXPECT_JSON_EQ and enable testing with single-precision
  • Loading branch information
sethrj committed Feb 19, 2024
1 parent 0f74ea9 commit 796c854
Show file tree
Hide file tree
Showing 17 changed files with 397 additions and 74 deletions.
9 changes: 8 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ include(CeleritasAddTest)
file(TO_CMAKE_PATH "${PROJECT_SOURCE_DIR}" CELERITAS_SOURCE_DIR)
configure_file(celeritas_test_config.h.in celeritas_test_config.h @ONLY)

celeritas_add_library(testcel_harness
set(_harness_sources
Test.cc
testdetail/NonMasterResultPrinter.cc
testdetail/TestMacrosImpl.cc
testdetail/TestMainImpl.cc
)
if(CELERITAS_USE_JSON)
list(APPEND _harness_sources
testdetail/JsonComparer.json.cc
)
endif()
celeritas_add_library(testcel_harness ${_harness_sources})
target_compile_features(testcel_harness PUBLIC cxx_std_17)
celeritas_target_link_libraries(testcel_harness
PUBLIC Celeritas::corecel GTest::GTest
Expand Down Expand Up @@ -71,5 +77,6 @@ endif()

celeritas_setup_tests(SERIAL PREFIX testdetail)
celeritas_add_test(TestMacros.test.cc)
celeritas_add_test(JsonComparer.test.cc)

#-----------------------------------------------------------------------------#
92 changes: 92 additions & 0 deletions test/JsonComparer.test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2024 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file JsonComparer.test.cc
//---------------------------------------------------------------------------//
#include "testdetail/JsonComparer.hh"

#include "celeritas_test.hh"

namespace celeritas
{
namespace testdetail
{
namespace test
{
//---------------------------------------------------------------------------//

class JsonComparerTest : public ::celeritas::test::Test
{
protected:
void SetUp() override {}
};

TEST_F(JsonComparerTest, parse_errors)
{
JsonComparer compare;
EXPECT_FALSE(compare("not valid json"));
EXPECT_FALSE(compare("null", "blorp"));
}

TEST_F(JsonComparerTest, scalars)
{
JsonComparer compare{real_type(0.001)};

EXPECT_TRUE(compare("null", "null"));

EXPECT_TRUE(compare("10"));
EXPECT_FALSE(compare("10", "11"));

EXPECT_TRUE(compare("10.0"));
EXPECT_TRUE(compare("10.0", "10.0001"));
EXPECT_FALSE(compare("10.0", "10.1"));
//
EXPECT_TRUE(compare("\"hi\"", "\"hi\""));
EXPECT_FALSE(compare("\"hi\"", "\"bye\""));

EXPECT_FALSE(compare("10.0", "10")); // float to int
EXPECT_FALSE(compare("10", "null")); // float to null
}

TEST_F(JsonComparerTest, array)
{
JsonComparer compare;

EXPECT_TRUE(compare("[]", "[]"));
EXPECT_TRUE(compare("[1, 2, 3]", "[1, 2, 3]"));
EXPECT_FALSE(compare("[1, 2, 3]", "[2, 2, 3]"));
}

TEST_F(JsonComparerTest, object)
{
JsonComparer compare{real_type(0.001)};

EXPECT_TRUE(compare(R"json({"a": 1, "b": 2})json"));
EXPECT_TRUE(
compare(R"json({"a": 1, "b": 2})json", R"json({"b": 2, "a": 1})json"));
EXPECT_FALSE(compare(R"json({"a": 1})json", R"json({"a": 1, "c": 2})json"));
EXPECT_FALSE(
compare(R"json({"a": 1, "b": 2})json", R"json({"a": 1, "c": 2})json"));
EXPECT_FALSE(
compare(R"json({"a": 1, "b": 2})json", R"json({"a": 2, "b": 1})json"));
}

TEST_F(JsonComparerTest, stringification)
{
JsonComparer compare{real_type(0.001)};
auto r = compare(R"json({"a": 1, "b": [1, 2, [0]]})json",
R"json({"a": 2, "b": [2, 3, [4, 5]]})json");
EXPECT_STREQ(R"(JSON objects differ:
value in .["a"]: expected 1, but got 2
value in .["b"][0]: expected 1, but got 2
value in .["b"][1]: expected 2, but got 3
size in .["b"][2]: expected 1, but got 2)",
r.message());
}

//---------------------------------------------------------------------------//
} // namespace test
} // namespace testdetail
} // namespace celeritas
8 changes: 3 additions & 5 deletions test/celeritas/ext/GeantImporter.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,9 @@ class FourSteelSlabsEmStandard : public GeantImporterTest
if (CELERITAS_UNITS == CELERITAS_UNITS_CGS)
{
nlohmann::json out = opts;
static char const expected[]
= R"json({"annihilation":true,"apply_cuts":false,"brems":"all","compton_scattering":true,"coulomb_scattering":false,"default_cutoff":0.1,"eloss_fluctuation":true,"em_bins_per_decade":7,"gamma_conversion":true,"gamma_general":false,"integral_approach":true,"ionization":true,"linear_loss_limit":0.01,"lowest_electron_energy":[0.001,"MeV"],"lpm":true,"max_energy":[100000000.0,"MeV"],"min_energy":[0.0001,"MeV"],"msc":"urban_extended","msc_lambda_limit":0.1,"msc_range_factor":0.04,"msc_safety_factor":0.6,"photoelectric":true,"rayleigh_scattering":true,"relaxation":"all","verbose":true})json";
EXPECT_EQ(std::string(expected), std::string(out.dump()))
<< "\n/*** REPLACE ***/\nR\"json(" << std::string(out.dump())
<< ")json\"\n/******/";
EXPECT_JSON_EQ(
R"json({"annihilation":true,"apply_cuts":false,"brems":"all","compton_scattering":true,"coulomb_scattering":false,"default_cutoff":0.1,"eloss_fluctuation":true,"em_bins_per_decade":7,"gamma_conversion":true,"gamma_general":false,"integral_approach":true,"ionization":true,"linear_loss_limit":0.01,"lowest_electron_energy":[0.001,"MeV"],"lpm":true,"max_energy":[100000000.0,"MeV"],"min_energy":[0.0001,"MeV"],"msc":"urban_extended","msc_lambda_limit":0.1,"msc_range_factor":0.04,"msc_safety_factor":0.6,"photoelectric":true,"rayleigh_scattering":true,"relaxation":"all","verbose":true})json",
std::string(out.dump()));
}
#endif
return opts;
Expand Down
12 changes: 4 additions & 8 deletions test/celeritas/geo/Geometry.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -270,19 +270,15 @@ TEST_F(SimpleCmsTest, output)
}
else if (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_VECGEOM)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"bbox":[[-1000.001,-1000.001,-2000.001],[1000.001,1000.001,2000.001]],"supports_safety":true,"volumes":{"label":["vacuum_tube","si_tracker","em_calorimeter","had_calorimeter","sc_solenoid","fe_muon_chambers","world"]}})json",
to_string(out))
<< "\n/*** REPLACE ***/\nR\"json(" << to_string(out)
<< ")json\"\n/******/";
to_string(out));
}
else if (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"bbox":[[-1000.0,-1000.0,-2000.0],[1000.0,1000.0,2000.0]],"supports_safety":false,"surfaces":{"label":["world_box.mx@global","world_box.px@global","world_box.my@global","world_box.py@global","world_box.mz@global","world_box.pz@global","guide_tube.coz@global","crystal_em_calorimeter_outer.mz@global","crystal_em_calorimeter_outer.pz@global","silicon_tracker_outer.coz@global","crystal_em_calorimeter_outer.coz@global","hadron_calorimeter_outer.coz@global","superconducting_solenoid_outer.coz@global","iron_muon_chambers_outer.coz@global"]},"volumes":{"label":["[EXTERIOR]@global","vacuum_tube@global","si_tracker@global","em_calorimeter@global","had_calorimeter@global","sc_solenoid@global","fe_muon_chambers@global","world@global"]}})json",
to_string(out))
<< "\n/*** REPLACE ***/\nR\"json(" << to_string(out)
<< ")json\"\n/******/";
to_string(out));
}
}

Expand Down
6 changes: 2 additions & 4 deletions test/celeritas/global/ActionRegistry.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,9 @@ TEST_F(ActionRegistryTest, output)

if (CELERITAS_USE_JSON)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"description":["","explicit action test","the second implicit action"],"label":["impl1","explicit","impl2"]})json",
to_string(out))
<< "\n/*** REPLACE ***/\nR\"json(" << to_string(out)
<< ")json\"\n/******/";
to_string(out));
}
}

Expand Down
7 changes: 4 additions & 3 deletions test/celeritas/global/KernelContextException.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ TEST_F(KernelContextExceptionTest, typical)
ss << R"json({"dir":[0.0,0.0,1.0],"energy":[10.0,"MeV"],"event":1,"label":"test-kernel","num_steps":1,"particle":0,"pos":[0.0,1.0,5.0],"surface":11,"thread":)json"
<< e.thread().unchecked_get()
<< R"json(,"track":3,"track_slot":15,"volume":2})json";
EXPECT_EQ(ss.str(), get_json_str(e));
EXPECT_JSON_EQ(ss.str(), get_json_str(e));
}
};
// Since tracks are initialized back to front, the thread ID must be toward
Expand Down Expand Up @@ -189,7 +189,7 @@ TEST_F(KernelContextExceptionTest, uninitialized_track)
std::stringstream ss;
ss << R"json({"label":"test-kernel","thread":)json"
<< e.thread().unchecked_get() << R"json(,"track_slot":1})json";
EXPECT_EQ(ss.str(), get_json_str(e));
EXPECT_JSON_EQ(ss.str(), get_json_str(e));
}
};

Expand Down Expand Up @@ -218,7 +218,8 @@ TEST_F(KernelContextExceptionTest, bad_thread)
EXPECT_EQ(TrackSlotId{}, e.track_slot());
if (CELERITAS_USE_JSON)
{
EXPECT_EQ(R"json({"label":"dumb-kernel"})json", get_json_str(e));
EXPECT_JSON_EQ(R"json({"label":"dumb-kernel"})json",
get_json_str(e));
}
};
CELER_TRY_HANDLE_CONTEXT(
Expand Down
2 changes: 1 addition & 1 deletion test/celeritas/mat/Material.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ TEST_F(MaterialTest, isotope_view)
EXPECT_VEC_SOFT_EQ(expected_nuclear_masses, nuclear_masses);
}

TEST_F(MaterialTest, TEST_IF_CELERITAS_DOUBLE(output))
TEST_F(MaterialTest, output)
{
MaterialParamsOutput out(params);
EXPECT_EQ("material", out.label());
Expand Down
8 changes: 3 additions & 5 deletions test/celeritas/phys/Particle.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,16 @@ TEST_F(ParticleTest, params_accessors)
EXPECT_EQ(PDGNumber(11), defs.id_to_pdg(ParticleId(0)));
}

TEST_F(ParticleTest, TEST_IF_CELERITAS_DOUBLE(output))
TEST_F(ParticleTest, output)
{
ParticleParamsOutput out(this->particle_params);
EXPECT_EQ("particle", out.label());

if (CELERITAS_USE_JSON && CELERITAS_UNITS == CELERITAS_UNITS_CGS)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"_units":{"charge":"e","mass":"MeV/c^2"},"charge":[-1.0,0.0,0.0,1.0],"decay_constant":[0.0,0.0,0.0011371389583807142,0.0],"is_antiparticle":[false,false,false,true],"label":["electron","gamma","neutron","positron"],"mass":[0.5109989461,0.0,939.565413,0.5109989461],"pdg":[11,22,2112,-11]})json",
to_string(out))
<< "\n/*** REPLACE ***/\nR\"json(" << to_string(out)
<< ")json\"\n/******/";
to_string(out));
}
}

Expand Down
4 changes: 0 additions & 4 deletions test/celeritas/phys/Physics.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ TEST_F(PhysicsParamsTest, output)
PhysicsParamsOutput out(this->physics());
EXPECT_EQ("physics", out.label());

if (CELERITAS_REAL_TYPE != CELERITAS_REAL_TYPE_DOUBLE)
{
GTEST_SKIP() << "Test results are based on double-precision data";
}
if (CELERITAS_UNITS != CELERITAS_UNITS_CGS)
{
GTEST_SKIP() << "Test results are based on CGS units";
Expand Down
6 changes: 3 additions & 3 deletions test/celeritas/phys/PrimaryGenerator.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ TEST_F(PrimaryGeneratorTest, options)
#if CELERITAS_USE_JSON
{
nlohmann::json out = opts;
static char const expected[]
= R"json({"direction":{"distribution":"isotropic","params":[]},"energy":{"distribution":"delta","params":[1.0]},"num_events":1,"pdg":[22],"position":{"distribution":"box","params":[-3.0,-3.0,-3.0,3.0,3.0,3.0]},"primaries_per_event":10,"seed":0})json";
EXPECT_EQ(std::string(expected), std::string(out.dump()));
EXPECT_JSON_EQ(
R"json({"direction":{"distribution":"isotropic","params":[]},"energy":{"distribution":"delta","params":[1.0]},"num_events":1,"pdg":[22],"position":{"distribution":"box","params":[-3.0,-3.0,-3.0,3.0,3.0,3.0]},"primaries_per_event":10,"seed":0})json",
std::string(out.dump()));
}
#endif
}
Expand Down
6 changes: 3 additions & 3 deletions test/corecel/io/OutputRegistry.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ TEST_F(OutputRegistryTest, minimal)
std::string result = this->to_string(reg);
if (CELERITAS_USE_JSON)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"input":{"input_value":42},"result":{"out":1,"timing":2}})json",
result);
}
Expand Down Expand Up @@ -177,7 +177,7 @@ TEST_F(OutputRegistryTest, exception_output)
std::string result = this->to_string(reg);
if (CELERITAS_USE_JSON)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"result":{"exception":{"condition":"false","file":"FILE","line":123,"type":"RuntimeError","what":"things went wrong","which":"runtime"}}})json",
result);
}
Expand All @@ -197,7 +197,7 @@ TEST_F(OutputRegistryTest, nested_exception_output)
std::string result = this->to_string(reg);
if (CELERITAS_USE_JSON)
{
EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"result":{"exception":{"condition":"false","context":{"event":2,"thread":123,"track":4567,"type":"MockKernelContextException"},"file":"FILE","line":123,"type":"RuntimeError","what":"things went wrong","which":"runtime"}}})json",
result);
}
Expand Down
6 changes: 3 additions & 3 deletions test/corecel/sys/Environment.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ TEST(EnvironmentTest, TEST_IF_CELERITAS_JSON(json))
{
// Save environment
nlohmann::json out{env};
static char const expected[]
= R"json([{"ENVTEST_CUSTOM":"custom","ENVTEST_ONE":"111111","ENVTEST_ZERO":"000000"}])json";
EXPECT_EQ(std::string(expected), std::string(out.dump()));
EXPECT_JSON_EQ(
R"json([{"ENVTEST_CUSTOM":"custom","ENVTEST_ONE":"111111","ENVTEST_ZERO":"000000"}])json",
out.dump());
}
#endif
}
Expand Down
12 changes: 4 additions & 8 deletions test/geocel/vg/Vecgeom.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -714,11 +714,9 @@ TEST_F(SolidsTest, output)
{
auto out_str = simplify_pointers(to_string(out));

EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"bbox":[[-600.001,-300.001,-75.001],[600.001,300.001,75.001]],"supports_safety":true,"volumes":{"label":["b500","b100","union1","b100","box500","cone1","para1","sphere1","parabol1","trap1","trd1","trd2","trd3","trd3_refl","tube100","boolean1","polycone1","genPocone1","ellipsoid1","tetrah1","orb1","polyhedr1","hype1","elltube1","ellcone1","arb8b","arb8a","xtru1","World","","trd3_refl"]}})json",
out_str)
<< "\n/*** REPLACE ***/\nR\"json(" << out_str
<< ")json\"\n/******/";
out_str);
}
}

Expand Down Expand Up @@ -1282,11 +1280,9 @@ TEST_F(SolidsGeantTest, output)
{
auto out_str = simplify_pointers(to_string(out));

EXPECT_EQ(
EXPECT_JSON_EQ(
R"json({"bbox":[[-600.001,-300.001,-75.001],[600.001,300.001,75.001]],"supports_safety":true,"volumes":{"label":["box500@0x0","cone1@0x0","para1@0x0","sphere1@0x0","parabol1@0x0","trap1@0x0","trd1@0x0","trd2@0x0","trd3@0x0","trd3_refl@0x0","tube100@0x0","","","","","boolean1@0x0","polycone1@0x0","genPocone1@0x0","ellipsoid1@0x0","tetrah1@0x0","orb1@0x0","polyhedr1@0x0","hype1@0x0","elltube1@0x0","ellcone1@0x0","arb8b@0x0","arb8a@0x0","xtru1@0x0","World@0x0","","trd3@0x0_refl"]}})json",
out_str)
<< "\n/*** REPLACE ***/\nR\"json(" << out_str
<< ")json\"\n/******/";
out_str);
}
}

Expand Down

0 comments on commit 796c854

Please sign in to comment.