Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#include "SimpleEDProductGetter.h"

#include "DataFormats/Common/interface/EDProductGetter.h"
#include "DataFormats/Common/interface/Ref.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "catch.hpp"

#include <iostream>
#include <string>
#include <utility>
#include <thread>
#include <atomic>

using product1_t = std::vector<int>;
using product2_t = std::map<std::string, int>;
using ref1_t = edm::Ref<product1_t>;
// using ref2_t = edm::Ref<product2_t, int>;

TEST_CASE("Ref tests", "[Ref]") {
  SECTION("default constructor") {
    ref1_t default_ref;
    REQUIRE(default_ref.isNull());
    REQUIRE(default_ref.isNonnull() == false);
    REQUIRE(!default_ref);
    REQUIRE(default_ref.productGetter() == 0);
    REQUIRE(default_ref.id().isValid() == false);
    REQUIRE(default_ref.isAvailable() == false);
  }

  // SECTION("default constructor with string key") {
  //   ref2_t default_ref;
  //   REQUIRE(default_ref.isNull());
  //   REQUIRE(default_ref.isNonnull()==false);
  //   REQUIRE(!default_ref);
  //   REQUIRE(default_ref.productGetter()==0);
  //   REQUIRE(default_ref.id().isValid()==false);
  //   REQUIRE(default_ref.id().isAvailable()==false);
  // }

  SECTION("non-default constructor") {
    SimpleEDProductGetter getter;
    edm::ProductID id(1, 201U);
    REQUIRE(id.isValid());
    auto prod = std::make_unique<product1_t>();
    prod->push_back(1);
    prod->push_back(2);
    getter.addProduct(id, std::move(prod));

    ref1_t ref0(id, 0, &getter);
    REQUIRE(ref0.isNull() == false);
    REQUIRE(ref0.isNonnull());
    REQUIRE(!!ref0);
    REQUIRE(ref0.productGetter() == &getter);
    REQUIRE(ref0.id().isValid());
    REQUIRE(ref0.isAvailable() == true);
    REQUIRE(*ref0 == 1);

    ref1_t ref1(id, 1, &getter);
    REQUIRE(ref1.isNonnull());
    REQUIRE(ref1.isAvailable() == true);
    REQUIRE(*ref1 == 2);
  }

  // SECTION("non-default constructor 2") {
  //   SimpleEDProductGetter getter;
  //   edm::EDProductGetter::Operate op(&getter);
  //   edm::ProductID id(1, 201U);
  //   REQUIRE(id.isValid());
  //   auto prod = std::make_unique<product2_t>();
  //   prod->insert(std::make_pair(std::string("a"), 1));
  //   prod->insert(std::make_pair(std::string("b"), 2));
  //   prod->insert(std::make_pair(std::string("c"), 3));
  //   getter.addProduct(id, prod);
  //   ref2_t refa(id, std::string("a"), &getter);
  //   REQUIRE(refa.isNull()==false);
  //   REQUIRE(refa.isNonnull());
  //   REQUIRE(!!refa);
  //   REQUIRE(refa.productGetter()==&getter);
  //   REQUIRE(refa.id().isValid());
  //   REQUIRE(*refa == 1);
  //   ref2_t refb(id, "b", &getter);
  //   REQUIRE(refb.isNonnull());
  //   REQUIRE(*refb == 2);
  // }

  SECTION("using wrong productid") {
    SimpleEDProductGetter getter;
    edm::ProductID id(1, 1U);
    REQUIRE(id.isValid());
    auto prod = std::make_unique<product1_t>();
    prod->push_back(1);
    prod->push_back(2);
    getter.addProduct(id, std::move(prod));
    edm::ProductID wrong_id(1, 100U);
    REQUIRE(wrong_id.isValid());
    ref1_t ref(wrong_id, 0, &getter);
    REQUIRE_THROWS_AS(*ref, edm::Exception);
    REQUIRE_THROWS_AS(ref.operator->(), edm::Exception);
  }

  SECTION("threading") {
    constexpr int kNThreads = 8;
    std::atomic<int> s_threadsStarting{kNThreads};
    SimpleEDProductGetter getter;
    edm::ProductID id(1, 1U);
    REQUIRE(id.isValid());
    auto prod = std::make_unique<product1_t>();
    prod->push_back(1);
    prod->push_back(2);
    getter.addProduct(id, std::move(prod));
    ref1_t ref0(id, 0, &getter);
    ref1_t ref1(id, 1, &getter);
    std::vector<std::thread> threads;
    std::vector<std::exception_ptr> excepPtrs(kNThreads, std::exception_ptr{});
    for (unsigned int i = 0; i < kNThreads; ++i) {
      threads.emplace_back([&ref0, &ref1, i, &excepPtrs, &s_threadsStarting]() {
        --s_threadsStarting;
        while (0 != s_threadsStarting) {
        }
        try {
          REQUIRE(*ref0 == 1);
          REQUIRE(*ref1 == 2);
        } catch (...) {
          excepPtrs[i] = std::current_exception();
        }
      });
    }
    for (auto& t : threads) {
      t.join();
    }
    for (auto& e : excepPtrs) {
      if (e) {
        std::rethrow_exception(e);
      }
    }
  }
}