Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:03:56

0001 /*
0002  *  CMSSW
0003  */
0004 #define CATCH_CONFIG_MAIN
0005 #include "catch.hpp"
0006 
0007 #include "DataFormats/Common/interface/DetSetVector.h"
0008 #include "DataFormats/Common/interface/Ref.h"
0009 #include "DataFormats/Common/interface/TestHandle.h"
0010 #include "DataFormats/Provenance/interface/ProductID.h"
0011 
0012 #include <algorithm>
0013 #include <cassert>
0014 #include <iterator>
0015 #include <ostream>
0016 #include <stdexcept>
0017 #include <vector>
0018 
0019 using namespace edm;
0020 
0021 //------------------------------------------------------
0022 // This is a sample VALUE class, almost the simplest possible.
0023 //------------------------------------------------------
0024 
0025 struct Empty {};
0026 
0027 template <typename BASE>
0028 class ValueT : public BASE {
0029 public:
0030   // VALUES must be default constructible
0031   ValueT() : d_(0.0) {}
0032 
0033   // This constructor is used for testing; it is not required by the
0034   // concept VALUE.
0035   explicit ValueT(double d) : d_(d) {}
0036 
0037   // This access function is used for testing; it is not required by
0038   // the concept VALUE.
0039   double val() const { return d_; }
0040 
0041   // VALUES must be destructible
0042   ~ValueT() {}
0043 
0044   // VALUES must be LessThanComparable
0045   bool operator<(ValueT const& other) const { return d_ < other.d_; }
0046 
0047   // The private stuff below is all implementation detail, and not
0048   // required by the concept VALUE.
0049 private:
0050   double d_;
0051 };
0052 
0053 typedef edm::DoNotSortUponInsertion DNS;
0054 
0055 template <>
0056 bool ValueT<DNS>::operator<(ValueT<DNS> const& /*other*/) const {
0057   throw std::logic_error("You can't sort me!");
0058 }
0059 
0060 typedef ValueT<Empty> Value;
0061 //typedef ValueT<DNS> Value; // NoSort;
0062 
0063 //------------------------------------------------------
0064 // The stream insertion operator is not required; it is used here
0065 // for diagnostic output.
0066 //
0067 // It is inline to avoid multiple definition problems. Note that this
0068 // cc file is *not* a compilation unit; it is actually an include
0069 // file, which the build system combines with others to create a
0070 // compilation unit.
0071 //
0072 //------------------------------------------------------
0073 
0074 template <typename BASE>
0075 std::ostream& operator<<(std::ostream& os, ValueT<BASE> const& v) {
0076   os << " val: " << v.val();
0077   return os;
0078 }
0079 
0080 typedef edm::DetSetVector<Value> coll_type;
0081 typedef coll_type::detset detset;
0082 
0083 void check_outer_collection_order(coll_type const& c) {
0084   if (c.size() < 2)
0085     return;
0086   coll_type::const_iterator i = c.begin();
0087   coll_type::const_iterator e = c.end();
0088   // Invariant: sequence from prev to i is correctly ordered
0089   coll_type::const_iterator prev(i);
0090   ++i;
0091   for (; i != e; ++i, ++prev) {
0092     // We don't use CPPUNIT_ASSERT because it gives us grossly
0093     // insufficient context if a failure occurs.
0094     REQUIRE(prev->id < i->id);
0095   }
0096 }
0097 
0098 void check_inner_collection_order(detset const& d) {
0099   if (d.data.size() < 2)
0100     return;
0101   detset::const_iterator i = d.data.begin();
0102   detset::const_iterator e = d.data.end();
0103   // Invariant: sequence from prev to i is correctly ordered
0104   detset::const_iterator prev(i);
0105   ++i;
0106   for (; i != e; ++i, ++prev) {
0107     // We don't use CPPUNIT_ASSERT because it gives us grossly
0108     // insufficient context if a failure occurs.
0109     //
0110     // We don't check that *prev < *i because they might be equal.
0111     // We don't want to require an op<= or op==.
0112     REQUIRE(!(*i < *prev));
0113   }
0114 }
0115 
0116 void printDetSet(detset const& ds, std::ostream& os) {
0117   os << "size: " << ds.data.size() << '\n' << "values: ";
0118   std::copy(ds.data.begin(), ds.data.end(), std::ostream_iterator<detset::value_type>(os, " "));
0119 }
0120 
0121 void sanity_check(coll_type const& c) {
0122   check_outer_collection_order(c);
0123   for (coll_type::const_iterator i = c.begin(), e = c.end(); i != e; ++i) {
0124     //       printDetSet(*i, std::cerr);
0125     //       std::cerr << '\n';
0126     check_inner_collection_order(*i);
0127   }
0128 }
0129 
0130 void check_ids(coll_type const& c) {
0131   // Long way to get all ids...
0132   std::vector<det_id_type> all_ids;
0133   for (coll_type::const_iterator i = c.begin(), e = c.end(); i != e; ++i) {
0134     all_ids.push_back(i->id);
0135   }
0136   REQUIRE(c.size() == all_ids.size());
0137 
0138   std::vector<det_id_type> nice_ids;
0139   c.getIds(nice_ids);
0140   REQUIRE(all_ids == nice_ids);
0141 }
0142 
0143 namespace {
0144   template <typename T>
0145   struct DSVGetter : edm::EDProductGetter {
0146     DSVGetter() : edm::EDProductGetter(), prod_(nullptr) {}
0147     WrapperBase const* getIt(ProductID const&) const override { return prod_; }
0148 
0149     std::optional<std::tuple<edm::WrapperBase const*, unsigned int>> getThinnedProduct(ProductID const&,
0150                                                                                        unsigned int) const override {
0151       return std::nullopt;
0152     }
0153 
0154     void getThinnedProducts(ProductID const& pid,
0155                             std::vector<WrapperBase const*>& wrappers,
0156                             std::vector<unsigned int>& keys) const override {}
0157 
0158     edm::OptionalThinnedKey getThinnedKeyFrom(ProductID const&, unsigned int, ProductID const&) const override {
0159       return std::monostate{};
0160     }
0161 
0162     unsigned int transitionIndex_() const override { return 0U; }
0163 
0164     edm::Wrapper<T> const* prod_;
0165   };
0166 }  // namespace
0167 
0168 TEST_CASE("test DetSetVector", "[DetSetVector]") {
0169   SECTION("detsetTest") {
0170     //std::cerr << "\nStart DetSetVector_t detsetTest()\n";
0171     detset d;
0172     Value v1(1.1);
0173     Value v2(2.2);
0174     d.id = edm::det_id_type(3);
0175     d.data.push_back(v1);
0176     d.data.push_back(v2);
0177     std::sort(d.data.begin(), d.data.end());
0178     check_inner_collection_order(d);
0179     //std::cerr << "\nEnd DetSetVector_t detsetTest()\n";
0180   }
0181 
0182   SECTION("refTest") {
0183     coll_type c;
0184     detset d3;
0185     Value v1(1.1);
0186     Value v2(2.2);
0187     d3.id = edm::det_id_type(3);
0188     d3.data.push_back(v1);
0189     d3.data.push_back(v2);
0190     c.insert(d3);
0191     detset d1;
0192     Value v1a(4.1);
0193     Value v2a(3.2);
0194     d1.id = edm::det_id_type(1);
0195     d1.data.push_back(v1a);
0196     d1.data.push_back(v2a);
0197     c.insert(d1);
0198     c.post_insert();
0199 
0200     auto pC = std::make_unique<coll_type>(c);
0201     edm::Wrapper<coll_type> wrapper(std::move(pC));
0202     DSVGetter<coll_type> theGetter;
0203     theGetter.prod_ = &wrapper;
0204 
0205     typedef edm::Ref<coll_type, detset> RefDetSet;
0206     typedef edm::Ref<coll_type, Value> RefDet;
0207 
0208     {
0209       RefDetSet refSet(edm::ProductID(1, 1), 0, &theGetter);
0210       REQUIRE((!(d1 < *refSet) && !(*refSet < d1)));
0211     }
0212     {
0213       RefDetSet refSet(edm::ProductID(1, 1), 1, &theGetter);
0214       REQUIRE((!(d3 < *refSet) && !(*refSet < d3)));
0215     }
0216     {
0217       RefDet refDet(edm::ProductID(1, 1), RefDet::key_type(3, 0), &theGetter);
0218       REQUIRE((!(v1 < *refDet) && !(*refDet < v1)));
0219     }
0220 
0221     {
0222       TestHandle<coll_type> pc2(&c, ProductID(1, 1));
0223       RefDet refDet = makeRefToDetSetVector(pc2, det_id_type(3), c[3].data.begin());
0224       REQUIRE((!(v1 < *refDet) && !(*refDet < v1)));
0225     }
0226 
0227     using namespace Catch::Matchers;
0228     SECTION("bad detid") {
0229       TestHandle<coll_type> pc2(&c, ProductID(1, 1));
0230       REQUIRE_THROWS_MATCHES(
0231           makeRefToDetSetVector(pc2, det_id_type(12), c[3].data.begin()),
0232           edm::Exception,
0233           Predicate<edm::Exception>(
0234               [](auto const& iExcept) { return iExcept.categoryCode() == edm::errors::InvalidReference; },
0235               "Exception has wrong category"));
0236     }
0237 
0238     SECTION("bad iterator") {
0239       TestHandle<coll_type> pc2(&c, ProductID(1, 1));
0240       REQUIRE_THROWS_MATCHES(
0241           makeRefToDetSetVector(pc2, det_id_type(1), c[3].data.begin()),
0242           edm::Exception,
0243           Predicate<edm::Exception>([](auto const& x) { return x.categoryCode() == edm::errors::InvalidReference; },
0244                                     "Exception has wrong category"));
0245     }
0246   }
0247 
0248   SECTION("work") {
0249     coll_type c1;
0250     c1.post_insert();
0251     sanity_check(c1);
0252     REQUIRE(c1.size() == 0);
0253     REQUIRE(c1.empty());
0254 
0255     coll_type c2(c1);
0256     REQUIRE(c2.size() == c1.size());
0257     sanity_check(c2);
0258     coll_type c;
0259     sanity_check(c);
0260     {
0261       detset d;
0262       Value v1(1.1);
0263       Value v2(2.2);
0264       d.id = edm::det_id_type(3);
0265       d.data.push_back(v1);
0266       d.data.push_back(v2);
0267       c.insert(d);
0268       c.post_insert();
0269     }
0270     sanity_check(c);
0271     REQUIRE(c.size() == 1);
0272     {
0273       detset d;
0274       Value v1(4.1);
0275       Value v2(3.2);
0276       d.id = edm::det_id_type(1);
0277       d.data.push_back(v1);
0278       d.data.push_back(v2);
0279       c.insert(d);
0280       c.post_insert();
0281     }
0282     sanity_check(c);
0283     REQUIRE(c.size() == 2);
0284 
0285     {
0286       detset d;
0287       Value v1(1.1);
0288       Value v2(1.2);
0289       Value v3(2.2);
0290       d.id = edm::det_id_type(10);
0291       d.data.push_back(v3);
0292       d.data.push_back(v2);
0293       d.data.push_back(v1);
0294       c.insert(d);
0295       c.post_insert();
0296     }
0297     sanity_check(c);
0298     REQUIRE(c.size() == 3);
0299 
0300     coll_type another;
0301     c.swap(another);
0302     REQUIRE(c.empty());
0303     REQUIRE(another.size() == 3);
0304     sanity_check(c);
0305     sanity_check(another);
0306 
0307     c.swap(another);
0308     REQUIRE(c.size() == 3);
0309 
0310     {
0311       // We should not find anything with ID=11
0312       coll_type::iterator i = c.find(edm::det_id_type(11));
0313       REQUIRE(i == c.end());
0314 
0315       coll_type::const_iterator ci = static_cast<coll_type const&>(c).find(edm::det_id_type(11));
0316       REQUIRE(ci == c.end());
0317     }
0318     {
0319       // We should find  ID=10
0320       coll_type::iterator i = c.find(edm::det_id_type(10));
0321       REQUIRE(i != c.end());
0322       REQUIRE(i->id == 10);
0323       REQUIRE(i->data.size() == 3);
0324     }
0325     using namespace Catch::Matchers;
0326     {
0327       // We should not find ID=100; op[] should throw.
0328       SECTION("op[] should throw") {
0329         REQUIRE_THROWS_MATCHES(
0330             c[edm::det_id_type(100)],
0331             edm::Exception,
0332             Predicate<edm::Exception>([](auto const& x) { return x.categoryCode() == edm::errors::InvalidReference; },
0333                                       "Exception has wrong category"));
0334       }
0335     }
0336 
0337     {
0338       // We should not find ID=100; op[] should throw.
0339       SECTION("coll_type op[] should throw") {
0340         REQUIRE_THROWS_MATCHES(
0341             static_cast<coll_type const&>(c)[edm::det_id_type(100)],
0342             edm::Exception,
0343             Predicate<edm::Exception>([](auto const& x) { return x.categoryCode() == edm::errors::InvalidReference; },
0344                                       "Exception has wrong category"));
0345       }
0346     }
0347     {
0348       // We should find id = 3
0349       coll_type const& rc = c;
0350       coll_type::const_reference r = rc[3];
0351       REQUIRE(r.id == edm::det_id_type(3));
0352       REQUIRE(r.data.size() == 2);
0353 
0354       coll_type::reference r2 = c[3];
0355       REQUIRE(r2.id == edm::det_id_type(3));
0356       REQUIRE(r2.data.size() == 2);
0357     }
0358 
0359     {
0360       // We should not find id = 17, but a new empty DetSet should be
0361       // inserted, carrying the correct DetId.
0362       coll_type::size_type oldsize = c.size();
0363       coll_type::reference r = c.find_or_insert(edm::det_id_type(17));
0364       coll_type::size_type newsize = c.size();
0365       REQUIRE(newsize > oldsize);
0366       REQUIRE(newsize == (oldsize + 1));
0367       REQUIRE(r.id == edm::det_id_type(17));
0368       REQUIRE(r.data.size() == 0);
0369       r.data.push_back(Value(10.1));
0370       r.data.push_back(Value(9.1));
0371       r.data.push_back(Value(4.0));
0372       r.data.push_back(Value(4.0));
0373       c.post_insert();
0374       sanity_check(c);
0375     }
0376     {
0377       // Make sure we can swap in a vector.
0378       unsigned int const numDetSets = 20;
0379       unsigned int const detSetSize = 14;
0380       std::vector<detset> v;
0381       for (unsigned int i = 0; i < numDetSets; ++i) {
0382         detset d(i);
0383         for (unsigned int j = 0; j < detSetSize; ++j) {
0384           d.data.push_back(Value(100 * i + 1.0 / j));
0385         }
0386         v.push_back(d);
0387       }
0388       REQUIRE(v.size() == numDetSets);
0389       coll_type c3(v);
0390       c3.post_insert();
0391       REQUIRE(v.size() == 0);
0392       REQUIRE(c3.size() == numDetSets);
0393       sanity_check(c3);
0394 
0395       coll_type c4;
0396       c4 = c3;
0397       REQUIRE(c4.size() == numDetSets);
0398       sanity_check(c3);
0399       sanity_check(c4);
0400 
0401       check_ids(c3);
0402     }
0403   }
0404 }