Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeometryHierarchyMapJsonConverterTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GeometryHierarchyMapJsonConverterTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/unit_test.hpp>
10 
15 
16 #include <algorithm>
17 #include <fstream>
18 #include <initializer_list>
19 #include <stdexcept>
20 #include <string>
21 #include <vector>
22 
23 #include <nlohmann/json.hpp>
24 
25 namespace {
26 
28 using nlohmann::json;
29 
30 // helper function to create geometry ids.
31 GeometryIdentifier makeId(int volume = 0, int layer = 0, int sensitive = 0) {
32  return GeometryIdentifier().setVolume(volume).setLayer(layer).setSensitive(
33  sensitive);
34 }
35 
36 // example element for the container
37 
38 struct Thing {
39  double x = 1.0;
40  int y = 23;
41 
42  friend constexpr bool operator==(const Thing& lhs, const Thing& rhs) {
43  return (lhs.x == rhs.x) and (lhs.y == rhs.y);
44  }
45 };
46 
47 // custom Json encoder/decoder. naming is mandated by nlohmann::json and thus
48 // can not match our naming guidelines.
49 
50 void to_json(json& j, const Thing& t) {
51  j = json{{"x", t.x}, {"y", t.y}};
52 }
53 
54 void from_json(const json& j, Thing& t) {
55  j.at("x").get_to(t.x);
56  j.at("y").get_to(t.y);
57 }
58 
59 std::ostream& operator<<(std::ostream& os, const Thing& t) {
60  os << nlohmann::json(t);
61  return os;
62 }
63 
64 class ThingDecorator {
65  public:
66  void decorate(const Thing* a_thing, nlohmann::json& a_json) const {
67  if (a_thing != nullptr) {
68  a_json["product"] = a_thing->x * a_thing->y;
69  }
70  }
71 };
72 
73 using Container = Acts::GeometryHierarchyMap<Thing>;
74 using Converter =
76 
77 } // namespace
78 
79 template <>
80 void Acts::decorateJson<Thing>(const ThingDecorator* decorator,
81  const Thing& src, nlohmann::json& dest) {
82  if (decorator != nullptr) {
83  decorator->decorate(&src, dest);
84  }
85 }
86 
87 BOOST_TEST_DONT_PRINT_LOG_VALUE(json::iterator)
88 BOOST_TEST_DONT_PRINT_LOG_VALUE(Container::Iterator)
89 
90 BOOST_AUTO_TEST_SUITE(GeometryHierarchyMapJsonConverter)
91 
93  ThingDecorator decorator;
94  Container c = {
95  {makeId(1), {2.0, -3}},
96  {makeId(2, 3), {-4.5, 5}},
97  {makeId(4, 5, 6), {7.25, -8}},
98  };
99  json j = Converter("thing").toJson(c, &decorator);
100 
101  BOOST_CHECK(j.is_object());
102  // check header
103  auto header = j.find("acts-geometry-hierarchy-map");
104  BOOST_CHECK_NE(header, j.end());
105  BOOST_CHECK(header->is_object());
106  BOOST_CHECK(header->at("format-version").is_number_integer());
107  BOOST_CHECK_EQUAL(header->at("format-version").get<int>(), 0);
108  BOOST_CHECK(header->at("value-identifier").is_string());
109  BOOST_CHECK_EQUAL(header->at("value-identifier").get<std::string>(), "thing");
110  // check entries
111  auto entries = j.find("entries");
112  BOOST_CHECK_NE(entries, j.end());
113  BOOST_CHECK(entries->is_array());
114  BOOST_CHECK_EQUAL(entries->size(), 3u);
115 }
116 
118  json j = {
119  {
120  "acts-geometry-hierarchy-map",
121  {
122  {"format-version", 0},
123  {"value-identifier", "thing"},
124  },
125  },
126  {
127  "entries",
128  {
129  {
130  {"volume", 2},
131  {"layer", 3},
132  {"value", {{"x", 4.0}, {"y", 4}}},
133  },
134  {
135  {"volume", 5},
136  {"layer", 6},
137  {"sensitive", 7},
138  {"value", {{"x", 3.0}, {"y", 3}}},
139  },
140  },
141  },
142  };
143  Container c = Converter("thing").fromJson(j);
144 
145  BOOST_CHECK(not c.empty());
146  BOOST_CHECK_EQUAL(c.size(), 2);
147  {
148  auto it = c.find(makeId(2, 3));
149  BOOST_CHECK_NE(it, c.end());
150  BOOST_CHECK_EQUAL(it->x, 4.0);
151  BOOST_CHECK_EQUAL(it->y, 4);
152  }
153  {
154  auto it = c.find(makeId(5, 6, 7));
155  BOOST_CHECK_NE(it, c.end());
156  BOOST_CHECK_EQUAL(it->x, 3.0);
157  BOOST_CHECK_EQUAL(it->y, 3);
158  }
159 }
160 
161 BOOST_AUTO_TEST_CASE(FromJsonMissingHeader) {
162  json j = {
163  {"entries", {}},
164  };
165  BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
166  std::invalid_argument);
167 }
168 
169 BOOST_AUTO_TEST_CASE(FromJsonInvalidFormatVersion) {
170  json j = {
171  {
172  "acts-geometry-hierarchy-map",
173  {
174  {"format-version", -1},
175  {"value-identifier", "an-identifier"},
176  },
177  },
178  {"entries", {}},
179  };
180  BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
181  std::invalid_argument);
182 }
183 
184 BOOST_AUTO_TEST_CASE(FromJsonInvalidValueIdentifier) {
185  json j = {
186  {
187  "acts-geometry-hierarchy-map",
188  {
189  {"format-version", 0},
190  {"value-identifier", "an-identifier"},
191  },
192  },
193  {"entries", {}},
194  };
195  BOOST_CHECK_THROW(Converter("not-the-identifier").fromJson(j),
196  std::invalid_argument);
197 }
198 
199 BOOST_AUTO_TEST_CASE(FromJsonMissingEntries) {
200  json j = {
201  {
202  "acts-geometry-hierarchy-map",
203  {
204  {"format-version", 0},
205  {"value-identifier", "an-identifier"},
206  },
207  },
208  };
209  BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
210  std::invalid_argument);
211 }
212 
214  ThingDecorator decorator;
215  Container c0 = {
216  {makeId(1), {2.0, -3}},
217  {makeId(2, 3), {-4.5, 5}},
218  {makeId(4, 5, 6), {7.25, -8}},
219  };
220  auto j = Converter("the-identifier").toJson(c0, &decorator);
221  auto c1 = Converter("the-identifier").fromJson(j);
222 
223  BOOST_CHECK_EQUAL(c0.size(), c1.size());
224  for (auto i = std::min(c0.size(), c1.size()); 0 < i--;) {
225  BOOST_CHECK_EQUAL(c0.idAt(i), c1.idAt(i));
226  BOOST_CHECK_EQUAL(c0.valueAt(i), c1.valueAt(i));
227  }
228 }
229 
231  // read json data from file
232  auto path = Acts::Test::getDataPath("geometry-hierarchy-map.json");
233  auto file = std::ifstream(path, std::ifstream::in | std::ifstream::binary);
234  BOOST_CHECK(file.good());
235  json j;
236  file >> j;
237  BOOST_CHECK(file.good());
238  // convert json to container
239  Container c = Converter("thing").fromJson(j);
240  // check container content
241  BOOST_CHECK(not c.empty());
242  BOOST_CHECK_EQUAL(c.size(), 4);
243  BOOST_CHECK_NE(c.find(makeId()), c.end());
244  BOOST_CHECK_NE(c.find(makeId(1, 2)), c.end());
245  BOOST_CHECK_NE(c.find(makeId(3)), c.end());
246  BOOST_CHECK_NE(c.find(makeId(3, 4)), c.end());
247 }
248 
249 BOOST_AUTO_TEST_SUITE_END()