LSSTApplications  18.1.0
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>>(4);
124 auto const VALUE4 = SimpleStorable();
125 auto const KEY5 = makeKey<ComplexStorable>(5);
126 auto const VALUE5 = ComplexStorable(-100.0);
127 } // namespace
128 
133 public:
134  virtual ~GenericFactory() = default;
135 
146  virtual std::unique_ptr<GenericMap<int>> makeGenericMap() const = 0;
147 
149  virtual std::unique_ptr<MutableGenericMap<std::string>> makeMutableGenericMap() const = 0;
150 };
151 
152 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstAt, GenericMapFactory) {
153  static GenericMapFactory const factory;
154  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
155 
156  BOOST_TEST(demoMap->at(KEY0) == VALUE0);
157  BOOST_TEST(demoMap->at(KEY1) == VALUE1);
158  BOOST_TEST(demoMap->at(KEY2) == VALUE2);
159  BOOST_TEST(demoMap->at(KEY3) == VALUE3);
160  BOOST_TEST(*(demoMap->at(KEY4)) == VALUE4);
161  BOOST_TEST(demoMap->at(KEY5) == VALUE5);
162 }
163 
164 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestAt, GenericMapFactory) {
165  using namespace std::string_literals;
166 
167  static GenericMapFactory const factory;
168  std::unique_ptr<GenericMap<int>> demoMap = factory.makeGenericMap();
169 
170  BOOST_TEST(demoMap->at(KEY0) == VALUE0);
171  demoMap->at(KEY0) = false;
172  BOOST_TEST(demoMap->at(KEY0) == false);
173  BOOST_CHECK_THROW(demoMap->at(makeKey<int>(KEY0.getId())), pex::exceptions::OutOfRangeError);
174 
175  BOOST_TEST(demoMap->at(KEY1) == VALUE1);
176  demoMap->at(KEY1)++;
177  BOOST_TEST(demoMap->at(KEY1) == VALUE1 + 1);
178  BOOST_CHECK_THROW(demoMap->at(makeKey<bool>(KEY1.getId())), pex::exceptions::OutOfRangeError);
179 
180  BOOST_TEST(demoMap->at(KEY2) == VALUE2);
181  demoMap->at(KEY2) = 0.0;
182  BOOST_TEST(demoMap->at(KEY2) == 0.0);
183  // VALUE2 is of a different type than KEY2, check that alternate key is absent
184  using Type2 = std::remove_const_t<decltype(VALUE2)>;
185  BOOST_CHECK_THROW(demoMap->at(makeKey<Type2>(KEY2.getId())), pex::exceptions::OutOfRangeError);
186 
187  BOOST_TEST(demoMap->at(KEY3) == VALUE3);
188  demoMap->at(KEY3).append(" Oops, wrong question."s);
189  BOOST_TEST(demoMap->at(KEY3) == VALUE3 + " Oops, wrong question."s);
190 
191  BOOST_TEST(*(demoMap->at(KEY4)) == VALUE4);
192  // VALUE4 is of a different type than KEY4, check that alternate key is absent
193  using Type4 = std::remove_const_t<decltype(VALUE4)>;
194  BOOST_CHECK_THROW(demoMap->at(makeKey<Type4>(KEY4.getId())), pex::exceptions::OutOfRangeError);
195 
196  BOOST_TEST(demoMap->at(KEY5) == VALUE5);
197  BOOST_TEST(demoMap->at(makeKey<SimpleStorable>(KEY5.getId())) == VALUE5);
198 
199  ComplexStorable newValue(5.0);
200  demoMap->at(KEY5) = newValue;
201  BOOST_TEST(demoMap->at(KEY5) == newValue);
202 }
203 
204 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestEquals, GenericMapFactory) {
205  static GenericMapFactory const factory;
206  auto map1 = factory.makeGenericMap();
207 
208  // Use BOOST_CHECK to avoid BOOST_TEST bug from GenericMap being unprintable
209  BOOST_CHECK(*map1 == *map1);
210  // Maps are unequal because shared_ptr members point to different objects
211  BOOST_CHECK(*map1 != *(factory.makeGenericMap()));
212 }
213 
214 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstVisitor, GenericMapFactory) {
215  static GenericMapFactory const factory;
216  std::unique_ptr<GenericMap<int> const> const map = factory.makeGenericMap();
217  std::vector<int> mapKeys = map->keys();
218 
219  // Visitors return string because it's one of the few operations valid for all types of interest
220  // This lets us test generic lambdas as visitors
221  auto bruteForcePrinter = [&map](int key) {
222  switch (key) {
223  case 0:
224  return universalToString(map->at(KEY0));
225  case 1:
226  return universalToString(map->at(KEY1));
227  case 2:
228  return universalToString(map->at(KEY2));
229  case 3:
230  return universalToString(map->at(KEY3));
231  case 4:
232  return universalToString(map->at(KEY4));
233  case 5:
234  return universalToString(map->at(KEY5));
235  default:
236  throw std::invalid_argument("Bad key found");
237  };
238  };
239  std::vector<std::string> expected;
240  for (int key : mapKeys) {
241  expected.push_back(bruteForcePrinter(key));
242  }
243 
244  // Test local class that returns void
245  class {
246  public:
247  std::vector<std::string> results;
248 
249  // Local classes can't have method templates
250  void operator()(int, bool value) { results.push_back(universalToString(value)); }
251  void operator()(int, std::int32_t const& value) { results.push_back(universalToString(value)); }
252  void operator()(int, std::int64_t value) { results.push_back(universalToString(value)); }
253  void operator()(int, float const& value) { results.push_back(universalToString(value)); }
254  void operator()(int, double value) { results.push_back(universalToString(value)); }
255  void operator()(int, std::string const& value) { results.push_back(universalToString(value)); }
256  void operator()(int, Storable const& value) { results.push_back(universalToString(value)); }
257  void operator()(int, std::shared_ptr<Storable> value) { results.push_back(universalToString(value)); }
258  } printer;
259  map->apply(printer);
260  BOOST_REQUIRE(printer.results.size() == expected.size());
261  for (std::size_t i = 0; i < printer.results.size(); ++i) {
262  BOOST_TEST(printer.results[i] == expected[i], printer.results[i] << " != " << expected[i] << ", key = " << mapKeys[i]);
263  }
264 
265  // Test lambda that returns string
266  std::vector<std::string> strings = map->apply([](int, auto const& value) { return universalToString(value); });
267  BOOST_REQUIRE(strings.size() == expected.size());
268  for (std::size_t i = 0; i < strings.size(); ++i) {
269  BOOST_TEST(strings[i] == expected[i], strings[i] << " != " << expected[i] << ", key = " << mapKeys[i]);
270  }
271 }
272 
273 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestModifyingVoidVisitor, GenericMapFactory) {
274  static GenericMapFactory const factory;
275  std::unique_ptr<GenericMap<int>> map = factory.makeGenericMap();
276  std::vector<int> originalKeys = map->keys();
277 
278  // Test local class that returns void
279  class {
280  public:
281  // Local classes can't have method templates
282  void operator()(int, bool& value) { value = !value; }
283  void operator()(int, std::int32_t& value) { value *= 2; }
284  void operator()(int, std::int64_t& value) { value *= 2; }
285  void operator()(int, float& value) { value *= 2; }
286  void operator()(int, double& value) { value *= 2; }
287  void operator()(int, std::string& value) { value += "Appendix"; }
288  void operator()(int, Storable& value) {
289  auto complexStorable = dynamic_cast<ComplexStorable*>(&value);
290  if (complexStorable != nullptr) {
291  *complexStorable = 42;
292  }
293  }
294  void operator()(int, std::shared_ptr<Storable>) {}
295  } grower;
296  map->apply(grower);
297  std::vector<int> newKeys = map->keys();
298 
299  BOOST_TEST(newKeys == originalKeys);
300  BOOST_TEST(map->at(KEY0) == !VALUE0);
301  BOOST_TEST(map->at(KEY1) == 2 * VALUE1);
302  BOOST_TEST(map->at(KEY2) == 2 * VALUE2);
303  BOOST_TEST(map->at(KEY3) == VALUE3 + "Appendix");
304  BOOST_TEST(*(map->at(KEY4)) == VALUE4);
305  BOOST_TEST(map->at(KEY5) != VALUE5);
306  BOOST_TEST(map->at(KEY5) == ComplexStorable(42));
307 }
308 
309 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestModifyingReturningVisitor, GenericMapFactory) {
310  static GenericMapFactory const factory;
311  std::unique_ptr<GenericMap<int>> map = factory.makeGenericMap();
312  std::vector<int> originalKeys = map->keys();
313 
314  // Test local class that returns int
315  class {
316  public:
317  // Local classes can't have method templates
318  int operator()(int key, bool& value) {
319  value = !value;
320  return key;
321  }
322  int operator()(int key, std::int32_t& value) {
323  value *= 2;
324  return key;
325  }
326  int operator()(int key, std::int64_t& value) {
327  value *= 2;
328  return key;
329  }
330  int operator()(int key, float& value) {
331  value *= 2;
332  return key;
333  }
334  int operator()(int key, double& value) {
335  value *= 2;
336  return key;
337  }
338  int operator()(int key, std::string& value) {
339  value += "Appendix";
340  return key;
341  }
342  int operator()(int key, Storable& value) {
343  auto complexStorable = dynamic_cast<ComplexStorable*>(&value);
344  if (complexStorable != nullptr) {
345  *complexStorable = 42;
346  }
347  return key;
348  }
349  int operator()(int key, std::shared_ptr<Storable>) { return key; }
350  } grower;
351  std::vector<int> editedKeys = map->apply(grower);
352  BOOST_TEST(editedKeys == originalKeys);
353 
354  std::vector<int> newKeys = map->keys();
355  BOOST_TEST(newKeys == originalKeys);
356  BOOST_TEST(map->at(KEY0) == !VALUE0);
357  BOOST_TEST(map->at(KEY1) == 2 * VALUE1);
358  BOOST_TEST(map->at(KEY2) == 2 * VALUE2);
359  BOOST_TEST(map->at(KEY3) == VALUE3 + "Appendix");
360  BOOST_TEST(*(map->at(KEY4)) == VALUE4);
361  BOOST_TEST(map->at(KEY5) != VALUE5);
362  BOOST_TEST(map->at(KEY5) == ComplexStorable(42));
363 }
364 
365 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestMutableEquals, GenericMapFactory) {
366  using namespace std::string_literals;
367 
368  static GenericMapFactory const factory;
369  auto map1 = factory.makeMutableGenericMap();
370  auto map2 = factory.makeMutableGenericMap();
371 
372  // Use BOOST_CHECK to avoid BOOST_TEST bug from GenericMap being unprintable
373  BOOST_CHECK(*map1 == *map2);
374 
375  auto primitiveKey = makeKey<int>("primitive"s);
376  map1->insert(primitiveKey, 42);
377  BOOST_CHECK(*map1 != *map2);
378  map2->insert(primitiveKey, 42);
379  BOOST_CHECK(*map1 == *map2);
380 
381  auto sharedKey = makeKey<std::shared_ptr<SimpleStorable>>("shared"s);
382  auto common = std::make_shared<SimpleStorable>(VALUE4);
383  map1->insert(sharedKey, common);
384  BOOST_CHECK(*map1 != *map2);
385  map2->insert(sharedKey, std::make_shared<SimpleStorable>(VALUE4));
386  BOOST_CHECK(*map1 != *map2);
387  map2->erase(sharedKey);
388  map2->insert(sharedKey, common);
389  BOOST_CHECK(*map1 == *map2);
390 
391  auto storableKey = makeKey<ComplexStorable>("storable"s);
392  map1->insert(storableKey, VALUE5);
393  BOOST_CHECK(*map1 != *map2);
394  map2->insert(storableKey, VALUE5);
395  BOOST_CHECK(*map1 == *map2);
396 }
397 
398 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestSize, GenericMapFactory) {
399  static GenericMapFactory const factory;
400  std::unique_ptr<GenericMap<int>> demoMap = factory.makeGenericMap();
401 
402  BOOST_TEST(demoMap->size() == 6);
403  BOOST_TEST(!demoMap->empty());
404 }
405 
406 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestMutableSize, GenericMapFactory) {
407  using namespace std::string_literals;
408 
409  static GenericMapFactory const factory;
410  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
411 
412  BOOST_TEST_REQUIRE(demoMap->size() == 0);
413  BOOST_TEST_REQUIRE(demoMap->empty());
414 
415  demoMap->insert(makeKey<int>("Negative One"s), -1);
416  BOOST_TEST(demoMap->size() == 1);
417  BOOST_TEST(!demoMap->empty());
418 
419  demoMap->erase(makeKey<int>("Negative One"s));
420  BOOST_TEST(demoMap->size() == 0);
421  BOOST_TEST(demoMap->empty());
422 }
423 
424 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakContains, GenericMapFactory) {
425  using namespace std::string_literals;
426 
427  static GenericMapFactory const factory;
428  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
429 
430  BOOST_TEST(demoMap->contains(KEY0.getId()));
431  BOOST_TEST(demoMap->contains(KEY1.getId()));
432  BOOST_TEST(demoMap->contains(KEY2.getId()));
433  BOOST_TEST(demoMap->contains(KEY3.getId()));
434  BOOST_TEST(demoMap->contains(KEY4.getId()));
435  BOOST_TEST(demoMap->contains(KEY5.getId()));
436  BOOST_TEST(!demoMap->contains(6));
437 }
438 
439 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestContains, GenericMapFactory) {
440  static GenericMapFactory const factory;
441  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
442 
443  BOOST_TEST(demoMap->contains(KEY0));
444  BOOST_TEST(!demoMap->contains(makeKey<int>(KEY0.getId())));
445 
446  BOOST_TEST(demoMap->contains(KEY1));
447  BOOST_TEST(!demoMap->contains(makeKey<bool>(KEY1.getId())));
448 
449  BOOST_TEST(demoMap->contains(KEY2));
450  // VALUE2 is of a different type than KEY2, check that alternate key is absent
451  BOOST_TEST(!demoMap->contains(makeKey<decltype(VALUE2)>(KEY2.getId())));
452 
453  BOOST_TEST(demoMap->contains(KEY3));
454 
455  BOOST_TEST(demoMap->contains(KEY4));
456  // VALUE4 is of a different type than KEY4, check that alternate key is absent
457  BOOST_TEST(!demoMap->contains(makeKey<decltype(VALUE4)>(KEY4.getId())));
458 
459  BOOST_TEST(demoMap->contains(KEY5));
460  BOOST_TEST(demoMap->contains(makeKey<SimpleStorable>(KEY5.getId())));
461  BOOST_TEST(demoMap->contains(makeKey<Storable>(KEY5.getId())));
462 }
463 
464 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestKeys, GenericMapFactory) {
465  static GenericMapFactory const factory;
466  std::unique_ptr<GenericMap<int> const> demoMap = factory.makeGenericMap();
467  auto orderedKeys = demoMap->keys();
468  // GenericMaps don't have an iteration order yet
469  std::set<int> keys(orderedKeys.begin(), orderedKeys.end());
470 
471  BOOST_TEST(keys == std::set<int>({KEY0.getId(), KEY1.getId(), KEY2.getId(), KEY3.getId(), KEY4.getId(),
472  KEY5.getId()}));
473 }
474 
475 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestClearIdempotent, GenericMapFactory) {
476  static GenericMapFactory const factory;
477  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
478 
479  BOOST_TEST_REQUIRE(demoMap->empty());
480  demoMap->clear();
481  BOOST_TEST(demoMap->empty());
482 }
483 
484 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestClear, GenericMapFactory) {
485  using namespace std::string_literals;
486 
487  static GenericMapFactory const factory;
488  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
489 
490  demoMap->insert(makeKey<int>("prime"s), 3);
491  demoMap->insert(makeKey<std::string>("foo"s), "bar"s);
492 
493  BOOST_TEST_REQUIRE(!demoMap->empty());
494  demoMap->clear();
495  BOOST_TEST(demoMap->empty());
496 }
497 
498 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertInt, GenericMapFactory) {
499  using namespace std::string_literals;
500 
501  static GenericMapFactory const factory;
502  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
503 
504  BOOST_TEST_REQUIRE(demoMap->empty());
505 
506  int x = 27;
507  BOOST_TEST(demoMap->insert(makeKey<int>("cube"s), x) == true);
508  BOOST_TEST(demoMap->insert(makeKey<int>("cube"s), 0) == false);
509 
510  BOOST_TEST(!demoMap->empty());
511  BOOST_TEST(demoMap->size() == 1);
512  BOOST_TEST(demoMap->contains("cube"s));
513  BOOST_TEST(demoMap->contains(makeKey<int>("cube"s)));
514  BOOST_TEST(!demoMap->contains(makeKey<double>("cube"s)));
515  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == x);
516 
517  x = 0;
518  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) != x);
519 
520  demoMap->at(makeKey<int>("cube"s)) = 0;
521  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == 0);
522 }
523 
524 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakInsertInt, GenericMapFactory) {
525  using namespace std::string_literals;
526 
527  static GenericMapFactory const factory;
528  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
529 
530  BOOST_TEST_REQUIRE(demoMap->empty());
531 
532  auto insertResult = demoMap->insert("cube"s, 27);
533  BOOST_TEST(insertResult.second == true);
534  BOOST_TEST(demoMap->insert("cube"s, 0).second == false);
535 
536  BOOST_TEST(!demoMap->empty());
537  BOOST_TEST(demoMap->size() == 1);
538  BOOST_TEST(demoMap->contains("cube"s));
539  BOOST_TEST(demoMap->contains(insertResult.first));
540  BOOST_TEST(demoMap->contains(makeKey<int>("cube"s)));
541  BOOST_TEST(!demoMap->contains(makeKey<double>("cube"s)));
542  BOOST_TEST(demoMap->at(insertResult.first) == 27);
543  BOOST_TEST(demoMap->at(makeKey<int>("cube"s)) == 27);
544 
545  demoMap->at(insertResult.first) = 0;
546  BOOST_TEST(demoMap->at(insertResult.first) == 0);
547 }
548 
549 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertString, GenericMapFactory) {
550  using namespace std::string_literals;
551 
552  static GenericMapFactory const factory;
553  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
554 
555  BOOST_TEST_REQUIRE(demoMap->empty());
556 
557  std::string answer(
558  "I have a most elegant and wonderful proof, but this string is too small to contain it."s);
559  BOOST_TEST(demoMap->insert(makeKey<std::string>("Ultimate answer"s), answer) == true);
560  BOOST_TEST(demoMap->insert(makeKey<std::string>("OK"s), "Ook!"s) == true);
561  BOOST_TEST(demoMap->insert(makeKey<std::string>("Ultimate answer"s), "Something philosophical"s) ==
562  false);
563 
564  BOOST_TEST(!demoMap->empty());
565  BOOST_TEST(demoMap->size() == 2);
566  BOOST_TEST(demoMap->contains("OK"s));
567  BOOST_TEST(demoMap->contains(makeKey<std::string>("Ultimate answer"s)));
568  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) == answer);
569  BOOST_TEST(demoMap->at(makeKey<std::string>("OK"s)) == "Ook!"s);
570 
571  answer = "I don't know"s;
572  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) != answer);
573 }
574 
575 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestWeakInsertString, GenericMapFactory) {
576  using namespace std::string_literals;
577 
578  static GenericMapFactory const factory;
579  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
580 
581  BOOST_TEST_REQUIRE(demoMap->empty());
582 
583  auto insertResult1 = demoMap->insert("Ultimate answer"s, "Something philosophical"s);
584  BOOST_TEST(insertResult1.second == true);
585  auto insertResult2 = demoMap->insert("OK"s, "Ook!"s);
586  BOOST_TEST(insertResult2.second == true);
587 
588  BOOST_TEST(!demoMap->empty());
589  BOOST_TEST(demoMap->size() == 2);
590  BOOST_TEST(demoMap->contains(insertResult1.first));
591  BOOST_TEST(demoMap->contains(insertResult2.first));
592  BOOST_TEST(demoMap->contains("OK"s));
593  BOOST_TEST(demoMap->contains(makeKey<std::string>("Ultimate answer"s)));
594  BOOST_TEST(demoMap->at(insertResult1.first) == "Something philosophical"s);
595  BOOST_TEST(demoMap->at(makeKey<std::string>("Ultimate answer"s)) == "Something philosophical"s);
596  BOOST_TEST(demoMap->at(insertResult2.first) == "Ook!"s);
597  BOOST_TEST(demoMap->at(makeKey<std::string>("OK"s)) == "Ook!"s);
598 }
599 
600 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertStorable, GenericMapFactory) {
601  using namespace std::string_literals;
602 
603  static GenericMapFactory const factory;
604  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
605 
606  BOOST_TEST_REQUIRE(demoMap->empty());
607 
608  ComplexStorable object(3.1416);
609  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("foo"s), object) == true);
610  BOOST_TEST(demoMap->insert(makeKey<std::shared_ptr<ComplexStorable>>("bar"s),
611  std::make_shared<ComplexStorable>(3.141)) == true);
612  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("foo"s), SimpleStorable()) == false);
613  BOOST_TEST(demoMap->insert(makeKey<std::shared_ptr<SimpleStorable>>("bar"s),
614  std::make_shared<SimpleStorable>()) == false);
615 
616  BOOST_TEST(!demoMap->empty());
617  BOOST_TEST(demoMap->size() == 2);
618  BOOST_TEST(demoMap->contains("foo"s));
619  BOOST_TEST(demoMap->contains(makeKey<Storable>("foo"s)));
620  BOOST_TEST(demoMap->contains(makeKey<std::shared_ptr<ComplexStorable>>("bar"s)));
621 
622  // ComplexStorable::operator== is asymmetric
623  // Use BOOST_CHECK_EQUAL to avoid BOOST_TEST bug from Storable being abstract
624  BOOST_TEST(object == demoMap->at(makeKey<SimpleStorable>("foo"s)));
625  object = ComplexStorable(1.4);
626  BOOST_TEST(object != demoMap->at(makeKey<SimpleStorable>("foo"s)));
627  BOOST_TEST(*(demoMap->at(makeKey<std::shared_ptr<ComplexStorable>>("bar"s))) == ComplexStorable(3.141));
628 }
629 
630 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInterleavedInserts, GenericMapFactory) {
631  using namespace std::string_literals;
632 
633  static GenericMapFactory const factory;
634  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
635 
636  BOOST_TEST_REQUIRE(demoMap->empty());
637 
638  BOOST_TEST(demoMap->insert(makeKey<int>("key1"s), 3) == true);
639  BOOST_TEST(demoMap->insert(makeKey<double>("key1"s), 1.0) == false);
640  BOOST_TEST(demoMap->insert<Storable>(makeKey<Storable>("key2"s), SimpleStorable()) == true);
641  BOOST_TEST(demoMap->insert(makeKey<std::string>("key3"s), "Test value"s) == true);
642  BOOST_TEST(demoMap->insert(makeKey<std::string>("key4"s), "This is some text"s) == true);
643  std::string const message = "Unknown value for key5."s;
644  BOOST_TEST(demoMap->insert(makeKey<std::string>("key5"s), message) == true);
645  BOOST_TEST(demoMap->insert(makeKey<int>("key3"s), 20) == false);
646  BOOST_TEST(demoMap->insert<double>(makeKey<double>("key6"s), 42) == true);
647 
648  BOOST_TEST(!demoMap->empty());
649  BOOST_TEST(demoMap->size() == 6);
650  BOOST_TEST(demoMap->at(makeKey<int>("key1"s)) == 3);
651  BOOST_TEST(demoMap->at(makeKey<double>("key6"s)) == 42);
652  BOOST_TEST(demoMap->at(makeKey<SimpleStorable>("key2"s)) == SimpleStorable());
653  BOOST_TEST(demoMap->at(makeKey<std::string>("key3"s)) == "Test value"s);
654  BOOST_TEST(demoMap->at(makeKey<std::string>("key4"s)) == "This is some text"s);
655  BOOST_TEST(demoMap->at(makeKey<std::string>("key5"s)) == message);
656 }
657 
658 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestErase, GenericMapFactory) {
659  using namespace std::string_literals;
660 
661  static GenericMapFactory const factory;
662  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
663 
664  demoMap->insert(makeKey<int>("Ultimate answer"s), 42);
665  BOOST_TEST_REQUIRE(demoMap->size() == 1);
666 
667  BOOST_TEST(demoMap->erase(makeKey<std::string>("Ultimate answer"s)) == false);
668  BOOST_TEST(demoMap->size() == 1);
669  BOOST_TEST(demoMap->erase(makeKey<int>("Ultimate answer"s)) == true);
670  BOOST_TEST(demoMap->size() == 0);
671 }
672 
673 BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestInsertEraseInsert, GenericMapFactory) {
674  using namespace std::string_literals;
675 
676  static GenericMapFactory const factory;
677  std::unique_ptr<MutableGenericMap<std::string>> demoMap = factory.makeMutableGenericMap();
678 
679  BOOST_TEST_REQUIRE(demoMap->empty());
680 
681  BOOST_TEST(demoMap->insert(makeKey<int>("Ultimate answer"s), 42) == true);
682  BOOST_TEST(demoMap->insert(makeKey<int>("OK"s), 200) == true);
683  BOOST_TEST(demoMap->erase(makeKey<int>("Ultimate answer"s)) == true);
684  BOOST_TEST(demoMap->insert(makeKey<double>("Ultimate answer"s), 3.1415927) == true);
685 
686  BOOST_TEST(!demoMap->empty());
687  BOOST_TEST(demoMap->size() == 2);
688  BOOST_TEST(demoMap->contains("OK"s));
689  BOOST_TEST(!demoMap->contains(makeKey<int>("Ultimate answer"s)));
690  BOOST_TEST(demoMap->contains(makeKey<double>("Ultimate answer"s)));
691  BOOST_TEST(demoMap->at(makeKey<double>("Ultimate answer"s)) == 3.1415927);
692 }
693 
701 template <class GenericMapFactory>
702 void addGenericMapTestCases(boost::unit_test::test_suite* const suite) {
703  using factories = boost::mpl::list<GenericMapFactory>;
704 
705  suite->add(BOOST_TEST_CASE_TEMPLATE(TestConstAt, factories));
706  suite->add(BOOST_TEST_CASE_TEMPLATE(TestAt, factories));
707  suite->add(BOOST_TEST_CASE_TEMPLATE(TestEquals, factories));
708  suite->add(BOOST_TEST_CASE_TEMPLATE(TestSize, factories));
709  suite->add(BOOST_TEST_CASE_TEMPLATE(TestWeakContains, factories));
710  suite->add(BOOST_TEST_CASE_TEMPLATE(TestContains, factories));
711  suite->add(BOOST_TEST_CASE_TEMPLATE(TestKeys, factories));
712  suite->add(BOOST_TEST_CASE_TEMPLATE(TestConstVisitor, factories));
713  suite->add(BOOST_TEST_CASE_TEMPLATE(TestModifyingVoidVisitor, factories));
714  suite->add(BOOST_TEST_CASE_TEMPLATE(TestModifyingReturningVisitor, factories));
715 }
716 
726 template <class GenericMapFactory>
727 void addMutableGenericMapTestCases(boost::unit_test::test_suite* const suite) {
728  using factories = boost::mpl::list<GenericMapFactory>;
729 
730  addGenericMapTestCases<GenericMapFactory>(suite);
731 
732  suite->add(BOOST_TEST_CASE_TEMPLATE(TestMutableEquals, factories));
733  suite->add(BOOST_TEST_CASE_TEMPLATE(TestMutableSize, factories));
734  suite->add(BOOST_TEST_CASE_TEMPLATE(TestClear, factories));
735  suite->add(BOOST_TEST_CASE_TEMPLATE(TestClearIdempotent, factories));
736  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertInt, factories));
737  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertString, factories));
738  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertStorable, factories));
739  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInterleavedInserts, factories));
740  suite->add(BOOST_TEST_CASE_TEMPLATE(TestErase, factories));
741  suite->add(BOOST_TEST_CASE_TEMPLATE(TestInsertEraseInsert, factories));
742 }
743 
752 template <class GenericMapFactory>
753 inline void addGenericMapTestCases() {
754  addGenericMapTestCases<GenericMapFactory>(&(boost::unit_test::framework::master_test_suite()));
755 }
756 
766 template <class GenericMapFactory>
768  addMutableGenericMapTestCases<GenericMapFactory>(&(boost::unit_test::framework::master_test_suite()));
769 }
770 
771 } // namespace test
772 } // namespace typehandling
773 } // namespace afw
774 } // namespace lsst
775 
776 #endif
Interface supporting iteration over heterogenous containers.
Definition: Storable.h:56
T to_string(T... args)
BOOST_TEST_CASE_TEMPLATE_FUNCTION(TestConstAt, GenericMapFactory)
Definition: test.h:152
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: GenericMap.h:162
void addMutableGenericMapTestCases(boost::unit_test::test_suite *const suite)
Create generic test cases for a specific MutableGenericMap implementation.
Definition: test.h:727
STL class.
T push_back(T... args)
A base class for image defects.
T str(T... args)
Abstract factory that creates GenericMap and MutableGenericMap instances as needed.
Definition: test.h:132
solver_t * s
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.
Key< U > key
Definition: Schema.cc:281
ItemVariant const * other
Definition: Schema.cc:56
void addGenericMapTestCases(boost::unit_test::test_suite *const suite)
Create generic test cases for a specific GenericMap implementation.
Definition: test.h:702