LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
test.h
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 /*
3  * This file is part of afw.
4  *
5  * Developed for the LSST Data Management System.
6  * This product includes software developed by the LSST Project
7  * (https://www.lsst.org).
8  * See the COPYRIGHT file at the top-level directory of this distribution
9  * for details of code ownership.
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
25 #ifndef LSST_AFW_TYPEHANDLING_TEST_H
26 #define LSST_AFW_TYPEHANDLING_TEST_H
27 
28 #define BOOST_TEST_DYN_LINK
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wunused-variable"
31 #include "boost/test/unit_test.hpp"
32 #pragma clang diagnostic pop
33 
34 #include <memory>
35 #include <numeric>
36 #include <set>
37 #include <sstream>
38 #include <string>
39 
40 #include <boost/mpl/list.hpp>
41 
42 #include "lsst/pex/exceptions.h"
43 
46 
47 namespace lsst {
48 namespace afw {
49 namespace typehandling {
50 namespace test {
51 
52 /*
53  * This include file defines tests that exercise the GenericMap and MutableGenericMap interfaces, and ensures
54  * that any implementation satisfies the requirements of these interfaces. Subclass authors should call either
55  * addGenericMapTestCases or addMutableGenericMapTestCases in a suitable entry point, such as a global fixture
56  * or a module initialization function.
57  */
58 
59 namespace {
60 class SimpleStorable : public Storable {
61 public:
62  virtual ~SimpleStorable() = default;
63 
64  std::shared_ptr<Storable> cloneStorable() const override { return std::make_unique<SimpleStorable>(); }
65 
66  std::string toString() const override { return "Simplest possible representation"; }
67 
68  bool equals(Storable const& other) const noexcept override { return singleClassEquals(*this, other); }
69  virtual bool operator==(SimpleStorable const& other) const { return true; }
70  bool operator!=(SimpleStorable const& other) const { return !(*this == other); }
71 };
72 
73 class ComplexStorable final : public SimpleStorable {
74 public:
75  constexpr ComplexStorable(double storage) : SimpleStorable(), storage(storage) {}
76 
77  ComplexStorable& operator=(double newValue) {
78  storage = newValue;
79  return *this;
80  }
81 
82  std::shared_ptr<Storable> cloneStorable() const override {
83  return std::make_unique<ComplexStorable>(storage);
84  }
85 
86  std::string toString() const override { return "ComplexStorable(" + std::to_string(storage) + ")"; }
87 
88  std::size_t hash_value() const noexcept override { return std::hash<double>()(storage); }
89 
90  // Warning: violates both substitution and equality symmetry!
91  bool equals(Storable const& other) const noexcept override {
92  auto complexOther = dynamic_cast<ComplexStorable const*>(&other);
93  if (complexOther) {
94  return this->storage == complexOther->storage;
95  } else {
96  return false;
97  }
98  }
99  bool operator==(SimpleStorable const& other) const override { return this->equals(other); }
100 
101 private:
102  double storage;
103 };
104 
105 template <typename T>
106 std::string universalToString(T const& value) {
107  std::stringstream buffer;
108  buffer << value;
109  return buffer.str();
110 };
111 
112 // Would make more sense as static constants in GenericFactory
113 // but neither string nor Storable qualify as literal types
114 // In anonymous namespace to ensure constants are internal to whatever test includes this header
115 auto const KEY0 = makeKey<bool>(0);
116 bool const VALUE0 = true;
117 auto const KEY1 = makeKey<int>(1);
118 int const VALUE1 = 42;
119 auto const KEY2 = makeKey<double>(2);
120 int const VALUE2 = VALUE1;
121 auto const KEY3 = makeKey<std::string>(3);
122 std::string const VALUE3 = "How many roads must a man walk down?";
123 auto const KEY4 = makeKey<std::shared_ptr<SimpleStorable const>>(4);
124 auto const VALUE4 = SimpleStorable();
125 auto const KEY5 = makeKey<ComplexStorable>(5);
126 auto const VALUE5 = ComplexStorable(-100.0);
127 auto const KEY6 = makeKey<std::shared_ptr<Storable const>>(6);
128 auto const VALUE6 = std::shared_ptr<Storable const>();
129 } // namespace
130 
135 public:
136  virtual ~GenericFactory() = default;
137 
149  virtual std::unique_ptr<GenericMap<int>> makeGenericMap() const = 0;
150 
152  virtual std::unique_ptr<MutableGenericMap<std::string>> makeMutableGenericMap() const = 0;
153 };
154 
155 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstAt, GenericMapFactory) {
156  static GenericMapFactory const factory;
157  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
158 
159  BOOST_TEST(demoMap->at(KEY0) == VALUE0);
160  BOOST_TEST(demoMap->at(KEY1) == VALUE1);
161  BOOST_TEST(demoMap->at(KEY2) == VALUE2);
162  BOOST_TEST(demoMap->at(KEY3) == VALUE3);
163  BOOST_TEST(*(demoMap->at(KEY4)) == VALUE4);
164  BOOST_TEST(demoMap->at(KEY5) == VALUE5);
165  BOOST_TEST(demoMap->at(KEY6) == VALUE6);
166 }
167 
168 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestAt, GenericMapFactory) {
169  using namespace std::string_literals;
170 
171  static GenericMapFactory const factory;
172  std::unique_ptr<GenericMap<int>> demoMap = factory.makeGenericMap();
173 
174  BOOST_TEST(demoMap->at(KEY0) == VALUE0);
175  demoMap->at(KEY0) = false;
176  BOOST_TEST(demoMap->at(KEY0) == false);
177  BOOST_CHECK_THROW(demoMap->at(makeKey<int>(KEY0.getId())), pex::exceptions::OutOfRangeError);
178 
179  BOOST_TEST(demoMap->at(KEY1) == VALUE1);
180  demoMap->at(KEY1)++;
181  BOOST_TEST(demoMap->at(KEY1) == VALUE1 + 1);
182  BOOST_CHECK_THROW(demoMap->at(makeKey<bool>(KEY1.getId())), pex::exceptions::OutOfRangeError);
183 
184  BOOST_TEST(demoMap->at(KEY2) == VALUE2);
185  demoMap->at(KEY2) = 0.0;
186  BOOST_TEST(demoMap->at(KEY2) == 0.0);
187  // VALUE2 is of a different type than KEY2, check that alternate key is absent
188  using Type2 = std::remove_const_t<decltype(VALUE2)>;
189  BOOST_CHECK_THROW(demoMap->at(makeKey<Type2>(KEY2.getId())), pex::exceptions::OutOfRangeError);
190 
191  BOOST_TEST(demoMap->at(KEY3) == VALUE3);
192  demoMap->at(KEY3).append(" Oops, wrong question."s);
193  BOOST_TEST(demoMap->at(KEY3) == VALUE3 + " Oops, wrong question."s);
194 
195  BOOST_TEST(*(demoMap->at(KEY4)) == VALUE4);
196  // VALUE4 is of a different type than KEY4, check that alternate key is absent
197  using Type4 = std::remove_const_t<decltype(VALUE4)>;
198  BOOST_CHECK_THROW(demoMap->at(makeKey<Type4>(KEY4.getId())), pex::exceptions::OutOfRangeError);
199 
200  BOOST_TEST(demoMap->at(KEY5) == VALUE5);
201  BOOST_TEST(demoMap->at(makeKey<SimpleStorable>(KEY5.getId())) == VALUE5);
202 
203  ComplexStorable newValue(5.0);
204  demoMap->at(KEY5) = newValue;
205  BOOST_TEST(demoMap->at(KEY5) == newValue);
206 
207  BOOST_TEST(demoMap->at(KEY6) == VALUE6);
208 }
209 
210 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestEquals, GenericMapFactory) {
211  static GenericMapFactory const factory;
212  auto map1 = factory.makeGenericMap();
213 
214  // Use BOOST_CHECK to avoid BOOST_TEST bug from GenericMap being unprintable
215  BOOST_CHECK(*map1 == *map1);
216  // Maps are unequal because shared_ptr members point to different objects
217  BOOST_CHECK(*map1 != *(factory.makeGenericMap()));
218 }
219 
220 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstVisitor, GenericMapFactory) {
221  static GenericMapFactory const factory;
222  std::unique_ptr<GenericMap<int> const> const map = factory.makeGenericMap();
223  std::vector<int> mapKeys = map->keys();
224 
225  // Visitors return string because it's one of the few operations valid for all types of interest
226  // This lets us test generic lambdas as visitors
227  auto bruteForcePrinter = [&map](int key) {
228  switch (key) {
229  case 0:
230  return universalToString(map->at(KEY0));
231  case 1:
232  return universalToString(map->at(KEY1));
233  case 2:
234  return universalToString(map->at(KEY2));
235  case 3:
236  return universalToString(map->at(KEY3));
237  case 4:
238  return universalToString(map->at(KEY4));
239  case 5:
240  return universalToString(map->at(KEY5));
241  case 6:
242  return universalToString(map->at(KEY6));
243  default:
244  throw std::invalid_argument("Bad key found");
245  };
246  };
247  std::vector<std::string> expected;
248  for (int key : mapKeys) {
249  expected.push_back(bruteForcePrinter(key));
250  }
251 
252  // Test local class that returns void
253  class {
254  public:
255  std::vector<std::string> results;
256 
257  // Local classes can't have method templates
258  void operator()(int, bool value) { results.push_back(universalToString(value)); }
259  void operator()(int, int const& value) { results.push_back(universalToString(value)); }
260  void operator()(int, long value) { results.push_back(universalToString(value)); }
261  void operator()(int, long long value) { results.push_back(universalToString(value)); }
262  void operator()(int, float const& value) { results.push_back(universalToString(value)); }
263  void operator()(int, double value) { results.push_back(universalToString(value)); }
264  void operator()(int, std::string const& value) { results.push_back(universalToString(value)); }
265  void operator()(int, Storable const& value) { results.push_back(universalToString(value)); }
266  void operator()(int, std::shared_ptr<Storable const> value) {
267  results.push_back(universalToString(value));
268  }
269  } printer;
270  map->apply(printer);
271  BOOST_REQUIRE(printer.results.size() == expected.size());
272  for (std::size_t i = 0; i < printer.results.size(); ++i) {
273  BOOST_TEST(printer.results[i] == expected[i],
274  printer.results[i] << " != " << expected[i] << ", key = " << mapKeys[i]);
275  }
276 
277  // Test lambda that returns string
278  std::vector<std::string> strings =
279  map->apply([](int, auto const& value) { return universalToString(value); });
280  BOOST_REQUIRE(strings.size() == expected.size());
281  for (std::size_t i = 0; i < strings.size(); ++i) {
282  BOOST_TEST(strings[i] == expected[i],
283  strings[i] << " != " << expected[i] << ", key = " << mapKeys[i]);
284  }
285 }
286 
287 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestModifyingVoidVisitor, GenericMapFactory) {
288  static GenericMapFactory const factory;
289  std::unique_ptr<GenericMap<int>> map = factory.makeGenericMap();
290  std::vector<int> originalKeys = map->keys();
291 
292  // Test local class that returns void
293  class {
294  public:
295  // Local classes can't have method templates
296  void operator()(int, bool& value) { value = !value; }
297  void operator()(int, int& value) { value *= 2; }
298  void operator()(int, long& value) { value *= 2; }
299  void operator()(int, long long& value) { value *= 2; }
300  void operator()(int, float& value) { value *= 2; }
301  void operator()(int, double& value) { value *= 2; }
302  void operator()(int, std::string& value) { value += "Appendix"; }
303  void operator()(int, Storable& value) {
304  auto complexStorable = dynamic_cast<ComplexStorable*>(&value);
305  if (complexStorable != nullptr) {
306  *complexStorable = 42;
307  }
308  }
309  void operator()(int, std::shared_ptr<Storable const>) {}
310  } grower;
311  map->apply(grower);
312  std::vector<int> newKeys = map->keys();
313 
314  BOOST_TEST(newKeys == originalKeys);
315  BOOST_TEST(map->at(KEY0) == !VALUE0);
316  BOOST_TEST(map->at(KEY1) == 2 * VALUE1);
317  BOOST_TEST(map->at(KEY2) == 2 * VALUE2);
318  BOOST_TEST(map->at(KEY3) == VALUE3 + "Appendix");
319  BOOST_TEST(*(map->at(KEY4)) == VALUE4);
320  BOOST_TEST(map->at(KEY5) != VALUE5);
321  BOOST_TEST(map->at(KEY5) == ComplexStorable(42));
322  BOOST_TEST(map->at(KEY6) == nullptr);
323 }
324 
325 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestModifyingReturningVisitor, GenericMapFactory) {
326  static GenericMapFactory const factory;
327  std::unique_ptr<GenericMap<int>> map = factory.makeGenericMap();
328  std::vector<int> originalKeys = map->keys();
329 
330  // Test local class that returns int
331  class {
332  public:
333  // Local classes can't have method templates
334  int operator()(int key, bool& value) {
335  value = !value;
336  return key;
337  }
338  int operator()(int key, int& value) {
339  value *= 2;
340  return key;
341  }
342  int operator()(int key, long& value) {
343  value *= 2;
344  return key;
345  }
346  int operator()(int key, long long& value) {
347  value *= 2;
348  return key;
349  }
350  int operator()(int key, float& value) {
351  value *= 2;
352  return key;
353  }
354  int operator()(int key, double& value) {
355  value *= 2;
356  return key;
357  }
358  int operator()(int key, std::string& value) {
359  value += "Appendix";
360  return key;
361  }
362  int operator()(int key, Storable& value) {
363  auto complexStorable = dynamic_cast<ComplexStorable*>(&value);
364  if (complexStorable != nullptr) {
365  *complexStorable = 42;
366  }
367  return key;
368  }
369  int operator()(int key, std::shared_ptr<Storable const>) { return key; }
370  } grower;
371  std::vector<int> editedKeys = map->apply(grower);
372  BOOST_TEST(editedKeys == originalKeys);
373 
374  std::vector<int> newKeys = map->keys();
375  BOOST_TEST(newKeys == originalKeys);
376  BOOST_TEST(map->at(KEY0) == !VALUE0);
377  BOOST_TEST(map->at(KEY1) == 2 * VALUE1);
378  BOOST_TEST(map->at(KEY2) == 2 * VALUE2);
379  BOOST_TEST(map->at(KEY3) == VALUE3 + "Appendix");
380  BOOST_TEST(*(map->at(KEY4)) == VALUE4);
381  BOOST_TEST(map->at(KEY5) != VALUE5);
382  BOOST_TEST(map->at(KEY5) == ComplexStorable(42));
383  BOOST_TEST(map->at(KEY6) == nullptr);
384 }
385 
386 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestMutableEquals, GenericMapFactory) {
387  using namespace std::string_literals;
388 
389  static GenericMapFactory const factory;
390  auto map1 = factory.makeMutableGenericMap();
391  auto map2 = factory.makeMutableGenericMap();
392 
393  // Use BOOST_CHECK to avoid BOOST_TEST bug from GenericMap being unprintable
394  BOOST_CHECK(*map1 == *map2);
395 
396  auto primitiveKey = makeKey<int>("primitive"s);
397  map1->insert(primitiveKey, 42);
398  BOOST_CHECK(*map1 != *map2);
399  map2->insert(primitiveKey, 42);
400  BOOST_CHECK(*map1 == *map2);
401 
402  auto sharedKey = makeKey<std::shared_ptr<SimpleStorable const>>("shared"s);
403  auto common = std::make_shared<SimpleStorable const>(VALUE4);
404  map1->insert(sharedKey, common);
405  BOOST_CHECK(*map1 != *map2);
406  map2->insert(sharedKey, std::make_shared<SimpleStorable const>(VALUE4));
407  BOOST_CHECK(*map1 != *map2);
408  map2->erase(sharedKey);
409  map2->insert(sharedKey, common);
410  BOOST_CHECK(*map1 == *map2);
411 
412  auto storableKey = makeKey<ComplexStorable>("storable"s);
413  map1->insert(storableKey, VALUE5);
414  BOOST_CHECK(*map1 != *map2);
415  map2->insert(storableKey, VALUE5);
416  BOOST_CHECK(*map1 == *map2);
417 
418  auto nullKey = makeKey<std::shared_ptr<ComplexStorable const>>("null"s);
419  map1->insert(nullKey, std::static_pointer_cast<ComplexStorable const>(VALUE6));
420  BOOST_CHECK(*map1 != *map2);
421  map2->insert(nullKey, std::static_pointer_cast<ComplexStorable const>(VALUE6));
422  BOOST_CHECK(*map1 == *map2);
423 }
424 
425 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestSize, GenericMapFactory) {
426  static GenericMapFactory const factory;
427  std::unique_ptr<GenericMap<int>> demoMap = factory.makeGenericMap();
428 
429  BOOST_TEST(demoMap->size() == 7);
430  BOOST_TEST(!demoMap->empty());
431 }
432 
433 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestMutableSize, GenericMapFactory) {
434  using namespace std::string_literals;
435 
436  static GenericMapFactory const factory;
437  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
438 
439  BOOST_TEST_REQUIRE(demoMap->size() == 0);
440  BOOST_TEST_REQUIRE(demoMap->empty());
441 
442  demoMap->insert(makeKey<int>("Negative One"s), -1);
443  BOOST_TEST(demoMap->size() == 1);
444  BOOST_TEST(!demoMap->empty());
445 
446  demoMap->erase(makeKey<int>("Negative One"s));
447  BOOST_TEST(demoMap->size() == 0);
448  BOOST_TEST(demoMap->empty());
449 }
450 
451 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakContains, GenericMapFactory) {
452  using namespace std::string_literals;
453 
454  static GenericMapFactory const factory;
455  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
456 
457  BOOST_TEST(demoMap->contains(KEY0.getId()));
458  BOOST_TEST(demoMap->contains(KEY1.getId()));
459  BOOST_TEST(demoMap->contains(KEY2.getId()));
460  BOOST_TEST(demoMap->contains(KEY3.getId()));
461  BOOST_TEST(demoMap->contains(KEY4.getId()));
462  BOOST_TEST(demoMap->contains(KEY5.getId()));
463  BOOST_TEST(demoMap->contains(KEY6.getId()));
464 }
465 
466 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestContains, GenericMapFactory) {
467  static GenericMapFactory const factory;
468  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
469 
470  BOOST_TEST(demoMap->contains(KEY0));
471  BOOST_TEST(!demoMap->contains(makeKey<int>(KEY0.getId())));
472 
473  BOOST_TEST(demoMap->contains(KEY1));
474  BOOST_TEST(!demoMap->contains(makeKey<bool>(KEY1.getId())));
475 
476  BOOST_TEST(demoMap->contains(KEY2));
477  // VALUE2 is of a different type than KEY2, check that alternate key is absent
478  BOOST_TEST(!demoMap->contains(makeKey<decltype(VALUE2)>(KEY2.getId())));
479 
480  BOOST_TEST(demoMap->contains(KEY3));
481 
482  BOOST_TEST(demoMap->contains(KEY4));
483  // VALUE4 is of a different type than KEY4, check that alternate key is absent
484  BOOST_TEST(!demoMap->contains(makeKey<decltype(VALUE4)>(KEY4.getId())));
485 
486  BOOST_TEST(demoMap->contains(KEY5));
487  BOOST_TEST(demoMap->contains(makeKey<SimpleStorable>(KEY5.getId())));
488  BOOST_TEST(demoMap->contains(makeKey<Storable>(KEY5.getId())));
489 
490  BOOST_TEST(demoMap->contains(KEY6));
491  BOOST_TEST(demoMap->contains(makeKey<std::shared_ptr<SimpleStorable const>>(KEY6.getId())));
492  BOOST_TEST(demoMap->contains(makeKey<std::shared_ptr<ComplexStorable const>>(KEY6.getId())));
493 }
494 
495 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestKeys, GenericMapFactory) {
496  static GenericMapFactory const factory;
497  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
498  auto orderedKeys = demoMap->keys();
499  // GenericMap allows keys in any order, so just check they're the same
500  std::set<int> keys(orderedKeys.begin(), orderedKeys.end());
501 
502  BOOST_TEST(keys == std::set<int>({KEY0.getId(), KEY1.getId(), KEY2.getId(), KEY3.getId(), KEY4.getId(),
503  KEY5.getId(), KEY6.getId()}));
504 }
505 
506 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestKeyOrder, GenericMapFactory) {
507  static GenericMapFactory const factory;
508  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
509  auto keys = demoMap->keys();
510 
511  std::vector<int> iterOrder;
512  demoMap->apply([&iterOrder](int key, auto value) { iterOrder.push_back(key); });
513  BOOST_TEST(keys == iterOrder);
514 }
515 
516 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestClearIdempotent, GenericMapFactory) {
517  static GenericMapFactory const factory;
518  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
519 
520  BOOST_TEST_REQUIRE(demoMap->empty());
521  demoMap->clear();
522  BOOST_TEST(demoMap->empty());
523 }
524 
525 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestClear, GenericMapFactory) {
526  using namespace std::string_literals;
527 
528  static GenericMapFactory const factory;
529  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
530 
531  demoMap->insert(makeKey<int>("prime"s), 3);
532  demoMap->insert(makeKey<std::string>("foo"s), "bar"s);
533 
534  BOOST_TEST_REQUIRE(!demoMap->empty());
535  demoMap->clear();
536  BOOST_TEST(demoMap->empty());
537 }
538 
539 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertInt, GenericMapFactory) {
540  using namespace std::string_literals;
541 
542  static GenericMapFactory const factory;
543  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
544 
545  BOOST_TEST_REQUIRE(demoMap->empty());
546 
547  int x = 27;
548  BOOST_TEST(demoMap->insert(makeKey<int>("cube"s), x) == true);
549  BOOST_TEST(demoMap->insert(makeKey<int>("cube"s), 0) == false);
550 
551  BOOST_TEST(!demoMap->empty());
552  BOOST_TEST(demoMap->size() == 1);
553  BOOST_TEST(demoMap->contains("cube"s));
554  BOOST_TEST(demoMap->contains(makeKey<int>("cube"s)));
555  BOOST_TEST(!demoMap->contains(makeKey<double>("cube"s)));
556  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == x);
557 
558  x = 0;
559  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) != x);
560 
561  demoMap->at(makeKey<int>("cube"s)) = 0;
562  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == 0);
563 }
564 
565 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakInsertInt, GenericMapFactory) {
566  using namespace std::string_literals;
567 
568  static GenericMapFactory const factory;
569  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
570 
571  BOOST_TEST_REQUIRE(demoMap->empty());
572 
573  auto insertResult = demoMap->insert("cube"s, 27);
574  BOOST_TEST(insertResult.second == true);
575  BOOST_TEST(demoMap->insert("cube"s, 0).second == false);
576 
577  BOOST_TEST(!demoMap->empty());
578  BOOST_TEST(demoMap->size() == 1);
579  BOOST_TEST(demoMap->contains("cube"s));
580  BOOST_TEST(demoMap->contains(insertResult.first));
581  BOOST_TEST(demoMap->contains(makeKey<int>("cube"s)));
582  BOOST_TEST(!demoMap->contains(makeKey<double>("cube"s)));
583  BOOST_TEST(demoMap->at(insertResult.first) == 27);
584  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == 27);
585 
586  demoMap->at(insertResult.first) = 0;
587  BOOST_TEST(demoMap->at(insertResult.first) == 0);
588 }
589 
590 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertString, GenericMapFactory) {
591  using namespace std::string_literals;
592 
593  static GenericMapFactory const factory;
594  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
595 
596  BOOST_TEST_REQUIRE(demoMap->empty());
597 
598  std::string answer(
599  "I have a most elegant and wonderful proof, but this string is too small to contain it."s);
600  BOOST_TEST(demoMap->insert(makeKey<std::string>("Ultimate answer"s), answer) == true);
601  BOOST_TEST(demoMap->insert(makeKey<std::string>("OK"s), "Ook!"s) == true);
602  BOOST_TEST(demoMap->insert(makeKey<std::string>("Ultimate answer"s), "Something philosophical"s) ==
603  false);
604 
605  BOOST_TEST(!demoMap->empty());
606  BOOST_TEST(demoMap->size() == 2);
607  BOOST_TEST(demoMap->contains("OK"s));
608  BOOST_TEST(demoMap->contains(makeKey<std::string>("Ultimate answer"s)));
609  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) == answer);
610  BOOST_TEST(demoMap->at(makeKey<std::string>("OK"s)) == "Ook!"s);
611 
612  answer = "I don't know"s;
613  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) != answer);
614 }
615 
616 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakInsertString, GenericMapFactory) {
617  using namespace std::string_literals;
618 
619  static GenericMapFactory const factory;
620  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
621 
622  BOOST_TEST_REQUIRE(demoMap->empty());
623 
624  auto insertResult1 = demoMap->insert("Ultimate answer"s, "Something philosophical"s);
625  BOOST_TEST(insertResult1.second == true);
626  auto insertResult2 = demoMap->insert("OK"s, "Ook!"s);
627  BOOST_TEST(insertResult2.second == true);
628 
629  BOOST_TEST(!demoMap->empty());
630  BOOST_TEST(demoMap->size() == 2);
631  BOOST_TEST(demoMap->contains(insertResult1.first));
632  BOOST_TEST(demoMap->contains(insertResult2.first));
633  BOOST_TEST(demoMap->contains("OK"s));
634  BOOST_TEST(demoMap->contains(makeKey<std::string>("Ultimate answer"s)));
635  BOOST_TEST(demoMap->at(insertResult1.first) == "Something philosophical"s);
636  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) == "Something philosophical"s);
637  BOOST_TEST(demoMap->at(insertResult2.first) == "Ook!"s);
638  BOOST_TEST(demoMap->at(makeKey<std::string>("OK"s)) == "Ook!"s);
639 }
640 
641 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertStorable, GenericMapFactory) {
642  using namespace std::string_literals;
643 
644  static GenericMapFactory const factory;
645  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
646 
647  BOOST_TEST_REQUIRE(demoMap->empty());
648 
649  ComplexStorable object(3.1416);
650  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("foo"s), object) == true);
651  BOOST_TEST(demoMap->insert(makeKey<std::shared_ptr<ComplexStorable const>>("bar"s),
652  std::make_shared<ComplexStorable const>(3.141)) == true);
653  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("foo"s), SimpleStorable()) == false);
654  BOOST_TEST(demoMap->insert(makeKey<std::shared_ptr<SimpleStorable const>>("bar"s),
655  std::make_shared<SimpleStorable const>()) == false);
656  BOOST_TEST(demoMap->insert(makeKey<std::shared_ptr<SimpleStorable const>>("null"s),
657  std::make_shared<SimpleStorable const>()) == true);
658 
659  BOOST_TEST(!demoMap->empty());
660  BOOST_TEST(demoMap->size() == 3);
661  BOOST_TEST(demoMap->contains("foo"s));
662  BOOST_TEST(demoMap->contains(makeKey<Storable>("foo"s)));
663  BOOST_TEST(demoMap->contains(makeKey<std::shared_ptr<ComplexStorable const>>("bar"s)));
664  BOOST_TEST(demoMap->contains(makeKey<std::shared_ptr<SimpleStorable const>>("null"s)));
665 
666  // ComplexStorable::operator== is asymmetric
667  BOOST_TEST(object == demoMap->at(makeKey<SimpleStorable>("foo"s)));
668  object = ComplexStorable(1.4);
669  BOOST_TEST(object != demoMap->at(makeKey<SimpleStorable>("foo"s)));
670  BOOST_TEST(*(demoMap->at(makeKey<std::shared_ptr<ComplexStorable const>>("bar"s))) ==
671  ComplexStorable(3.141));
672 }
673 
674 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInterleavedInserts, GenericMapFactory) {
675  using namespace std::string_literals;
676 
677  static GenericMapFactory const factory;
678  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
679 
680  BOOST_TEST_REQUIRE(demoMap->empty());
681 
682  BOOST_TEST(demoMap->insert(makeKey<int>("key1"s), 3) == true);
683  BOOST_TEST(demoMap->insert(makeKey<double>("key1"s), 1.0) == false);
684  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("key2"s), SimpleStorable()) == true);
685  BOOST_TEST(demoMap->insert(makeKey<std::string>("key3"s), "Test value"s) == true);
686  BOOST_TEST(demoMap->insert(makeKey<std::string>("key4"s), "This is some text"s) == true);
687  std::string const message = "Unknown value for key5."s;
688  BOOST_TEST(demoMap->insert(makeKey<std::string>("key5"s), message) == true);
689  BOOST_TEST(demoMap->insert(makeKey<int>("key3"s), 20) == false);
690  BOOST_TEST(demoMap->insert<double>(makeKey<double>("key6"s), 42) == true);
691 
692  BOOST_TEST(!demoMap->empty());
693  BOOST_TEST(demoMap->size() == 6);
694  BOOST_TEST(demoMap->at(makeKey<int>("key1"s)) == 3);
695  BOOST_TEST(demoMap->at(makeKey<double>("key6"s)) == 42);
696  BOOST_TEST(demoMap->at(makeKey<SimpleStorable>("key2"s)) == SimpleStorable());
697  BOOST_TEST(demoMap->at(makeKey<std::string>("key3"s)) == "Test value"s);
698  BOOST_TEST(demoMap->at(makeKey<std::string>("key4"s)) == "This is some text"s);
699  BOOST_TEST(demoMap->at(makeKey<std::string>("key5"s)) == message);
700 }
701 
702 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestErase, GenericMapFactory) {
703  using namespace std::string_literals;
704 
705  static GenericMapFactory const factory;
706  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
707 
708  demoMap->insert(makeKey<int>("Ultimate answer"s), 42);
709  BOOST_TEST_REQUIRE(demoMap->size() == 1);
710 
711  BOOST_TEST(demoMap->erase(makeKey<std::string>("Ultimate answer"s)) == false);
712  BOOST_TEST(demoMap->size() == 1);
713  BOOST_TEST(demoMap->erase(makeKey<int>("Ultimate answer"s)) == true);
714  BOOST_TEST(demoMap->size() == 0);
715 }
716 
717 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertEraseInsert, GenericMapFactory) {
718  using namespace std::string_literals;
719 
720  static GenericMapFactory const factory;
721  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
722 
723  BOOST_TEST_REQUIRE(demoMap->empty());
724 
725  BOOST_TEST(demoMap->insert(makeKey<int>("Ultimate answer"s), 42) == true);
726  BOOST_TEST(demoMap->insert(makeKey<int>("OK"s), 200) == true);
727  BOOST_TEST(demoMap->erase(makeKey<int>("Ultimate answer"s)) == true);
728  BOOST_TEST(demoMap->insert(makeKey<double>("Ultimate answer"s), 3.1415927) == true);
729 
730  BOOST_TEST(!demoMap->empty());
731  BOOST_TEST(demoMap->size() == 2);
732  BOOST_TEST(demoMap->contains("OK"s));
733  BOOST_TEST(!demoMap->contains(makeKey<int>("Ultimate answer"s)));
734  BOOST_TEST(demoMap->contains(makeKey<double>("Ultimate answer"s)));
735  BOOST_TEST(demoMap->at(makeKey<double>("Ultimate answer"s)) == 3.1415927);
736 }
737 
745 template <class GenericMapFactory>
746 void addGenericMapTestCases(boost::unit_test::test_suite* const suite) {
747  using factories = boost::mpl::list<GenericMapFactory>;
748 
749  suite->add(BOOST_TEST_CASE_TEMPLATE(TestConstAt, factories));
750  suite->add(BOOST_TEST_CASE_TEMPLATE(TestAt, factories));
751  suite->add(BOOST_TEST_CASE_TEMPLATE(TestEquals, factories));
752  suite->add(BOOST_TEST_CASE_TEMPLATE(TestSize, factories));
753  suite->add(BOOST_TEST_CASE_TEMPLATE(TestWeakContains, factories));
754  suite->add(BOOST_TEST_CASE_TEMPLATE(TestContains, factories));
755  suite->add(BOOST_TEST_CASE_TEMPLATE(TestKeys, factories));
756  suite->add(BOOST_TEST_CASE_TEMPLATE(TestKeyOrder, factories));
757  suite->add(BOOST_TEST_CASE_TEMPLATE(TestConstVisitor, factories));
758  suite->add(BOOST_TEST_CASE_TEMPLATE(TestModifyingVoidVisitor, factories));
759  suite->add(BOOST_TEST_CASE_TEMPLATE(TestModifyingReturningVisitor, factories));
760 }
761 
771 template <class GenericMapFactory>
772 void addMutableGenericMapTestCases(boost::unit_test::test_suite* const suite) {
773  using factories = boost::mpl::list<GenericMapFactory>;
774 
775  addGenericMapTestCases<GenericMapFactory>(suite);
776 
777  suite->add(BOOST_TEST_CASE_TEMPLATE(TestMutableEquals, factories));
778  suite->add(BOOST_TEST_CASE_TEMPLATE(TestMutableSize, factories));
779  suite->add(BOOST_TEST_CASE_TEMPLATE(TestClear, factories));
780  suite->add(BOOST_TEST_CASE_TEMPLATE(TestClearIdempotent, factories));
781  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertInt, factories));
782  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertString, factories));
783  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertStorable, factories));
784  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInterleavedInserts, factories));
785  suite->add(BOOST_TEST_CASE_TEMPLATE(TestErase, factories));
786  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertEraseInsert, factories));
787 }
788 
797 template <class GenericMapFactory>
798 inline void addGenericMapTestCases() {
799  addGenericMapTestCases<GenericMapFactory>(&(boost::unit_test::framework::master_test_suite()));
800 }
801 
811 template <class GenericMapFactory>
813  addMutableGenericMapTestCases<GenericMapFactory>(&(boost::unit_test::framework::master_test_suite()));
814 }
815 
816 } // namespace test
817 } // namespace typehandling
818 } // namespace afw
819 } // namespace lsst
820 
821 #endif
Interface supporting iteration over heterogenous containers.
Definition: Storable.h:58
T to_string(T... args)
BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstAt, GenericMapFactory)
Definition: test.h:155
ItemVariant const * other
Definition: Schema.cc:56
std::size_t hash_value(Extent< T, N > const &extent) noexcept
Definition: Extent.cc:127
constexpr Key< K, V > makeKey(K const &id)
Factory function for Key, to enable type parameter inference.
Definition: Key.h:173
void addMutableGenericMapTestCases(boost::unit_test::test_suite *const suite)
Create generic test cases for a specific MutableGenericMap implementation.
Definition: test.h:772
STL class.
T push_back(T... args)
A base class for image defects.
Key< U > key
Definition: Schema.cc:281
T str(T... args)
Abstract factory that creates GenericMap and MutableGenericMap instances as needed.
Definition: test.h:134
double x
T size(T... args)
STL class.
Reports attempts to access elements outside a valid range of indices.
Definition: Runtime.h:89
STL class.
void addGenericMapTestCases(boost::unit_test::test_suite *const suite)
Create generic test cases for a specific GenericMap implementation.
Definition: test.h:746