Project
Loading...
Searching...
No Matches
test_Variants.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include <catch_amalgamated.hpp>
13#include "Framework/Variant.h"
16#include <sstream>
17#include <cstring>
18
19using namespace o2::framework;
20
22{
23 auto const& err = error_from_ref(ref);
24 return strcmp(err.what, "Mismatch between types") == 0;
25}
26
27TEST_CASE("VariantTest")
28{
29 std::ostringstream ss{};
30 Variant a(10);
31 REQUIRE(a.get<int>() == 10);
32 ss << a;
33 Variant b(10.1f);
34 REQUIRE(b.get<float>() == 10.1f);
35 ss << b;
36 Variant c(10.2);
37 REQUIRE(c.get<double>() == 10.2);
38 ss << c;
39 REQUIRE_THROWS_AS(a.get<char*>(), RuntimeErrorRef);
40 Variant d("foo");
41 ss << d;
42 REQUIRE(std::string(d.get<const char*>()) == "foo");
43 REQUIRE(std::string(d.get<std::string_view>()) == "foo");
44 REQUIRE(std::string(d.get<std::string>()) == "foo");
45
46 Variant e(true);
47 REQUIRE(e.get<bool>() == true);
48
49 Variant f(false);
50 REQUIRE(f.get<bool>() == false);
51
52 REQUIRE(ss.str() == "1010.110.2foo");
53 // Spotted valgrind error while deleting a vector of variants.
54 std::vector<Variant> vector{1, 1.2, 1.1f, "foo"};
55 Variant sa("foo");
56 Variant sb(sa); // Copy constructor
57 Variant sc(std::move(sa)); // Move constructor
58 Variant sd = sc; // Copy assignment
59
60 REQUIRE(std::string(sb.get<const char*>()) == "foo");
61 REQUIRE(std::string(sc.get<const char*>()) == "foo");
62 REQUIRE(std::string(sd.get<const char*>()) == "foo");
63 REQUIRE(sa.get<const char*>() == nullptr);
64
65 int iarr[] = {1, 2, 3, 4, 5};
66 float farr[] = {0.2, 0.3, 123.123, 123.123, 3.005e-5, 1.1e6};
67 std::vector<double> dvec = {0.1, 0.2, 0.4, 0.9, 1.3, 14.5, 123.234, 1.213e-20};
68 Variant viarr(iarr, 5);
69 Variant vfarr(farr, 6);
70 Variant vdvec(dvec);
71
72 REQUIRE(viarr.size() == 5);
73 REQUIRE(viarr.get<int*>() != iarr);
74 for (auto i = 0u; i < viarr.size(); ++i) {
75 REQUIRE(iarr[i] == (viarr.get<int*>())[i]);
76 }
77
78 REQUIRE(vfarr.size() == 6);
79 REQUIRE(vfarr.get<float*>() != farr);
80 for (auto i = 0u; i < vfarr.size(); ++i) {
81 REQUIRE(farr[i] == (vfarr.get<float*>())[i]);
82 }
83
84 REQUIRE(vdvec.size() == dvec.size());
85 REQUIRE(vdvec.get<double*>() != dvec.data());
86 for (auto i = 0u; i < dvec.size(); ++i) {
87 REQUIRE(dvec[i] == (vdvec.get<double*>())[i]);
88 }
89
90 Variant fb(vfarr); // Copy constructor
91 Variant fc(std::move(vfarr)); // Move constructor
92 Variant fd = fc; // Copy assignment
93
94 REQUIRE(vfarr.get<float*>() == nullptr);
95
96 REQUIRE(fb.get<float*>() != farr);
97 for (auto i = 0u; i < fb.size(); ++i) {
98 REQUIRE(farr[i] == (fb.get<float*>())[i]);
99 }
100 REQUIRE(fc.get<float*>() != farr);
101 for (auto i = 0u; i < fc.size(); ++i) {
102 REQUIRE(farr[i] == (fc.get<float*>())[i]);
103 }
104 REQUIRE(fd.get<float*>() != farr);
105 for (auto i = 0u; i < fd.size(); ++i) {
106 REQUIRE(farr[i] == (fd.get<float*>())[i]);
107 }
108
109 std::vector<std::string> vstrings{"s1", "s2", "s3"};
110 std::string strings[] = {"l1", "l2", "l3"};
111 Variant vstr(strings, 3);
112 Variant vvstr(vstrings);
113
114 REQUIRE(vstr.size() == 3);
115 REQUIRE(vvstr.size() == 3);
116 for (auto i = 0u; i < vstr.size(); ++i) {
117 REQUIRE(strings[i] == (vstr.get<std::string*>())[i]);
118 }
119 for (auto i = 0u; i < vvstr.size(); ++i) {
120 REQUIRE(vstrings[i] == (vvstr.get<std::string*>())[i]);
121 }
122
123 Variant vsc(vstr); // Copy constructor
124 Variant vsm(std::move(vstr)); // Move constructor
125 Variant vscc = vsm; // Copy assignment
126 for (auto i = 0u; i < vsm.size(); ++i) {
127 REQUIRE(strings[i] == (vsm.get<std::string*>())[i]);
128 }
129 for (auto i = 0u; i < vscc.size(); ++i) {
130 REQUIRE(strings[i] == (vscc.get<std::string*>())[i]);
131 }
132
133 Variant vsca(vvstr); // Copy constructor
134 Variant vsma(std::move(vvstr)); // Move constructor
135 Variant vscca = vsma; // Copy assignment
136 for (auto i = 0u; i < vsma.size(); ++i) {
137 REQUIRE(vstrings[i] == (vsma.get<std::string*>())[i]);
138 }
139 for (auto i = 0u; i < vscca.size(); ++i) {
140 REQUIRE(vstrings[i] == (vscca.get<std::string*>())[i]);
141 }
142
143 float m[3][4] = {{0.5, 0.25, 0.125, 0.0625}, {1.0, 2.0, 3.0, 4.0}, {2.0, 0.5, 4.0, 0.25}};
144 Array2D mm(&m[0][0], 3, 4);
145 Variant vmm(mm);
146 auto const& mmc = vmm.get<Array2D<float>>();
147 for (auto i = 0u; i < 3; ++i) {
148 for (auto j = 0u; j < 4; ++j) {
149 REQUIRE(mmc(i, j) == mm(i, j));
150 }
151 }
152
153 Variant vmmc(vmm); // Copy constructor
154 Variant vmmm(std::move(vmm)); // Move constructor
155 Variant vmma = vmmm; // Copy assignment
156 auto const& mmc2 = vmmc.get<Array2D<float>>();
157 for (auto i = 0u; i < 3; ++i) {
158 for (auto j = 0u; j < 4; ++j) {
159 REQUIRE(mmc2(i, j) == mm(i, j));
160 }
161 }
162 auto const& mmc3 = vmma.get<Array2D<float>>();
163 for (auto i = 0u; i < 3; ++i) {
164 for (auto j = 0u; j < 4; ++j) {
165 REQUIRE(mmc3(i, j) == mm(i, j));
166 }
167 }
168 std::stringstream ssm;
169 ssm << vmma;
170 REQUIRE(ssm.str() == "{\"values\":[[0.5,0.25,0.125,0.0625],[1.0,2.0,3.0,4.0],[2.0,0.5,4.0,0.25]]}");
171
172 LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}};
173 Variant vlaf(laf);
174 auto const& lafc = vlaf.get<LabeledArray<float>>();
175 for (auto i = 0u; i < 3; ++i) {
176 for (auto j = 0u; j < 4; ++j) {
177 REQUIRE(laf.get(i, j) == lafc.get(i, j));
178 }
179 }
180
181 Variant vlafc(vlaf); // Copy constructor
182 Variant vlafm(std::move(vlaf)); // Move constructor
183 Variant vlafa = vlafm; // Copy assignment
184 auto const& lafc2 = vlafc.get<LabeledArray<float>>();
185 for (auto i = 0U; i < 3; ++i) {
186 for (auto j = 0U; j < 4; ++j) {
187 REQUIRE(lafc2.get(i, j) == mm(i, j));
188 }
189 }
190 auto const& lafc3 = vlafa.get<LabeledArray<float>>();
191 for (auto i = 0U; i < 3; ++i) {
192 for (auto j = 0U; j < 4; ++j) {
193 REQUIRE(lafc3.get(i, j) == mm(i, j));
194 }
195 }
196
197 std::vector<Variant> collection;
198 collection.push_back(vlafc);
199 collection.push_back(vlafm);
200 collection.push_back(vlafa);
201}
202
203TEST_CASE("Array2DTest")
204{
205 float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}};
206 Array2D mm(&m[0][0], 3, 4);
207 for (auto i = 0U; i < 3; ++i) {
208 for (auto j = 0U; j < 4; ++j) {
209 REQUIRE(mm(i, j) == m[i][j]);
210 }
211 }
212 std::vector<float> v = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2};
213 Array2D mv(v, 3, 4);
214 for (auto i = 0U; i < 3; ++i) {
215 for (auto j = 0U; j < 4; ++j) {
216 REQUIRE(mm(i, j) == v[i * 4 + j]);
217 }
218 }
219 for (auto i = 0U; i < 3; ++i) {
220 auto const& vv = mm[i];
221 for (auto j = 0u; j < 4; ++j) {
222 REQUIRE(vv[j] == mm(i, j));
223 }
224 }
225 std::vector<std::string> s = {"one", "two", "three", "four"};
226 Array2D ms(s, 4, 1);
227 for (auto i = 0U; i < 4; ++i) {
228 REQUIRE(ms(i, 0) == s[i]);
229 }
230}
231
232TEST_CASE("Array2DAssignmentTest")
233{
234 std::vector<int> v = {1, 2, 3, 4, 5, 6};
235 Array2D<int> source(v, 2, 3);
236
237 // copy assignment to an array of different shape makes an independent deep copy
238 Array2D<int> copied(std::vector<int>{7}, 1, 1);
239 copied = source;
240 REQUIRE(copied.rows == 2);
241 REQUIRE(copied.cols == 3);
242 REQUIRE(copied.data != source.data);
243 source[0][0] = 42;
244 REQUIRE(copied(0, 0) == 1);
245 for (auto i = 1U; i < 6; ++i) {
246 REQUIRE(copied(i / 3, i % 3) == v[i]);
247 }
248
249 // self copy assignment keeps the contents
250 auto& self = copied;
251 copied = self;
252 REQUIRE(copied.rows == 2);
253 REQUIRE(copied.cols == 3);
254 REQUIRE(copied(1, 2) == 6);
255
256 // move assignment takes over the buffer and empties the source
257 auto* buffer = copied.data;
258 Array2D<int> moved(std::vector<int>{7, 8}, 1, 2);
259 moved = std::move(copied);
260 REQUIRE(moved.data == buffer);
261 REQUIRE(moved.rows == 2);
262 REQUIRE(moved.cols == 3);
263 REQUIRE(moved(1, 2) == 6);
264 REQUIRE(copied.data == nullptr);
265 REQUIRE(copied.rows == 0);
266 REQUIRE(copied.cols == 0);
267
268 // self move assignment keeps the contents
269 auto& selfMoved = moved;
270 moved = std::move(selfMoved);
271 REQUIRE(moved.data == buffer);
272 REQUIRE(moved(1, 2) == 6);
273
274 // assigning an empty array releases the old buffer and leaves an empty array
275 moved = Array2D<int>{};
276 REQUIRE(moved.data == nullptr);
277 REQUIRE(moved.rows == 0);
278 REQUIRE(moved.cols == 0);
279
280 // strings are copied element by element
281 std::vector<std::string> s = {"one", "two"};
282 Array2D<std::string> ms(s, 2, 1);
284 msc = ms;
285 ms[0][0] = "changed";
286 REQUIRE(msc(0, 0) == "one");
287 REQUIRE(msc(1, 0) == "two");
288}
289
290TEST_CASE("VariantLifecycleTest")
291{
292 float m[2][3] = {{1, 2, 3}, {4, 5, 6}};
293 LabeledArray<float> laf{&m[0][0], 2, 3, {"r1", "r2"}, {"c1", "c2", "c3"}};
294 std::vector<std::string> vs{"s1", "s2", "s3"};
295 auto checkLabeled = [&](Variant const& v) {
296 REQUIRE(v.type() == VariantType::LabeledArrayFloat);
297 auto la = v.get<LabeledArray<float>>();
298 REQUIRE(la.rows() == 2);
299 REQUIRE(la.cols() == 3);
300 REQUIRE(la.get("r2", "c3") == 6);
301 REQUIRE(la.getLabelsRows() == std::vector<std::string>{"r1", "r2"});
302 };
303
304 Variant vl(laf);
305 // copies are independent and survive the destruction of the original
306 auto* copy = new Variant(vl);
307 Variant moved(std::move(*copy));
308 delete copy;
309 checkLabeled(vl);
310 checkLabeled(moved);
311
312 // assignment across types releases the previous content
313 Variant vstr("a string");
314 vstr = vl;
315 checkLabeled(vstr);
316 vstr = Variant("back to a string");
317 REQUIRE(vstr.type() == VariantType::String);
318 REQUIRE(std::string(vstr.get<const char*>()) == "back to a string");
319 vstr = std::move(moved);
320 checkLabeled(vstr);
321 Variant vvs(vs);
322 vstr = vvs;
323 REQUIRE(vstr.get<std::vector<std::string>>() == vs);
324
325 // self assignment keeps the content
326 auto& self = vl;
327 vl = self;
328 checkLabeled(vl);
329 vl = std::move(self);
330 checkLabeled(vl);
331
332 // moving a string array leaves a valid moved-from Variant behind
333 Variant vvsMoved(std::move(vvs));
334 REQUIRE(vvsMoved.get<std::vector<std::string>>() == vs);
335 vvs = vvsMoved;
336 REQUIRE(vvs.get<std::vector<std::string>>() == vs);
337
338 // reallocation of a container moves the Variants around
339 std::vector<Variant> collection;
340 for (auto i = 0; i < 20; ++i) {
341 collection.emplace_back(laf);
342 collection.emplace_back(Array2D<float>{&m[0][0], 2, 3});
343 collection.emplace_back(vs);
344 collection.emplace_back("a string");
345 }
346 std::vector<Variant> collectionCopy = collection;
347 collection.clear();
348 for (auto i = 0U; i < collectionCopy.size(); i += 4) {
349 checkLabeled(collectionCopy[i]);
350 REQUIRE(collectionCopy[i + 1].get<Array2D<float>>()(1, 2) == 6);
351 REQUIRE(collectionCopy[i + 2].get<std::vector<std::string>>() == vs);
352 REQUIRE(std::string(collectionCopy[i + 3].get<const char*>()) == "a string");
353 }
354
355 // a Variant created with only a type can be copied and destroyed
356 Variant typed(VariantType::LabeledArrayFloat);
357 Variant typedCopy(typed);
358 REQUIRE(typedCopy.get<LabeledArray<float>>().rows() == 0);
359 Variant typedString(VariantType::String);
360 Variant typedStringCopy(typedString);
361 REQUIRE(typedStringCopy.get<const char*>() == nullptr);
362
363 // set replaces the content and the type
364 Variant vset(1);
365 vset.set(laf);
366 checkLabeled(vset);
367 vset.set(vs);
368 REQUIRE(vset.type() == VariantType::ArrayString);
369 REQUIRE(vset.get<std::vector<std::string>>() == vs);
370}
371
372TEST_CASE("LabeledArrayTest")
373{
374 float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}};
375 std::string mS[3][4] = {{"a", "b", "c", "d"}, {"e", "f", "g", "h"}, {"i", "l", "m", "n"}};
376 std::string xl[] = {"c1", "c2", "c3", "c4"};
377 std::string yl[] = {"r1", "r2", "r3"};
378 LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}};
379 LabeledArray<std::string> las{&mS[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}};
380 for (auto i = 0u; i < 3; ++i) {
381 for (auto j = 0u; j < 4; ++j) {
382 REQUIRE(laf.get(yl[i].c_str(), xl[j].c_str()) == laf.get(i, j));
383 REQUIRE(laf.get(i, xl[j].c_str()) == laf.get(i, j));
384 REQUIRE(laf.get(yl[i].c_str(), j) == laf.get(i, j));
385
386 REQUIRE(las.get(yl[i].c_str(), xl[j].c_str()) == las.get(i, j));
387 REQUIRE(las.get(i, xl[j].c_str()) == las.get(i, j));
388 REQUIRE(las.get(yl[i].c_str(), j) == las.get(i, j));
389 }
390 }
391}
392
393TEST_CASE("VariantTreeConversionsTest")
394{
395 std::vector<std::string> vstrings{"0 1", "0 2", "0 3"};
396 Variant vvstr(vstrings);
397
398 auto tree = vectorToBranch(vvstr.get<std::string*>(), vvstr.size());
399 auto fromTree = vectorFromBranch<std::string>(tree);
400 auto v = Variant(fromTree);
401
402 REQUIRE(vvstr.size() == vstrings.size());
403 REQUIRE(v.size() == vstrings.size());
404 for (auto i = 0U; i < vvstr.size(); ++i) {
405 REQUIRE(vvstr.get<std::string*>()[i] == v.get<std::string*>()[i]);
406 }
407}
408
409TEST_CASE("VariantJSONConversionsTest")
410{
411 int iarr[] = {1, 2, 3, 4, 5};
412 Variant viarr(iarr, 5);
413 std::stringstream os;
414 VariantJSONHelpers::write(os, viarr);
415
416 std::stringstream is;
417 is.str(os.str());
418 auto v = VariantJSONHelpers::read<VariantType::ArrayInt>(is);
419 for (auto i = 0u; i < viarr.size(); ++i) {
420 REQUIRE(v.get<int*>()[i] == viarr.get<int*>()[i]);
421 }
422 os.str("");
423
424 float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}};
425 Array2D mm(&m[0][0], 3, 4);
426 Variant vmm(mm);
427 std::stringstream osm;
429
430 std::stringstream ism;
431 ism.str(osm.str());
432 auto vm = VariantJSONHelpers::read<VariantType::Array2DFloat>(ism);
433
434 for (auto i = 0u; i < mm.rows; ++i) {
435 for (auto j = 0u; j < mm.cols; ++j) {
436 REQUIRE(vmm.get<Array2D<float>>()(i, j) == vm.get<Array2D<float>>()(i, j));
437 }
438 }
439
440 LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}};
441 Variant vlaf(laf);
442 std::stringstream osl;
443 VariantJSONHelpers::write(osl, vlaf);
444
445 std::stringstream isl;
446 isl.str(osl.str());
447 auto vlafc = VariantJSONHelpers::read<VariantType::LabeledArrayFloat>(isl);
448
449 for (auto i = 0u; i < vlafc.get<LabeledArray<float>>().rows(); ++i) {
450 for (auto j = 0u; j < vlafc.get<LabeledArray<float>>().cols(); ++j) {
451 REQUIRE(vlaf.get<LabeledArray<float>>().get(i, j) == vlafc.get<LabeledArray<float>>().get(i, j));
452 }
453 }
454
455 std::string mS[3][4] = {{"a", "b", "c", "d"}, {"e", "f", "g", "h"}, {"i", "l", "m", "n"}};
456 LabeledArray<std::string> las{&mS[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}};
457 Variant vms(las);
458 std::stringstream ossl;
459 VariantJSONHelpers::write(ossl, vms);
460
461 std::stringstream issl;
462 issl.str(ossl.str());
463 auto vmsa = VariantJSONHelpers::read<VariantType::LabeledArrayString>(issl);
464
465 for (auto i = 0U; i < vmsa.get<LabeledArray<std::string>>().rows(); ++i) {
466 for (auto j = 0U; j < vmsa.get<LabeledArray<std::string>>().cols(); ++j) {
467 REQUIRE(vmsa.get<LabeledArray<std::string>>().get(i, j) == vms.get<LabeledArray<std::string>>().get(i, j));
468 }
469 }
470
471 std::vector<std::string> vstrings{"myoption_one", "myoption_two"};
472 Variant vvstr(vstrings);
473 REQUIRE(vvstr.size() == 2);
474 std::stringstream osal;
475 osal << vvstr;
476
477 std::stringstream isal;
478 isal.str(osal.str());
479 auto vvstra = VariantJSONHelpers::read<VariantType::ArrayString>(isal);
480
481 REQUIRE(vvstr.size() == vvstra.size());
482 for (auto i = 0U; i < vstrings.size(); ++i) {
483 REQUIRE(vstrings[i] == vvstra.get<std::string*>()[i]);
484 }
485}
486
487TEST_CASE("VariantThrowing")
488{
489 Variant a("true");
490 REQUIRE_THROWS_AS(a.get<int>(), o2::framework::RuntimeErrorRef);
491 try {
492 a.get<int>();
493 } catch (RuntimeErrorRef& ref) {
495 REQUIRE(error.what == std::string("Variant::get: Mismatch between types 4 0."));
496 }
497}
498
499// A Variant can be created from a vector only by copying its content
500static_assert(!std::is_constructible_v<Variant, std::vector<int>>);
501static_assert(!std::is_constructible_v<Variant, std::vector<float>>);
502static_assert(!std::is_constructible_v<Variant, std::vector<double>>);
503static_assert(!std::is_constructible_v<Variant, std::vector<bool>>);
504static_assert(!std::is_constructible_v<Variant, std::vector<std::string>>);
505// assignment from a temporary vector copies it
506static_assert(std::is_assignable_v<Variant&, std::vector<int>>);
507static_assert(std::is_assignable_v<Variant&, std::vector<std::string>>);
508static_assert(std::is_constructible_v<Variant, std::vector<int>&>);
509static_assert(std::is_constructible_v<Variant, std::vector<int> const&>);
510static_assert(std::is_constructible_v<Variant, std::vector<std::string> const&>);
511static_assert(std::is_assignable_v<Variant&, std::vector<int> const&>);
512
513namespace
514{
515template <typename T>
516void checkVectorCopy(VariantType type, std::vector<T> source)
517{
518 auto check = [&](Variant const& v, std::vector<T> const& from) {
519 REQUIRE(v.type() == type);
520 REQUIRE(v.size() == from.size());
521 auto const* stored = v.get<T*>();
522 REQUIRE(stored != from.data());
523 for (auto i = 0U; i < from.size(); ++i) {
524 REQUIRE(stored[i] == from[i]);
525 }
526 };
527 std::vector<T> const constSource = source;
528 Variant fromConst(constSource);
529 check(fromConst, constSource);
530
531 Variant fromMutable(source);
532 check(fromMutable, source);
533 // the Variant owns a copy, unaffected by later changes of the source
534 auto const original = source;
535 source[0] = source.back();
536 source.push_back(source[0]);
537 check(fromMutable, original);
538}
539} // namespace
540
541TEST_CASE("VariantFromVectorTest")
542{
543 checkVectorCopy<int>(VariantType::ArrayInt, {1, 2, 3, 4});
544 checkVectorCopy<float>(VariantType::ArrayFloat, {0.5f, 1.5f, 2.5f});
545 checkVectorCopy<double>(VariantType::ArrayDouble, {1e-3, 1e3});
546 checkVectorCopy<std::string>(VariantType::ArrayString, {"a", "bb", "ccc"});
547
548 // assignment from a vector copies as well
549 std::vector<int> vi{7, 8, 9};
550 Variant v(1);
551 v = vi;
552 REQUIRE(v.type() == VariantType::ArrayInt);
553 REQUIRE(v.size() == 3);
554 REQUIRE(v.get<int*>() != vi.data());
555 REQUIRE(v.get<int*>()[2] == 9);
556 // also from a temporary
557 auto makeStrings = []() { return std::vector<std::string>{"x", "y"}; };
558 v = makeStrings();
559 REQUIRE(v.type() == VariantType::ArrayString);
560 REQUIRE(v.size() == 2);
561 REQUIRE(v.get<std::string*>()[1] == "y");
562 v = std::vector<double>{1.5, 2.5, 3.5};
563 REQUIRE(v.type() == VariantType::ArrayDouble);
564 REQUIRE(v.size() == 3);
565 REQUIRE(v.get<double*>()[2] == 3.5);
566
567 // a Variant created from a const vector round-trips through JSON
568 std::vector<double> const vd{0.25, 0.5, 0.75};
569 Variant vdv(vd);
570 std::stringstream is(vdv.asString());
571 auto read = VariantJSONHelpers::read<VariantType::ArrayDouble>(is);
572 REQUIRE(read.size() == vd.size());
573 for (auto i = 0U; i < vd.size(); ++i) {
574 REQUIRE(read.get<double*>()[i] == vd[i]);
575 }
576}
577
578namespace
579{
580template <VariantType V, typename T>
581void checkLabeledArrayStringRoundTrip(LabeledArray<T> const& la)
582{
583 Variant v(la);
584 auto str = v.asString();
585 REQUIRE(str.find("undefined") == std::string::npos);
586 std::stringstream is(str);
587 auto vr = VariantJSONHelpers::read<V>(is);
588 REQUIRE(vr.type() == V);
589 auto lar = vr.template get<LabeledArray<T>>();
590 REQUIRE(lar.rows() == la.rows());
591 REQUIRE(lar.cols() == la.cols());
592 REQUIRE(lar.getLabelsRows() == la.getLabelsRows());
593 REQUIRE(lar.getLabelsCols() == la.getLabelsCols());
594 for (auto i = 0U; i < la.rows(); ++i) {
595 for (auto j = 0U; j < la.cols(); ++j) {
596 REQUIRE(lar.get(i, j) == la.get(i, j));
597 }
598 }
599}
600} // namespace
601
602TEST_CASE("LabeledArrayAsStringTest")
603{
604 int mi[2][2] = {{1, 2}, {3, 4}};
605 float mf[2][3] = {{0.5, 0.25, 0.125}, {1, 2, 3}};
606 double md[1][2] = {{1e-3, 1e10}};
607 std::string ms[2][1] = {{"a"}, {"b c"}};
608
609 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayInt>(LabeledArray<int>{&mi[0][0], 2, 2, {"r1", "r2"}, {"c1", "c2"}});
610 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayFloat>(LabeledArray<float>{&mf[0][0], 2, 3, {"r1", "r2"}, {"c1", "c2", "c3"}});
611 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayDouble>(LabeledArray<double>{&md[0][0], 1, 2, {"r1"}, {"c1", "c2"}});
612 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayString>(LabeledArray<std::string>{&ms[0][0], 2, 1, {"r1", "r2"}, {"c1"}});
613 // without labels
614 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayInt>(LabeledArray<int>{&mi[0][0], 2, 2});
615 // labels which need escaping in JSON
616 checkLabeledArrayStringRoundTrip<VariantType::LabeledArrayFloat>(LabeledArray<float>{&mf[0][0], 2, 3, {"row \"one\"", "row\\two"}, {"c 1", "c,2", "c:3"}});
617
618 Variant v(LabeledArray<int>{&mi[0][0], 2, 2, {"r1", "r2"}, {"c1", "c2"}});
619 REQUIRE(v.asString() == R"({"labels_rows":["r1","r2"],"labels_cols":["c1","c2"],"values":[[1,2],[3,4]]})");
620}
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
uint32_t cols
T get(uint32_t y, uint32_t x) const
Definition Array2D.h:209
Variant for configuration parameter storage. Owns stored data.
Definition Variant.h:319
std::string asString() const
Definition Variant.cxx:87
void set(T value)
Definition Variant.h:395
size_t size() const
Definition Variant.h:415
VariantType type() const
Definition Variant.h:414
const GLfloat * m
Definition glcorearb.h:4066
GLsizei const GLchar *const * strings
Definition glcorearb.h:1907
GLuint buffer
Definition glcorearb.h:655
const GLdouble * v
Definition glcorearb.h:832
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint ref
Definition glcorearb.h:291
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
void check(const std::vector< std::string > &arguments, const std::vector< ConfigParamSpec > &workflowOptions, const std::vector< DeviceSpec > &deviceSpecs, CheckMatrix &matrix)
TEST_CASE("test_prepareArguments")
RuntimeError & error_from_ref(RuntimeErrorRef)
boost::property_tree::ptree vectorToBranch(T const *values, size_t size)
auto getLabelsRows() const
Definition Array2D.h:157
auto getLabelsCols() const
Definition Array2D.h:162
static void write(std::ostream &o, Variant const &v)
bool unknown_type(RuntimeErrorRef const &ref)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< ReadoutWindowData > rows
const std::string str