File indexing completed on 2025-12-16 09:25:35
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0012 #include "Acts/Geometry/GeometryIdentifier.hpp"
0013 #include "ActsPlugins/Json/GeometryHierarchyMapJsonConverter.hpp"
0014 #include "ActsTests/CommonHelpers/DataDirectory.hpp"
0015
0016 #include <algorithm>
0017 #include <fstream>
0018 #include <initializer_list>
0019 #include <stdexcept>
0020 #include <string>
0021 #include <vector>
0022
0023 #include <nlohmann/json.hpp>
0024
0025 using namespace Acts;
0026
0027 using nlohmann::json;
0028
0029 namespace {
0030
0031
0032 GeometryIdentifier makeId(int volume = 0, int layer = 0, int sensitive = 0) {
0033 return GeometryIdentifier().withVolume(volume).withLayer(layer).withSensitive(
0034 sensitive);
0035 }
0036
0037
0038
0039 struct Thing {
0040 double x = 1.0;
0041 int y = 23;
0042
0043 friend constexpr bool operator==(const Thing& lhs, const Thing& rhs) {
0044 return (lhs.x == rhs.x) && (lhs.y == rhs.y);
0045 }
0046 };
0047
0048
0049
0050
0051 void to_json(json& j, const Thing& t) {
0052 j = json{{"x", t.x}, {"y", t.y}};
0053 }
0054
0055 void from_json(const json& j, Thing& t) {
0056 j.at("x").get_to(t.x);
0057 j.at("y").get_to(t.y);
0058 }
0059
0060 std::ostream& operator<<(std::ostream& os, const Thing& t) {
0061 os << nlohmann::json(t);
0062 return os;
0063 }
0064
0065 class ThingDecorator {
0066 public:
0067 void decorate(const Thing* a_thing, nlohmann::json& a_json) const {
0068 if (a_thing != nullptr) {
0069 a_json["product"] = a_thing->x * a_thing->y;
0070 }
0071 }
0072 };
0073
0074 using Container = GeometryHierarchyMap<Thing>;
0075 using Converter = GeometryHierarchyMapJsonConverter<Thing, ThingDecorator>;
0076
0077 }
0078
0079 template <>
0080 void Acts::decorateJson<Thing>(const ThingDecorator* decorator,
0081 const Thing& src, nlohmann::json& dest) {
0082 if (decorator != nullptr) {
0083 decorator->decorate(&src, dest);
0084 }
0085 }
0086
0087 BOOST_TEST_DONT_PRINT_LOG_VALUE(json::iterator)
0088 BOOST_TEST_DONT_PRINT_LOG_VALUE(Container::Iterator)
0089
0090 namespace ActsTests {
0091
0092 BOOST_AUTO_TEST_SUITE(JsonSuite)
0093
0094 BOOST_AUTO_TEST_CASE(ToJson) {
0095 ThingDecorator decorator;
0096 Container c = {
0097 {makeId(1), {2.0, -3}},
0098 {makeId(2, 3), {-4.5, 5}},
0099 {makeId(4, 5, 6), {7.25, -8}},
0100 };
0101 json j = Converter("thing").toJson(c, &decorator);
0102
0103 BOOST_CHECK(j.is_object());
0104
0105 auto header = j.find("acts-geometry-hierarchy-map");
0106 BOOST_CHECK_NE(header, j.end());
0107 BOOST_CHECK(header->is_object());
0108 BOOST_CHECK(header->at("format-version").is_number_integer());
0109 BOOST_CHECK_EQUAL(header->at("format-version").get<int>(), 0);
0110 BOOST_CHECK(header->at("value-identifier").is_string());
0111 BOOST_CHECK_EQUAL(header->at("value-identifier").get<std::string>(), "thing");
0112
0113 auto entries = j.find("entries");
0114 BOOST_CHECK_NE(entries, j.end());
0115 BOOST_CHECK(entries->is_array());
0116 BOOST_CHECK_EQUAL(entries->size(), 3u);
0117 }
0118
0119 BOOST_AUTO_TEST_CASE(FromJson) {
0120 json j = {
0121 {
0122 "acts-geometry-hierarchy-map",
0123 {
0124 {"format-version", 0},
0125 {"value-identifier", "thing"},
0126 },
0127 },
0128 {
0129 "entries",
0130 {
0131 {
0132 {"volume", 2},
0133 {"layer", 3},
0134 {"value", {{"x", 4.0}, {"y", 4}}},
0135 },
0136 {
0137 {"volume", 5},
0138 {"layer", 6},
0139 {"sensitive", 7},
0140 {"value", {{"x", 3.0}, {"y", 3}}},
0141 },
0142 },
0143 },
0144 };
0145 Container c = Converter("thing").fromJson(j);
0146
0147 BOOST_CHECK(!c.empty());
0148 BOOST_CHECK_EQUAL(c.size(), 2);
0149 {
0150 auto it = c.find(makeId(2, 3));
0151 BOOST_CHECK_NE(it, c.end());
0152 BOOST_CHECK_EQUAL(it->x, 4.0);
0153 BOOST_CHECK_EQUAL(it->y, 4);
0154 }
0155 {
0156 auto it = c.find(makeId(5, 6, 7));
0157 BOOST_CHECK_NE(it, c.end());
0158 BOOST_CHECK_EQUAL(it->x, 3.0);
0159 BOOST_CHECK_EQUAL(it->y, 3);
0160 }
0161 }
0162
0163 BOOST_AUTO_TEST_CASE(FromJsonMissingHeader) {
0164 json j = {
0165 {"entries", {}},
0166 };
0167 BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0168 std::invalid_argument);
0169 }
0170
0171 BOOST_AUTO_TEST_CASE(FromJsonInvalidFormatVersion) {
0172 json j = {
0173 {
0174 "acts-geometry-hierarchy-map",
0175 {
0176 {"format-version", -1},
0177 {"value-identifier", "an-identifier"},
0178 },
0179 },
0180 {"entries", {}},
0181 };
0182 BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0183 std::invalid_argument);
0184 }
0185
0186 BOOST_AUTO_TEST_CASE(FromJsonInvalidValueIdentifier) {
0187 json j = {
0188 {
0189 "acts-geometry-hierarchy-map",
0190 {
0191 {"format-version", 0},
0192 {"value-identifier", "an-identifier"},
0193 },
0194 },
0195 {"entries", {}},
0196 };
0197 BOOST_CHECK_THROW(Converter("not-the-identifier").fromJson(j),
0198 std::invalid_argument);
0199 }
0200
0201 BOOST_AUTO_TEST_CASE(FromJsonMissingEntries) {
0202 json j = {
0203 {
0204 "acts-geometry-hierarchy-map",
0205 {
0206 {"format-version", 0},
0207 {"value-identifier", "an-identifier"},
0208 },
0209 },
0210 };
0211 BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0212 std::invalid_argument);
0213 }
0214
0215 BOOST_AUTO_TEST_CASE(Roundtrip) {
0216 ThingDecorator decorator;
0217 Container c0 = {
0218 {makeId(1), {2.0, -3}},
0219 {makeId(2, 3), {-4.5, 5}},
0220 {makeId(4, 5, 6), {7.25, -8}},
0221 };
0222 auto j = Converter("the-identifier").toJson(c0, &decorator);
0223 auto c1 = Converter("the-identifier").fromJson(j);
0224
0225 BOOST_CHECK_EQUAL(c0.size(), c1.size());
0226 for (auto i = std::min(c0.size(), c1.size()); 0 < i--;) {
0227 BOOST_CHECK_EQUAL(c0.idAt(i), c1.idAt(i));
0228 BOOST_CHECK_EQUAL(c0.valueAt(i), c1.valueAt(i));
0229 }
0230 }
0231
0232 BOOST_AUTO_TEST_CASE(FromFile) {
0233
0234 auto path = ActsTests::getDataPath("geometry-hierarchy-map.json");
0235 auto file = std::ifstream(path, std::ifstream::in | std::ifstream::binary);
0236 BOOST_CHECK(file.good());
0237 json j;
0238 file >> j;
0239 BOOST_CHECK(file.good());
0240
0241 Container c = Converter("thing").fromJson(j);
0242
0243 BOOST_CHECK(!c.empty());
0244 BOOST_CHECK_EQUAL(c.size(), 4);
0245 BOOST_CHECK_NE(c.find(makeId()), c.end());
0246 BOOST_CHECK_NE(c.find(makeId(1, 2)), c.end());
0247 BOOST_CHECK_NE(c.find(makeId(3)), c.end());
0248 BOOST_CHECK_NE(c.find(makeId(3, 4)), c.end());
0249 }
0250
0251 BOOST_AUTO_TEST_SUITE_END()
0252
0253 }