quantities_test.cc
Go to the documentation of this file.
1 /**
2  * @file test/Utilities/quantities_test.cc
3  * @brief Unit test for `quantities.h` header
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date October 30, 2018
6  * @see lardataalg/Utilities/quantities.h
7  *
8  */
9 
10 // Boost libraries
11 #define BOOST_TEST_MODULE ( quantities_test )
12 #include <boost/test/unit_test.hpp>
13 
14 // LArSoft libraries
17 #include "larcorealg/CoreUtils/StdUtils.h" // util::to_string()
19 
20 // C/C++ standard libraries
21 #include <type_traits> // std::decay_t<>
22 
24 
25 // -----------------------------------------------------------------------------
26 // --- implementation detail tests
27 
28 template <typename> struct EmptyClass {};
29 
30 static_assert(!util::quantities::concepts::details::has_unit_v<double>);
33  );
36  );
39  );
42  );
45  );
46 
47 static_assert(!util::quantities::concepts::details::is_quantity_v<double>);
50  );
53  );
56  );
59  );
62  );
63 
64 static_assert(!util::quantities::concepts::details::has_quantity_v<double>);
67  );
70  );
73  );
76  );
79  );
80 
81 static_assert( util::quantities::second::isCompatibleValue<double>());
82 static_assert( util::quantities::second::isCompatibleValue<float>());
83 static_assert( util::quantities::second::isCompatibleValue<int>());
86  );
89  );
91 
92 static_assert( util::quantities::second::hasCompatibleValue<double>());
93 static_assert( util::quantities::second::hasCompatibleValue<float>());
94 static_assert( util::quantities::second::hasCompatibleValue<int>());
97  );
100  );
102  <EmptyClass<int>>()
103  );
104 
105 
106 // -----------------------------------------------------------------------------
107 // --- Quantity tests
108 // -----------------------------------------------------------------------------
109 static_assert
110  (util::quantities::microsecond::sameBaseUnitAs<util::quantities::second>());
113  );
114 static_assert
115  (!util::quantities::microsecond::sameUnitAs<util::quantities::second>());
116 
117 
118 // -----------------------------------------------------------------------------
120 
121  using namespace util::quantities::time_literals;
122 
124 
125  BOOST_TEST(t == -4_us); // just to be safe
126  static_assert(
127  std::is_same<decltype(+t), util::quantities::microseconds>(),
128  "Positive sign converts to a different type!"
129  );
130  BOOST_TEST(+t == -4_us);
131  static_assert(
132  std::is_same<decltype(-t), util::quantities::microseconds>(),
133  "Negative sign converts to a different type!"
134  );
135  BOOST_TEST(-t == 4_us);
136  static_assert(
137  std::is_same<decltype(t.abs()), util::quantities::microseconds>(),
138  "Negative sign converts to a different type!"
139  );
140  BOOST_TEST(t.abs() == 4.0_us);
141 
142 } // test_quantities_sign()
143 
144 
145 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147 
148  using namespace util::quantities::time_literals;
149 
150  //
151  // conversions to other scales
152  //
153  util::quantities::seconds t_s { 7.0 };
154 
155  BOOST_TEST(t_s.value() == 7.0);
156 
158  t_us = t_s;
159  BOOST_TEST(t_us == 7'000'000.0_us);
160 
162  BOOST_TEST(t == 7.0_s);
163 
164  static_assert(std::is_same<
167  >());
168  BOOST_TEST
169  (t.convertInto<util::quantities::microseconds>() == 7'000'000_us);
170 
171 } // test_quantities_conversions()
172 
173 
174 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176  //
177  // comparisons between quantities
178  //
179  util::quantities::microseconds t_us { 7.0 };
180  BOOST_TEST( t_us == t_us);
181  BOOST_TEST(!(t_us != t_us));
182  BOOST_TEST( (t_us >= t_us));
183  BOOST_TEST( (t_us <= t_us));
184  BOOST_TEST(!(t_us > t_us));
185  BOOST_TEST(!(t_us < t_us));
186 
187  util::quantities::nanoseconds t_ns { 7.0 };
188  BOOST_TEST( t_us != t_ns);
189  BOOST_TEST(!(t_us == t_ns));
190  BOOST_TEST( (t_us != t_ns));
191  BOOST_TEST( (t_us >= t_ns));
192  BOOST_TEST(!(t_us <= t_ns));
193  BOOST_TEST( (t_us > t_ns));
194  BOOST_TEST(!(t_us < t_ns));
195 
196  util::quantities::nanoseconds t2_ns { 7000.0 };
197  BOOST_TEST( t_us == t2_ns);
198  BOOST_TEST(!(t_us != t2_ns));
199  BOOST_TEST( (t_us >= t2_ns));
200  BOOST_TEST( (t_us <= t2_ns));
201  BOOST_TEST(!(t_us > t2_ns));
202  BOOST_TEST(!(t_us < t2_ns));
203 
204  BOOST_TEST( t_ns != t2_ns);
205  BOOST_TEST(!(t_ns == t2_ns));
206  BOOST_TEST( (t_ns != t2_ns));
207  BOOST_TEST(!(t_ns >= t2_ns));
208  BOOST_TEST( (t_ns <= t2_ns));
209  BOOST_TEST(!(t_ns > t2_ns));
210  BOOST_TEST( (t_ns < t2_ns));
211 
212 } // test_quantities_conversions()
213 
214 
215 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217  //
218  // multiplication and division by scalar
219  //
220 
221  using namespace util::quantities::time_literals;
222 
223 // 5_s * 6_s; // ERROR
224 // 5_s * 6_us; // ERROR
225 
226  util::quantities::seconds const t { 3.0 };
227  auto const twice_t = 2.0 * t;
228  static_assert(
229  std::is_same
230  <std::decay_t<decltype(twice_t)>, util::quantities::seconds>(),
231  "Multiplication by a scalar converts to a different type!"
232  );
233  BOOST_TEST(twice_t == 6.0_s);
234 
235  auto const t_twice = t * 2.0;
236  static_assert(
237  std::is_same
238  <std::decay_t<decltype(t_twice)>, util::quantities::seconds>(),
239  "Multiplication by a scalar converts to a different type!"
240  );
241  BOOST_TEST(twice_t == 6.0_s);
242 
243  static_assert(
244  std::is_same<decltype(twice_t / 2.0), util::quantities::seconds>(),
245  "Division by a scalar converts to a different type!"
246  );
247  BOOST_TEST(twice_t / 2.0 == 3.0_s);
248 
249  static_assert(
250  std::is_same<decltype(twice_t / t), double>(),
251  "Division by a scalar is not the base type!"
252  );
253  BOOST_TEST(twice_t / t == 2.0);
254 
255  static_assert(
256  std::is_same<decltype(t / 300_us), double>(),
257  "Division by a scalar is not the base type!"
258  );
259  BOOST_TEST(t / 300_us == 10'000.0);
260 
261 } // test_quantities_multiply_scalar()
262 
263 
264 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
265 void test_quantities_addition() {
266 
267  using namespace util::quantities::time_literals;
268 
269  //
270  // sum and difference
271  //
272 
273 // 5_s + 700_ms; // ERROR!
274 // 5_s + 0.7; // ERROR!
275 
276 
277  static_assert(
278  std::is_same<std::decay_t<decltype(45_s + 5_s)>, util::quantities::seconds>(),
279  "Addition converts to a different type!"
280  );
281  BOOST_TEST(45_s + 5_s == 50_s);
282 
283  static_assert(
284  std::is_same<decltype(5_s - 55_s), util::quantities::seconds>(),
285  "Subtraction converts to a different type!"
286  );
287  BOOST_TEST(5_s - 55_s == -50_s);
288 
289 
290  constexpr util::quantities::seconds t = 45_s;
291  static_assert(
292  std::is_same
293  <std::decay_t<decltype(t.plus(5000_ms))>, util::quantities::seconds>(),
294  "Addition converts to a different type!"
295  );
296  BOOST_TEST(t.plus(5000_ms) == 50_s);
297  BOOST_TEST(t == 45_s);
298 
299  static_assert(
300  std::is_same<decltype(t.minus(55000_ms)), util::quantities::seconds>(),
301  "Subtraction converts to a different type!"
302  );
303  BOOST_TEST(t.minus(55000_ms) == -10_s);
304  BOOST_TEST(t == 45_s);
305 
306 
307 } // test_quantities_addition()
308 
309 
310 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
311 void test_quantities_increment() {
312 
313  using namespace util::quantities::time_literals;
314 
315  //
316  // increment and decrement by a quantity
317  //
318  util::quantities::seconds t { 0.05 };
319 
320  t += 0.05_s;
321  static_assert(
322  std::is_same<decltype(t += 0.05_s), util::quantities::seconds&>(),
323  "Increment converts to a different type!"
324  );
325  BOOST_TEST(t == 0.1_s);
326 
327  t -= 0.05_s;
328  static_assert(
329  std::is_same<decltype(t -= 0.05_s), util::quantities::seconds&>(),
330  "Decrement converts to a different type!"
331  );
332  BOOST_TEST(t == 0.05_s);
333 
334  t += 50_ms;
335  static_assert(
336  std::is_same<decltype(t += 50_ms), util::quantities::seconds&>(),
337  "Increment converts to a different type!"
338  );
339  BOOST_TEST(t == 0.1_s);
340 
341  t -= 50_ms;
342  static_assert(
343  std::is_same<decltype(t -= 50_ms), util::quantities::seconds&>(),
344  "Decrement converts to a different type!"
345  );
346  BOOST_TEST(t == 0.05_s);
347 
348 } // test_quantities_multiply_scalar()
349 
350 
351 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
352 void test_quantities_scale() {
353 
354  using namespace util::quantities::time_literals;
355 
356  util::quantities::microseconds t { 11.0 };
357  //
358  // scaling
359  //
360  t *= 2.0;
361  static_assert(
362  std::is_same<decltype(t *= 2.0), util::quantities::microseconds&>(),
363  "Scaling converts to a different type!"
364  );
365  BOOST_TEST(t == 22.0_us);
366 
367  t /= 2.0;
368  static_assert(
369  std::is_same<decltype(t /= 2.0), util::quantities::microseconds&>(),
370  "Scaling (division) converts to a different type!"
371  );
372  BOOST_TEST(t == 11.0_us);
373 
374 } // test_quantities_scale()
375 
376 
377 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
378 void test_quantities_literals() {
379 
380  using namespace util::quantities::time_literals;
381 
382  constexpr util::quantities::second t1 = 7_s;
383  static_assert(t1.value() == 7.0, "Literal assignment failed.");
384 
385  constexpr util::quantities::microsecond t2 = 7_s;
386  static_assert(t2.value() == 7000000.0, "Literal conversion failed.");
387 
388  util::quantities::microsecond t3;
389  t3 = 7.0_s;
390  BOOST_TEST(t3.value() == 7000000.0);
391  BOOST_TEST(t3 == 7000000_us);
392 
393  static_assert(7000000_us == 7_s, "Literal conversion failed.");
394 
395 } // test_quantities_literals()
396 
397 
398 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
399 void test_quantities() {
400 
401  using namespace util::quantities::time_literals;
402 
403  // ---------------------------------------------------------------------------
404  // default constructor
405  //
406 // BOOST_TEST_CHECKPOINT("Default constructor");
407  util::quantities::microseconds t1; // can't do much with this except assigning
408 
409  // ---------------------------------------------------------------------------
410  // assignment
411  //
412 // t1 = 4.0; // error!
414  BOOST_TEST(util::to_string(t1.unit()) == "us");
415  BOOST_TEST(util::to_string(t1) == "4.000000 us");
416  BOOST_TEST(t1.value() == 4.0);
417 
418  // ---------------------------------------------------------------------------
419  // value constructor
420  //
422  BOOST_TEST(t2 == 7.0_us);
423 
424 
425  // ---------------------------------------------------------------------------
426 
427 } // test_quantities()
428 
429 
430 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
432 
433  using namespace util::quantities::time_literals;
434 
435  constexpr util::quantities::microseconds t1 { 10.0 };
436  constexpr util::quantities::microseconds t2 { 20.0 };
437  constexpr util::quantities::nanoseconds t_ns { 500.0 };
438  constexpr util::quantities::nanoseconds t1_ns = t1; // convert
439 
440  static_assert(t1.value() == 10.0, "value()");
441  static_assert(double(t1) == 10.0, "explicit conversion to plain number");
442  static_assert(+t1 == 10_us, "unary +");
443  static_assert(-t1 == -10_us, "unary -");
444  static_assert(t1.abs() == 10_us, "abs()");
445 
446  static_assert( (t1 == t1 ), "comparison");
447  static_assert(!(t1 == t2 ), "comparison");
448  static_assert(!(t1 == t_ns ), "comparison");
449  static_assert( (t1 == t1_ns), "comparison"); // rounding?
450 
451  static_assert(!(t1 != t1 ), "comparison");
452  static_assert( (t1 != t2 ), "comparison");
453  static_assert( (t1 != t_ns ), "comparison");
454  static_assert(!(t1 != t1_ns), "comparison"); // rounding?
455 
456  static_assert( (t1 >= t1 ), "comparison");
457  static_assert(!(t1 >= t2 ), "comparison");
458  static_assert( (t1 >= t_ns ), "comparison");
459  static_assert( (t1 >= t1_ns), "comparison"); // rounding?
460 
461  static_assert(!(t1 < t1 ), "comparison");
462  static_assert( (t1 < t2 ), "comparison");
463  static_assert(!(t1 < t_ns ), "comparison");
464  static_assert(!(t1 < t1_ns), "comparison"); // rounding?
465 
466  static_assert( (t1 <= t1 ), "comparison");
467  static_assert( (t1 <= t2 ), "comparison");
468  static_assert(!(t1 <= t_ns ), "comparison");
469  static_assert( (t1 <= t1_ns), "comparison"); // rounding?
470 
471  static_assert(!(t1 > t1 ), "comparison");
472  static_assert(!(t1 > t2 ), "comparison");
473  static_assert( (t1 > t_ns ), "comparison");
474  static_assert(!(t1 > t1_ns), "comparison"); // rounding?
475 
476  static_assert(t1 * 2.0 == 20.0_us, "scaling");
477  static_assert(2.0 * t1 == 20.0_us, "scaling");
478  static_assert(t1 / 2.0 == 5.0_us, "scaling");
479 
480 
481  // ---------------------------------------------------------------------------
482 
483 } // test_constexpr_operations()
484 
485 
486 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
488 
489  using namespace util::quantities::time_literals;
491 
492  constexpr auto expected = 3.0_ms;
493  static_assert(std::is_same<std::decay_t<decltype(expected)>, milliseconds>());
494 
495  auto q = util::quantities::makeQuantity<milliseconds>("3.0 ms");
496  static_assert(std::is_same<std::decay_t<decltype(q)>, milliseconds>());
497 
498  auto const tol = 1e-7% tolerance();
499  BOOST_TEST(q.value() == expected.value(), tol);
500 
501  q = util::quantities::makeQuantity<milliseconds>(" 3.0ms ");
502  BOOST_TEST(q.value() == expected.value(), tol);
503 
504  q = util::quantities::makeQuantity<milliseconds>("3ms");
505  BOOST_TEST(q.value() == expected.value(), tol);
506 
507  q = util::quantities::makeQuantity<milliseconds>("3000 us");
508  BOOST_TEST(q.value() == expected.value(), tol);
509 
510  q = util::quantities::makeQuantity<milliseconds>("0.03e+2 ms");
511  BOOST_TEST(q.value() == expected.value(), tol);
512 
513  q = util::quantities::makeQuantity<milliseconds>("+3ms");
514  BOOST_TEST(q.value() == expected.value(), tol);
515 
516  q = util::quantities::makeQuantity<milliseconds>("+3E-3s");
517  BOOST_TEST(q.value() == expected.value(), tol);
518 
519  q = util::quantities::makeQuantity<milliseconds>("3", true);
520  BOOST_TEST(q.value() == expected.value(), tol);
521 
522  q = util::quantities::makeQuantity<milliseconds>("3.0", true);
523  BOOST_TEST(q.value() == expected.value(), tol);
524 
525  q = util::quantities::makeQuantity<milliseconds>("30e-1", true);
526  BOOST_TEST(q.value() == expected.value(), tol);
527 
528  BOOST_CHECK_THROW(util::quantities::makeQuantity<milliseconds>("3"),
530 
531  BOOST_CHECK_THROW(util::quantities::makeQuantity<milliseconds>("3 kg"),
533 
534  BOOST_CHECK_THROW(util::quantities::makeQuantity<milliseconds>("3 dumbs"),
536 
537  BOOST_CHECK_THROW(util::quantities::makeQuantity<milliseconds>("three ms"),
539 
540  BOOST_CHECK_THROW(util::quantities::makeQuantity<milliseconds>("3.zero ms"),
542 
543 } // test_makeQuantity()
544 
545 
546 // -----------------------------------------------------------------------------
547 // BEGIN Test cases -----------------------------------------------------------
548 // -----------------------------------------------------------------------------
549 BOOST_AUTO_TEST_CASE(quantities_testcase) {
550 
551  test_quantities();
559 
561 
563 
565 
566 } // BOOST_AUTO_TEST_CASE(quantities_testcase)
567 
568 // -----------------------------------------------------------------------------
569 // END Test cases -------------------------------------------------------------
570 // -----------------------------------------------------------------------------
void test_makeQuantity()
const char expected[]
Definition: Exception_t.cc:22
auto const tol
Definition: SurfXYZTest.cc:16
auto const tolerance
void test_quantities_increment()
constexpr bool is_quantity_v
Trait: true if Q is a Quantity specialization.
Definition: quantities.h:268
static constexpr bool isCompatibleValue()
Returns whether U is a value type compatible with value_t.
Definition: quantities.h:786
void test_quantities_addition()
void test_quantities_scale()
String representing a quantity has spurious characters after the number.
Definition: quantities.h:1108
void test_quantities_conversions()
void test_quantities_multiply_scalar()
const double e
constexpr OQ convertInto() const
Convert this quantity into the specified one.
Definition: quantities.h:801
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
A value measured in the specified unit.
Definition: quantities.h:566
constexpr bool has_unit_v
Trait: true if U is a ScaledUnit-based object.
Definition: quantities.h:260
Literal constants for time quantities.
Definition: spacetime.h:175
constexpr bool has_quantity_v
Trait: true if Q is a Quantity-based object.
Definition: quantities.h:276
millisecond milliseconds
Alias for common language habits.
Definition: spacetime.h:105
Numeric variable proxies with embedded unit of measurement.
String representing a quantity has no unit.
Definition: quantities.h:1092
void test_quantities_sign()
Dimensioned variables representing space or time quantities.
Functions pulling in STL customization if available.
static constexpr bool sameBaseUnitAs()
Returns whether this quantity has the same base unit as OU.
Definition: quantities.h:762
String representing a quantity has an invalid number.
Definition: quantities.h:1104
void test_quantities_comparisons()
static constexpr bool hasCompatibleValue()
Definition: quantities.h:792
void test_quantities()
void test_constexpr_operations()
BOOST_AUTO_TEST_CASE(quantities_testcase)
void test_quantities_literals()