#include "ProducerWithPSetDesc.h"
#include "DataFormats/TestObjects/interface/ThingCollection.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"

#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/ParameterSet/interface/ParameterDescriptionBase.h"
#include "FWCore/ParameterSet/interface/ParameterDescription.h"
#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
#include "FWCore/ParameterSet/interface/ParameterWildcard.h"
#include "FWCore/ParameterSet/interface/EmptyGroupDescription.h"
#include "DataFormats/Provenance/interface/EventRange.h"
#include "DataFormats/Provenance/interface/LuminosityBlockID.h"
#include "DataFormats/Provenance/interface/EventID.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "FWCore/Utilities/interface/FileInPath.h"
#include "FWCore/ParameterSet/interface/PluginDescription.h"
#include "FWCore/ParameterSet/interface/ValidatedPluginMacros.h"
#include "FWCore/ParameterSet/interface/ValidatedPluginFactoryMacros.h"

#include <vector>
#include <limits>
#include <string>
#include <iostream>

namespace edmtest {

  struct AnotherIntMakerBase {
    virtual ~AnotherIntMakerBase() = default;
    virtual int value() const = 0;
  };

  using AnotherIntFactory = edmplugin::PluginFactory<AnotherIntMakerBase*(edm::ParameterSet const&)>;

  struct AnotherOneMaker : public AnotherIntMakerBase {
    explicit AnotherOneMaker(edm::ParameterSet const&) {}
    int value() const final { return 1; };

    static void fillPSetDescription(edm::ParameterSetDescription&) {}
  };

  struct AnotherValueMaker : public AnotherIntMakerBase {
    explicit AnotherValueMaker(edm::ParameterSet const& iPSet) : value_{iPSet.getParameter<int>("value")} {}
    int value() const final { return value_; };

    static void fillPSetDescription(edm::ParameterSetDescription& iDesc) { iDesc.add<int>("value", 5); }
    int value_;
  };
}  // namespace edmtest
EDM_REGISTER_VALIDATED_PLUGINFACTORY(edmtest::AnotherIntFactory, "edmtestAnotherIntFactory");
DEFINE_EDM_VALIDATED_PLUGIN(edmtest::AnotherIntFactory, edmtest::AnotherOneMaker, "edmtestAnotherOneMaker");
DEFINE_EDM_VALIDATED_PLUGIN(edmtest::AnotherIntFactory, edmtest::AnotherValueMaker, "edmtestAnotherValueMaker");

namespace edmtest {

  ProducerWithPSetDesc::ProducerWithPSetDesc(edm::ParameterSet const& ps) {
    testingAutoGeneratedCfi = ps.getUntrackedParameter<bool>("testingAutoGeneratedCfi", true);

    assert(ps.getParameter<int>("p_int") == 2147483647);
    assert(ps.getUntrackedParameter<int>("p_int_untracked") == -2147483647);
    if (testingAutoGeneratedCfi)
      assert(ps.getParameter<int>("p_int_opt") == 0);
    if (testingAutoGeneratedCfi) {
      assert(ps.getUntrackedParameter<int>("p_int_optuntracked") == 7);
      assert(!ps.exists("p_int_opt_nd"));
      assert(!ps.exists("p_int_optuntracked_nd"));
    } else {
      assert(!ps.exists("p_int_optuntracked"));
      assert(ps.getParameter<int>("p_int_opt_nd") == 11);
      assert(ps.getUntrackedParameter<int>("p_int_optuntracked_nd") == 12);
    }

    std::vector<int> vint;
    vint = ps.getParameter<std::vector<int>>("vint1");
    assert(vint.empty());
    vint = ps.getParameter<std::vector<int>>("vint2");
    assert(vint[0] == 2147483647);
    vint = ps.getParameter<std::vector<int>>("vint3");
    assert(vint[0] == 2147483647);
    assert(vint[1] == -2147483647);
    std::array<int, 2> testArray = ps.getParameter<std::array<int, 2>>(std::string("vint3"));
    assert(testArray[0] == 2147483647);
    assert(testArray[1] == -2147483647);
    std::array<int, 2> testArray1 = ps.getParameter<std::array<int, 2>>("vint3");
    assert(testArray1[0] == 2147483647);
    assert(testArray1[1] == -2147483647);
    vint = ps.getParameter<std::vector<int>>("vint4");
    assert(vint[0] == 2147483647);
    assert(vint[1] == -2147483647);
    assert(vint[2] == 0);

    assert(ps.getParameter<unsigned>("uint1") == 4294967295U);
    assert(ps.getUntrackedParameter<unsigned>("uint2") == 0);

    std::vector<unsigned> vuint;
    vuint = ps.getParameter<std::vector<unsigned>>("vuint1");
    assert(vuint.empty());
    vuint = ps.getParameter<std::vector<unsigned>>("vuint2");
    assert(vuint[0] == 4294967295U);
    vuint = ps.getParameter<std::vector<unsigned>>("vuint3");
    assert(vuint[0] == 4294967295U);
    assert(vuint[1] == 0);
    vuint = ps.getParameter<std::vector<unsigned>>("vuint4");
    assert(vuint[0] == 4294967295U);
    assert(vuint[1] == 0);
    assert(vuint[2] == 11);

    assert(ps.getParameter<long long>("int64v1") == 9000000000000000000LL);
    assert(ps.getParameter<long long>("int64v2") == -9000000000000000000LL);
    assert(ps.getParameter<long long>("int64v3") == 0);

    std::vector<long long> vint64;
    vint64 = ps.getParameter<std::vector<long long>>("vint64v1");
    assert(vint64.empty());
    vint64 = ps.getParameter<std::vector<long long>>("vint64v2");
    assert(vint64[0] == 9000000000000000000LL);
    vint64 = ps.getParameter<std::vector<long long>>("vint64v3");
    assert(vint64[0] == 9000000000000000000LL);
    assert(vint64[1] == -9000000000000000000LL);
    vint64 = ps.getParameter<std::vector<long long>>("vint64v4");
    assert(vint64[0] == 9000000000000000000LL);
    assert(vint64[1] == -9000000000000000000LL);
    assert(vint64[2] == 0);

    assert(ps.getParameter<unsigned long long>("uint64v1") == 18000000000000000000ULL);
    assert(ps.getUntrackedParameter<unsigned long long>("uint64v2") == 0);

    std::vector<unsigned long long> vuint64;
    vuint64 = ps.getParameter<std::vector<unsigned long long>>("vuint64v1");
    assert(vuint64.empty());
    vuint64 = ps.getParameter<std::vector<unsigned long long>>("vuint64v2");
    assert(vuint64[0] == 18000000000000000000ULL);
    vuint64 = ps.getParameter<std::vector<unsigned long long>>("vuint64v3");
    assert(vuint64[0] == 18000000000000000000ULL);
    assert(vuint64[1] == 0);
    vuint64 = ps.getParameter<std::vector<unsigned long long>>("vuint64v4");
    assert(vuint64[0] == 18000000000000000000ULL);
    assert(vuint64[1] == 0);
    assert(vuint64[2] == 11);

    // This one does not work because the precision in the ParameterSet stringified
    // format is 16 instead of 17.
    // assert(ps.getParameter<double>("doublev1") == std::numeric_limits<double>::min());
    assert(ps.getUntrackedParameter<double>("doublev2") == 0.0);
    assert(fabs(ps.getUntrackedParameter<double>("doublev3") - 0.3) < 0.0000001);

    std::vector<double> vdouble;
    vdouble = ps.getParameter<std::vector<double>>("vdoublev1");
    assert(vdouble.empty());
    // cmsRun will fail with a value this big
    // vdouble.push_back(std::numeric_limits<double>::max());
    // This works though
    vdouble = ps.getParameter<std::vector<double>>("vdoublev2");
    assert(vdouble[0] == 1e+300);
    vdouble = ps.getParameter<std::vector<double>>("vdoublev3");
    assert(vdouble[0] == 1e+300);
    assert(vdouble[1] == 0.0);
    vdouble = ps.getParameter<std::vector<double>>("vdoublev4");
    assert(vdouble[0] == 1e+300);
    assert(vdouble[1] == 0.0);
    assert(vdouble[2] == 11.0);
    vdouble = ps.getParameter<std::vector<double>>("vdoublev5");
    assert(vdouble[0] == 1e+300);
    assert(vdouble[1] == 0.0);
    assert(vdouble[2] == 11.0);
    assert(fabs(vdouble[3] - 0.3) < 0.0000001);

    assert(ps.getParameter<bool>("boolv1") == true);
    assert(ps.getParameter<bool>("boolv2") == false);

    std::string test("Hello");
    assert(ps.getParameter<std::string>("stringv1") == test);
    test.clear();
    assert(ps.getParameter<std::string>("stringv2") == test);

    std::vector<std::string> vstring;
    vstring = ps.getParameter<std::vector<std::string>>("vstringv1");
    assert(vstring.empty());
    vstring = ps.getParameter<std::vector<std::string>>("vstringv2");
    assert(vstring[0] == std::string("Hello"));
    vstring = ps.getParameter<std::vector<std::string>>("vstringv3");
    assert(vstring[0] == std::string("Hello"));
    assert(vstring[1] == std::string("World"));
    vstring = ps.getParameter<std::vector<std::string>>("vstringv4");
    assert(vstring[0] == std::string("Hello"));
    assert(vstring[1] == std::string("World"));
    assert(vstring[2] == std::string(""));

    edm::EventID eventID1(11, 0, 12);
    assert(ps.getParameter<edm::EventID>("eventIDv1") == eventID1);
    edm::EventID eventID2(101, 0, 102);
    assert(ps.getParameter<edm::EventID>("eventIDv2") == eventID2);

    std::vector<edm::EventID> vEventID;
    vEventID = ps.getParameter<std::vector<edm::EventID>>("vEventIDv1");
    assert(vEventID.empty());
    vEventID = ps.getParameter<std::vector<edm::EventID>>("vEventIDv2");
    assert(vEventID[0] == edm::EventID(1000, 0, 1100));
    vEventID = ps.getParameter<std::vector<edm::EventID>>("vEventIDv3");
    assert(vEventID[0] == edm::EventID(1000, 0, 1100));
    assert(vEventID[1] == edm::EventID(10000, 0, 11000));
    vEventID = ps.getParameter<std::vector<edm::EventID>>("vEventIDv4");
    assert(vEventID[0] == edm::EventID(1000, 0, 1100));
    assert(vEventID[1] == edm::EventID(10000, 0, 11000));
    assert(vEventID[2] == edm::EventID(100000, 0, 110000));

    edm::LuminosityBlockID luminosityID1(11, 12);
    assert(ps.getParameter<edm::LuminosityBlockID>("luminosityIDv1") == luminosityID1);
    edm::LuminosityBlockID luminosityID2(101, 102);
    assert(ps.getParameter<edm::LuminosityBlockID>("luminosityIDv2") == luminosityID2);

    std::vector<edm::LuminosityBlockID> vLuminosityBlockID;
    vLuminosityBlockID = ps.getParameter<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv1");
    assert(vLuminosityBlockID.empty());
    vLuminosityBlockID = ps.getParameter<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv2");
    assert(vLuminosityBlockID[0] == edm::LuminosityBlockID(1000, 1100));
    vLuminosityBlockID = ps.getParameter<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv3");
    assert(vLuminosityBlockID[0] == edm::LuminosityBlockID(1000, 1100));
    assert(vLuminosityBlockID[1] == edm::LuminosityBlockID(10000, 11000));
    vLuminosityBlockID = ps.getParameter<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv4");
    assert(vLuminosityBlockID[0] == edm::LuminosityBlockID(1000, 1100));
    assert(vLuminosityBlockID[1] == edm::LuminosityBlockID(10000, 11000));
    assert(vLuminosityBlockID[2] == edm::LuminosityBlockID(100000, 110000));

    edm::LuminosityBlockRange lumiRange1(1, 1, 9, 9);
    assert(ps.getParameter<edm::LuminosityBlockRange>("lumiRangev1").startLumiID() == lumiRange1.startLumiID());
    assert(ps.getParameter<edm::LuminosityBlockRange>("lumiRangev1").endLumiID() == lumiRange1.endLumiID());
    edm::LuminosityBlockRange lumiRange2(3, 4, 1000, 1000);
    assert(ps.getParameter<edm::LuminosityBlockRange>("lumiRangev2").startLumiID() == lumiRange2.startLumiID());
    assert(ps.getParameter<edm::LuminosityBlockRange>("lumiRangev2").endLumiID() == lumiRange2.endLumiID());

    std::vector<edm::LuminosityBlockRange> vLumiRange;
    vLumiRange = ps.getParameter<std::vector<edm::LuminosityBlockRange>>("vLumiRangev1");
    assert(vLumiRange.empty());
    vLumiRange = ps.getParameter<std::vector<edm::LuminosityBlockRange>>("vLumiRangev2");
    assert(vLumiRange[0].startLumiID() == lumiRange1.startLumiID());
    vLumiRange = ps.getParameter<std::vector<edm::LuminosityBlockRange>>("vLumiRangev3");
    assert(vLumiRange[0].startLumiID() == lumiRange1.startLumiID());
    assert(vLumiRange[1].startLumiID() == lumiRange2.startLumiID());
    assert(vLumiRange[1].endLumiID() == lumiRange2.endLumiID());

    edm::EventRange eventRange1(1, 0, 1, 8, 0, 8);
    assert(ps.getParameter<edm::EventRange>("eventRangev1").startEventID() == eventRange1.startEventID());
    assert(ps.getParameter<edm::EventRange>("eventRangev1").endEventID() == eventRange1.endEventID());
    edm::EventRange eventRange2(3, 0, 4, 1001, 0, 1002);
    assert(ps.getParameter<edm::EventRange>("eventRangev2").startEventID() == eventRange2.startEventID());
    assert(ps.getParameter<edm::EventRange>("eventRangev2").endEventID() == eventRange2.endEventID());

    std::vector<edm::EventRange> vEventRange;
    vEventRange = ps.getParameter<std::vector<edm::EventRange>>("vEventRangev1");
    assert(vEventRange.empty());
    vEventRange = ps.getParameter<std::vector<edm::EventRange>>("vEventRangev2");
    assert(vEventRange[0].startEventID() == eventRange1.startEventID());
    vEventRange = ps.getParameter<std::vector<edm::EventRange>>("vEventRangev3");
    assert(vEventRange[0].startEventID() == eventRange1.startEventID());
    assert(vEventRange[1].startEventID() == eventRange2.startEventID());

    edm::InputTag inputTag1("One", "Two", "Three");
    assert(ps.getParameter<edm::InputTag>("inputTagv1") == inputTag1);
    edm::InputTag inputTag2("One", "Two");
    assert(ps.getParameter<edm::InputTag>("inputTagv2") == inputTag2);
    edm::InputTag inputTag3("One");
    assert(ps.getParameter<edm::InputTag>("inputTagv3") == inputTag3);
    edm::InputTag inputTag4("One", "", "Three");
    assert(ps.getParameter<edm::InputTag>("inputTagv4") == inputTag4);

    std::vector<edm::InputTag> vInputTag;
    vInputTag = ps.getParameter<std::vector<edm::InputTag>>("vInputTagv1");
    assert(vInputTag.empty());
    vInputTag = ps.getParameter<std::vector<edm::InputTag>>("vInputTagv2");
    assert(vInputTag[0] == inputTag1);
    vInputTag = ps.getParameter<std::vector<edm::InputTag>>("vInputTagv3");
    assert(vInputTag[0] == inputTag1);
    assert(vInputTag[1] == inputTag2);
    vInputTag = ps.getParameter<std::vector<edm::InputTag>>("vInputTagv4");
    assert(vInputTag[0] == inputTag1);
    assert(vInputTag[1] == inputTag2);
    assert(vInputTag[2] == inputTag3);
    vInputTag = ps.getParameter<std::vector<edm::InputTag>>("vInputTagv5");
    assert(vInputTag[0] == inputTag1);
    assert(vInputTag[1] == inputTag2);
    assert(vInputTag[2] == inputTag3);
    assert(vInputTag[3] == inputTag4);

    edm::ESInputTag esinputTag1("One", "Two");
    assert(ps.getParameter<edm::ESInputTag>("esinputTagv1") == esinputTag1);
    edm::ESInputTag esinputTag2("One", "");
    assert(ps.getParameter<edm::ESInputTag>("esinputTagv2") == esinputTag2);
    edm::ESInputTag esinputTag3("", "Two");
    assert(ps.getParameter<edm::ESInputTag>("esinputTagv3") == esinputTag3);

    std::vector<edm::ESInputTag> vESInputTag;
    vESInputTag = ps.getParameter<std::vector<edm::ESInputTag>>("vESInputTagv1");
    assert(vESInputTag.empty());
    vESInputTag = ps.getParameter<std::vector<edm::ESInputTag>>("vESInputTagv2");
    assert(vESInputTag[0] == esinputTag1);
    vESInputTag = ps.getParameter<std::vector<edm::ESInputTag>>("vESInputTagv3");
    assert(vESInputTag[0] == esinputTag1);
    assert(vESInputTag[1] == esinputTag2);
    vESInputTag = ps.getParameter<std::vector<edm::ESInputTag>>("vESInputTagv4");
    assert(vESInputTag[0] == esinputTag1);
    assert(vESInputTag[1] == esinputTag2);
    assert(vESInputTag[2] == esinputTag3);

    // For purposes of the test, this just needs to point to any file
    // that exists.
    edm::FileInPath fileInPath("FWCore/Integration/plugins/ProducerWithPSetDesc.cc");
    assert(fileInPath == ps.getParameter<edm::FileInPath>("fileInPath"));

    edm::ParameterSet const& pset = ps.getParameterSet("bar");
    assert(pset.getParameter<unsigned>("Drinks") == 5U);
    assert(pset.getUntrackedParameter<unsigned>("uDrinks") == 5U);
    if (testingAutoGeneratedCfi)
      assert(pset.getParameter<unsigned>("oDrinks") == 5U);
    if (testingAutoGeneratedCfi)
      assert(pset.getUntrackedParameter<unsigned>("ouDrinks") == 5U);

    //std::vector<edm::ParameterSet> const& vpsetUntracked =
    //  ps.getUntrackedParameterSetVector("test104");

    std::vector<edm::ParameterSet> const& vpset = ps.getParameterSetVector("bars");

    assert(vpset.size() == 2U);

    const edm::ParameterSet& pset0 = vpset[0];
    assert(pset0.getParameter<unsigned>("Drinks") == 5U);
    assert(pset0.getUntrackedParameter<unsigned>("uDrinks") == 5U);
    assert(pset0.getParameter<unsigned>("oDrinks") == 11U);
    assert(pset0.exists("ouDrinks") == false);
    assert(pset0.exists("ndoDrinks") == false);
    assert(pset0.exists("ndouDrinks") == false);
    // assert(pset0.getUntrackedParameter<unsigned>("ndouDrinks") == 5);

    const edm::ParameterSet& pset1 = vpset[1];
    assert(pset1.getParameter<unsigned>("Drinks") == 5U);
    assert(pset1.getUntrackedParameter<unsigned>("uDrinks") == 5U);
    assert(pset1.getParameter<unsigned>("oDrinks") == 11U);
    assert(pset1.getUntrackedParameter<unsigned>("ouDrinks") == 11U);
    assert(pset1.exists("ndoDrinks") == false);
    assert(pset1.getUntrackedParameter<unsigned>("ndouDrinks") == 11U);

    assert(ps.getParameter<double>("test1") == 0.1);
    if (testingAutoGeneratedCfi) {
      assert(ps.getParameter<double>("test2") == 0.2);
      assert(ps.exists("test3") == false);

      assert(ps.getParameter<std::string>("testA") == std::string("fooA"));
      assert(ps.getParameter<int>("testB") == 100);
      assert(ps.getParameter<int>("testC") == 101);

      assert(ps.getParameter<int>("oiswitch") == 1);
      assert(ps.getParameter<double>("oivalue1") == 101.0);
      assert(ps.getParameter<double>("oivalue2") == 101.0);
    } else {
      assert(!ps.exists("test2"));
      assert(!ps.exists("test3"));

      assert(!ps.exists("testA"));
      assert(!ps.exists("testB"));
      assert(!ps.exists("testC"));

      assert(!ps.exists("oiswitch"));
      assert(!ps.exists("oivalue1"));
      assert(!ps.exists("oivalue2"));
    }

    edm::ParameterSet const& deeplyNestedPSet = pset1.getParameterSet("testDeeplyNested");
    if (testingAutoGeneratedCfi) {
      assert(!deeplyNestedPSet.exists("ndiswitch"));
      assert(!deeplyNestedPSet.exists("ndivalue1"));
      assert(!deeplyNestedPSet.exists("ndivalue2"));
    } else {
      assert(!deeplyNestedPSet.exists("ndiswitch"));
      assert(!deeplyNestedPSet.exists("ndivalue1"));
      assert(!deeplyNestedPSet.exists("ndivalue2"));
    }

    assert(deeplyNestedPSet.getParameter<bool>("bswitch") == false);
    assert(deeplyNestedPSet.getParameter<double>("bvalue1") == 101.0);
    assert(deeplyNestedPSet.getParameter<double>("bvalue2") == 101.0);
    assert(!deeplyNestedPSet.exists("bvalue"));

    assert(deeplyNestedPSet.getParameter<int>("iswitch") == 1);
    assert(deeplyNestedPSet.getParameter<double>("ivalue1") == 101.0);
    assert(deeplyNestedPSet.getUntrackedParameter<double>("ivalue2") == 101.0);
    assert(!deeplyNestedPSet.exists("ivalue"));

    assert(deeplyNestedPSet.getParameter<std::string>("sswitch") == std::string("1"));
    assert(deeplyNestedPSet.getParameter<double>("svalue1") == 101.0);
    assert(deeplyNestedPSet.getParameter<double>("svalue2") == 101.0);
    assert(!deeplyNestedPSet.exists("svalue"));

    if (testingAutoGeneratedCfi) {
      edm::ParameterSet const& pset11 = ps.getParameterSet("subpset");
      assert(pset11.getParameter<int>("xvalue") == 11);
      edm::ParameterSet const& pset111 = pset11.getUntrackedParameterSet("bar");
      assert(pset111.getParameter<unsigned>("Drinks") == 5U);
      assert(pset111.getUntrackedParameter<unsigned>("uDrinks") == 5U);
      assert(pset111.getParameter<unsigned>("oDrinks") == 5U);
      assert(pset111.getUntrackedParameter<unsigned>("ouDrinks") == 5U);
    }

    edm::ParameterSet const& psetXor = ps.getParameterSet("xorPset");
    assert(psetXor.getParameter<std::string>("name1") == std::string("11"));
    assert(!psetXor.exists("name2"));
    if (testingAutoGeneratedCfi) {
      assert(psetXor.getParameter<std::string>("name") == std::string("11"));
    } else {
      assert(psetXor.getParameter<unsigned>("name") == 11U);
    }

    edm::ParameterSet const& psetOr = ps.getParameterSet("orPset");
    assert(!psetOr.exists("z1"));
    assert(!psetOr.exists("z2"));
    if (testingAutoGeneratedCfi) {
      assert(psetOr.getParameter<std::string>("x1") == std::string("11"));
      assert(!psetOr.exists("x2"));
      assert(psetOr.getParameter<std::string>("y1") == std::string("11"));
      assert(!psetOr.exists("y2"));
    } else {
      assert(!psetOr.exists("x1"));
      assert(psetOr.getParameter<unsigned>("x2") == 11U);
      assert(psetOr.getParameter<std::string>("y1") == std::string("11"));
      assert(psetOr.getParameter<unsigned>("y2") == 11U);
    }

    edm::ParameterSet const& psetAnd = ps.getParameterSet("andPset");
    assert(psetAnd.getParameter<std::string>("x1") == std::string("11"));
    assert(psetAnd.getParameter<unsigned>("x2") == 11U);
    assert(psetAnd.getParameter<std::string>("y1") == std::string("11"));
    assert(psetAnd.getParameter<unsigned>("y2") == 11U);
    assert(psetAnd.getParameter<std::string>("z1") == std::string("11"));
    assert(psetAnd.getParameter<unsigned>("z2") == 11U);
    assert(psetAnd.getParameter<std::string>("b1") == std::string("11"));
    assert(psetAnd.getParameter<unsigned>("b2") == 11U);
    assert(psetAnd.getParameter<unsigned>("b3") == 11U);
    assert(psetAnd.getParameter<unsigned>("b4") == 11U);
    assert(psetAnd.getParameter<unsigned>("b5") == 11U);
    assert(psetAnd.getParameter<unsigned>("b6") == 11U);
    if (testingAutoGeneratedCfi) {
      assert(!psetAnd.exists("a1"));
      assert(!psetAnd.exists("a2"));
    } else {
      assert(psetAnd.getParameter<std::string>("a1") == std::string("11"));
      assert(psetAnd.getParameter<unsigned>("a2") == 11U);
    }

    edm::ParameterSet const& psetIfExists = ps.getParameterSet("ifExistsPset");
    assert(psetIfExists.getParameter<unsigned>("x1") == 11U);
    assert(psetIfExists.getParameter<std::string>("x2") == std::string("11"));
    assert(psetIfExists.getParameter<unsigned>("z1") == 11U);
    assert(psetIfExists.getParameter<std::string>("z2") == std::string("11"));
    if (testingAutoGeneratedCfi) {
      assert(!psetIfExists.exists("y1"));
      assert(!psetIfExists.exists("y2"));
    } else {
      assert(psetIfExists.getParameter<unsigned>("y1") == 11U);
      assert(!psetIfExists.exists("y2"));
    }

    edm::ParameterSet const& psetAllowed = ps.getParameterSet("allowedLabelsPset");
    if (testingAutoGeneratedCfi) {
      assert(psetAllowed.getParameter<std::vector<std::string>>("testAllowedLabels").empty());
      assert(psetAllowed.getUntrackedParameter<std::vector<std::string>>("testAllowedLabelsUntracked").empty());
      assert(!psetAllowed.exists("testOptAllowedLabels"));
      assert(!psetAllowed.exists("testOptAllowedLabelsUntracked"));
    }

    produces<ThingCollection>();
  }

  void ProducerWithPSetDesc::produce(edm::StreamID, edm::Event& e, edm::EventSetup const&) const {
    // This serves no purpose, I just put it here so the module does something
    // Probably could just make this method do nothing and it would not
    // affect the test.
    auto result = std::make_unique<ThingCollection>();  //Empty
    e.put(std::move(result));
  }

  void ProducerWithPSetDesc::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
    edm::ParameterSetDescription iDesc;

    // Try to exercise the description code by adding all different
    // types of parameters with a large range of values.  Also
    // nested ParameterSets and vectors of them at the end.

    iDesc.addOptionalUntracked<bool>("testingAutoGeneratedCfi", true);

    edm::ParameterDescriptionNode* pn;
    pn = iDesc.add<int>("p_int", 2147483647);
    pn->setComment(
        "A big integer. I am trying to test the wrapping of comments in"
        " the printed output by putting in a long comment to see if it gets"
        " wrapped OK. The comment should get indented to the second column"
        " indent on every line. By default newlines should be inserted between"
        " words to make the lines fit in the terminal screen width. There is "
        "a command line parameter that can be set to override this width to "
        "any desired value. If there is no terminal then it should default to "
        "80. The logic for setting the width is in edmPluginHelp.cpp");

    iDesc.addUntracked<int>("p_int_untracked", -2147483647);
    iDesc.addOptional<int>("p_int_opt", 0);
    iDesc.addOptionalUntracked<int>("p_int_optuntracked", 7);
    iDesc.addOptional<int>("p_int_opt_nd");
    iDesc.addOptionalUntracked<int>("p_int_optuntracked_nd");

    std::vector<int> vint;
    iDesc.add<std::vector<int>>("vint1", vint);
    vint.push_back(2147483647);
    iDesc.add<std::vector<int>>(std::string("vint2"), vint);
    vint.push_back(-2147483647);
    iDesc.add<std::vector<int>>("vint3", vint);
    vint.push_back(0);
    iDesc.add<std::vector<int>>("vint4", vint);

    iDesc.add<unsigned>("uint1", 4294967295U);
    iDesc.addUntracked<unsigned>("uint2", 0);

    std::vector<unsigned> vuint;
    iDesc.add<std::vector<unsigned>>("vuint1", vuint);
    vuint.push_back(4294967295U);
    iDesc.add<std::vector<unsigned>>("vuint2", vuint);
    vuint.push_back(0);
    iDesc.add<std::vector<unsigned>>("vuint3", vuint);
    vuint.push_back(11);
    iDesc.add<std::vector<unsigned>>("vuint4", vuint);
    vuint.push_back(21);
    vuint.push_back(31);
    vuint.push_back(41);
    iDesc.add<std::vector<unsigned>>("vuint5", vuint);

    iDesc.add<long long>("int64v1", 9000000000000000000LL);
    iDesc.add<long long>("int64v2", -9000000000000000000LL);
    iDesc.add<long long>("int64v3", 0);

    std::vector<long long> vint64;
    iDesc.add<std::vector<long long>>("vint64v1", vint64);
    vint64.push_back(9000000000000000000LL);
    iDesc.add<std::vector<long long>>("vint64v2", vint64);
    vint64.push_back(-9000000000000000000LL);
    iDesc.add<std::vector<long long>>("vint64v3", vint64);
    vint64.push_back(0);
    iDesc.add<std::vector<long long>>("vint64v4", vint64);

    iDesc.add<unsigned long long>("uint64v1", 18000000000000000000ULL);
    iDesc.addUntracked<unsigned long long>("uint64v2", 0);

    std::vector<unsigned long long> vuint64;
    iDesc.add<std::vector<unsigned long long>>("vuint64v1", vuint64);
    vuint64.push_back(18000000000000000000ULL);
    iDesc.add<std::vector<unsigned long long>>("vuint64v2", vuint64);
    vuint64.push_back(0);
    iDesc.add<std::vector<unsigned long long>>("vuint64v3", vuint64);
    vuint64.push_back(11);
    iDesc.add<std::vector<unsigned long long>>("vuint64v4", vuint64);

    iDesc.add<double>("doublev1", std::numeric_limits<double>::min());
    iDesc.addUntracked<double>("doublev2", 0.0);
    iDesc.addUntracked<double>("doublev3", 0.3);

    std::vector<double> vdouble;
    iDesc.add<std::vector<double>>("vdoublev1", vdouble);
    // cmsRun will fail with a value this big
    // vdouble.push_back(std::numeric_limits<double>::max());
    // This works though
    vdouble.push_back(1e+300);
    iDesc.add<std::vector<double>>("vdoublev2", vdouble);
    vdouble.push_back(0.0);
    iDesc.add<std::vector<double>>("vdoublev3", vdouble);
    vdouble.push_back(11.0);
    iDesc.add<std::vector<double>>("vdoublev4", vdouble);
    vdouble.push_back(0.3);
    iDesc.add<std::vector<double>>("vdoublev5", vdouble);

    iDesc.add<bool>("boolv1", true);
    iDesc.add<bool>("boolv2", false);

    std::string test("Hello");
    iDesc.add<std::string>("stringv1", test);
    test.clear();
    iDesc.add<std::string>("stringv2", test);

    std::vector<std::string> vstring;
    iDesc.add<std::vector<std::string>>("vstringv1", vstring);
    test = "Hello";
    vstring.push_back(test);
    iDesc.add<std::vector<std::string>>("vstringv2", vstring);
    test = "World";
    vstring.push_back(test);
    iDesc.add<std::vector<std::string>>("vstringv3", vstring);
    test = "";
    vstring.push_back(test);
    iDesc.add<std::vector<std::string>>("vstringv4", vstring);

    edm::EventID eventID(11, 0, 12);
    iDesc.add<edm::EventID>("eventIDv1", eventID);
    edm::EventID eventID2(101, 0, 102);
    iDesc.add<edm::EventID>("eventIDv2", eventID2);
    std::vector<edm::EventID> vEventID;
    iDesc.add<std::vector<edm::EventID>>("vEventIDv1", vEventID);
    edm::EventID eventID3(1000, 0, 1100);
    vEventID.push_back(eventID3);
    iDesc.add<std::vector<edm::EventID>>("vEventIDv2", vEventID);
    edm::EventID eventID4(10000, 0, 11000);
    vEventID.push_back(eventID4);
    iDesc.add<std::vector<edm::EventID>>("vEventIDv3", vEventID);
    edm::EventID eventID5(100000, 0, 110000);
    vEventID.push_back(eventID5);
    iDesc.add<std::vector<edm::EventID>>("vEventIDv4", vEventID);

    edm::LuminosityBlockID luminosityID(11, 12);
    iDesc.add<edm::LuminosityBlockID>("luminosityIDv1", luminosityID);
    edm::LuminosityBlockID luminosityID2(101, 102);
    iDesc.add<edm::LuminosityBlockID>("luminosityIDv2", luminosityID2);

    std::vector<edm::LuminosityBlockID> vLuminosityBlockID;
    iDesc.add<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv1", vLuminosityBlockID);
    edm::LuminosityBlockID luminosityID3(1000, 1100);
    vLuminosityBlockID.push_back(luminosityID3);
    iDesc.add<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv2", vLuminosityBlockID);
    edm::LuminosityBlockID luminosityID4(10000, 11000);
    vLuminosityBlockID.push_back(luminosityID4);
    iDesc.add<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv3", vLuminosityBlockID);
    edm::LuminosityBlockID luminosityID5(100000, 110000);
    vLuminosityBlockID.push_back(luminosityID5);
    iDesc.add<std::vector<edm::LuminosityBlockID>>("vLuminosityBlockIDv4", vLuminosityBlockID);

    edm::LuminosityBlockRange lumiRange(1, 1, 9, 9);
    iDesc.add<edm::LuminosityBlockRange>("lumiRangev1", lumiRange);
    edm::LuminosityBlockRange lumiRange2(3, 4, 1000, 1000);
    iDesc.add<edm::LuminosityBlockRange>("lumiRangev2", lumiRange2);

    std::vector<edm::LuminosityBlockRange> vLumiRange;
    iDesc.add<std::vector<edm::LuminosityBlockRange>>("vLumiRangev1", vLumiRange);
    vLumiRange.push_back(lumiRange);
    iDesc.add<std::vector<edm::LuminosityBlockRange>>("vLumiRangev2", vLumiRange);
    vLumiRange.push_back(lumiRange2);
    iDesc.add<std::vector<edm::LuminosityBlockRange>>("vLumiRangev3", vLumiRange);

    edm::EventRange eventRange(1, 0, 1, 8, 0, 8);
    iDesc.add<edm::EventRange>("eventRangev1", eventRange);
    edm::EventRange eventRange2(3, 0, 4, 1001, 0, 1002);
    iDesc.add<edm::EventRange>("eventRangev2", eventRange2);

    std::vector<edm::EventRange> vEventRange;
    iDesc.add<std::vector<edm::EventRange>>("vEventRangev1", vEventRange);
    vEventRange.push_back(eventRange);
    iDesc.add<std::vector<edm::EventRange>>("vEventRangev2", vEventRange);
    vEventRange.push_back(eventRange2);
    iDesc.add<std::vector<edm::EventRange>>("vEventRangev3", vEventRange);

    edm::InputTag inputTag("One", "Two", "Three");
    iDesc.add<edm::InputTag>("inputTagv1", inputTag);
    edm::InputTag inputTag2("One", "Two");
    iDesc.add<edm::InputTag>("inputTagv2", inputTag2);
    edm::InputTag inputTag3("One");
    iDesc.add<edm::InputTag>("inputTagv3", inputTag3);
    edm::InputTag inputTag4("One", "", "Three");
    iDesc.add<edm::InputTag>("inputTagv4", inputTag4);

    std::vector<edm::InputTag> vInputTag;
    iDesc.add<std::vector<edm::InputTag>>("vInputTagv1", vInputTag);
    vInputTag.push_back(inputTag);
    iDesc.add<std::vector<edm::InputTag>>("vInputTagv2", vInputTag);
    vInputTag.push_back(inputTag2);
    iDesc.add<std::vector<edm::InputTag>>("vInputTagv3", vInputTag);
    vInputTag.push_back(inputTag3);
    iDesc.add<std::vector<edm::InputTag>>("vInputTagv4", vInputTag);
    vInputTag.push_back(inputTag4);
    iDesc.add<std::vector<edm::InputTag>>("vInputTagv5", vInputTag);

    edm::ESInputTag esinputTag("One", "Two");
    iDesc.add<edm::ESInputTag>("esinputTagv1", esinputTag);
    edm::ESInputTag esinputTag2("One", "");
    iDesc.add<edm::ESInputTag>("esinputTagv2", esinputTag2);
    edm::ESInputTag esinputTag3("", "Two");
    iDesc.add<edm::ESInputTag>("esinputTagv3", esinputTag3);

    std::vector<edm::ESInputTag> vESInputTag;
    iDesc.add<std::vector<edm::ESInputTag>>("vESInputTagv1", vESInputTag);
    vESInputTag.push_back(esinputTag);
    iDesc.add<std::vector<edm::ESInputTag>>("vESInputTagv2", vESInputTag);
    vESInputTag.push_back(esinputTag2);
    iDesc.add<std::vector<edm::ESInputTag>>("vESInputTagv3", vESInputTag);
    vESInputTag.push_back(esinputTag3);
    iDesc.add<std::vector<edm::ESInputTag>>("vESInputTagv4", vESInputTag);

    // For purposes of the test, this just needs to point to any file
    // that exists.
    edm::FileInPath fileInPath("FWCore/Integration/plugins/ProducerWithPSetDesc.cc");
    iDesc.add<edm::FileInPath>("fileInPath", fileInPath);

    edm::EmptyGroupDescription emptyGroup;
    iDesc.addNode(emptyGroup);

    edm::ParameterSetDescription bar;
    bar.add<unsigned int>("Drinks", 5);
    bar.addUntracked<unsigned int>("uDrinks", 5);
    bar.addOptional<unsigned int>("oDrinks", 5);
    bar.addOptionalUntracked<unsigned int>("ouDrinks", 5);
    iDesc.add("bar", bar);

    edm::ParameterDescription<edm::ParameterSetDescription> test101("test101", bar, true);
    iDesc.addOptionalNode(test101, false);

    edm::ParameterSetDescription barx;
    barx.add<unsigned int>("Drinks", 5);
    barx.addUntracked<unsigned int>("uDrinks", 5);
    barx.addOptional<unsigned int>("oDrinks", 5);
    barx.addOptionalUntracked<unsigned int>("ouDrinks", 5);
    barx.addOptional<unsigned int>("ndoDrinks");
    barx.addOptionalUntracked<unsigned int>("ndouDrinks");

    edm::ParameterDescription<std::vector<edm::ParameterSet>> test102("test102", edm::ParameterSetDescription(), true);
    iDesc.addOptionalNode(test102, false);

    edm::ParameterDescription<std::vector<edm::ParameterSet>> test103(std::string("test103"), barx, true);
    iDesc.addOptionalNode(test103, false);

    std::vector<edm::ParameterSet> defaultVPSet104;
    defaultVPSet104.push_back(edm::ParameterSet());
    edm::ParameterDescription<std::vector<edm::ParameterSet>> test104(
        std::string("test104"), barx, false, defaultVPSet104);
    iDesc.addNode(test104);

    std::vector<edm::ParameterSet> defaultVPSet105;
    edm::ParameterDescription<std::vector<edm::ParameterSet>> test105(
        std::string("test105"), barx, false, defaultVPSet105);
    iDesc.addNode(test105);

    double d1 = 0.1;
    double d2 = 0.2;
    double d3 = 0.3;
    iDesc.addNode(edm::ParameterDescription<double>("test1", d1, true));
    iDesc.addOptionalNode(edm::ParameterDescription<double>("test2", d2, true), true);
    // The value in the second argument is not used in this case
    iDesc.addOptionalNode(edm::ParameterDescription<double>("test3", d3, true), false);

    iDesc.addOptionalNode(edm::ParameterDescription<std::string>("testA", "fooA", true) and
                              edm::ParameterDescription<int>("testB", 100, true) &&
                              edm::ParameterDescription<int>("testC", 101, true),
                          true);

    iDesc.ifValueOptional(edm::ParameterDescription<int>("oiswitch", 1, true),
                          0 >> edm::ParameterDescription<int>("oivalue", 100, true) or
                              1 >> (edm::ParameterDescription<double>("oivalue1", 101.0, true) and
                                    edm::ParameterDescription<double>("oivalue2", 101.0, true)) or
                              2 >> edm::ParameterDescription<std::string>("oivalue", "102", true),
                          true);

    edm::ParameterSetDescription deeplyNested;

    bool case0 = true;
    bool case1 = false;
    deeplyNested.ifValue(edm::ParameterDescription<bool>("bswitch", false, true),
                         case0 >> edm::ParameterDescription<int>("bvalue", 100, true) or
                             case1 >> (edm::ParameterDescription<double>("bvalue1", 101.0, true) and
                                       edm::ParameterDescription<double>("bvalue2", 101.0, true)));
    deeplyNested.ifValue(edm::ParameterDescription<int>("iswitch", 1, true),
                         0 >> edm::ParameterDescription<int>("ivalue", 100, true) or
                             1 >> (edm::ParameterDescription<double>("ivalue1", 101.0, true) and
                                   edm::ParameterDescription<double>("ivalue2", 101.0, false)) or
                             2 >> edm::ParameterDescription<std::string>("ivalue", "102", true));
    deeplyNested.ifValue(edm::ParameterDescription<std::string>("sswitch", std::string("1"), true),
                         std::string("0") >> edm::ParameterDescription<int>("svalue", 100, true) or
                             "1" >> (edm::ParameterDescription<double>("svalue1", 101.0, true) and
                                     edm::ParameterDescription<double>("svalue2", 101.0, true)) or
                             "2" >> edm::ParameterDescription<std::string>("svalue", "102", true));

    deeplyNested.ifValueOptional(edm::ParameterDescription<int>("ndiswitch", 1, true),
                                 0 >> edm::ParameterDescription<int>("ndivalue", 100, true) or
                                     1 >> (edm::ParameterDescription<double>("ndivalue1", 101.0, true) and
                                           edm::ParameterDescription<double>("ndivalue2", 101.0, true)) or
                                     2 >> edm::ParameterDescription<std::string>("ndivalue", "102", true),
                                 false);

    deeplyNested.add<int>("testint", 1000);

    barx.add("testDeeplyNested", deeplyNested);

    iDesc.add("testDeeplyNested2", deeplyNested);

    edm::ParameterSetDescription validator;
    validator.add<int>("xvalue", 7);
    std::vector<edm::ParameterSet> vDefaults;
    edm::ParameterSet vDefaults0;
    vDefaults.push_back(vDefaults0);
    edm::ParameterSet vDefaults1;
    vDefaults1.addParameter<int>("xvalue", 100);
    vDefaults.push_back(vDefaults1);
    barx.addVPSet("anotherVPSet", validator, vDefaults);

    std::vector<edm::ParameterSet> defaultVPSet;

    edm::ParameterSet psetInVector1;
    psetInVector1.addParameter<unsigned int>("oDrinks", 11U);
    defaultVPSet.push_back(psetInVector1);

    edm::ParameterSet psetInVector2;
    psetInVector2.addParameter<unsigned int>("oDrinks", 11U);
    psetInVector2.addUntrackedParameter<unsigned int>("ouDrinks", 11U);
    psetInVector2.addUntrackedParameter<unsigned int>("ndouDrinks", 11U);

    std::vector<edm::ParameterSet> anotherDefaultVPSet;
    anotherDefaultVPSet.push_back(edm::ParameterSet());
    edm::ParameterSet anotherParameterSet;
    anotherParameterSet.addParameter<int>("xvalue", 17);
    anotherDefaultVPSet.push_back(anotherParameterSet);
    psetInVector2.addParameter<std::vector<edm::ParameterSet>>("anotherVPSet", anotherDefaultVPSet);

    edm::ParameterSet defaultForDeeplyNested;
    defaultForDeeplyNested.addParameter<int>("testint", 2);
    psetInVector2.addParameter<edm::ParameterSet>("testDeeplyNested", defaultForDeeplyNested);

    defaultVPSet.push_back(psetInVector2);

    iDesc.addVPSet("bars", barx, defaultVPSet);

    // Alternate way to add a ParameterSetDescription
    edm::ParameterDescriptionBase* parDescription;
    parDescription = iDesc.addOptional("subpset", edm::ParameterSetDescription());
    edm::ParameterSetDescription* subPsetDescription = parDescription->parameterSetDescription();

    subPsetDescription->add<int>("xvalue", 11);
    subPsetDescription->addUntracked<edm::ParameterSetDescription>(std::string("bar"), bar);

    // -----------------------------------------------

    edm::ParameterSetDescription wildcardPset;
    wildcardPset.addOptional<unsigned>("p_uint_opt", 0);
    wildcardPset.addWildcard<int>("*");
    pn = wildcardPset.addWildcardUntracked<double>(std::string("*"));
    pn->setComment("A comment for a wildcard parameter");

    std::unique_ptr<edm::ParameterDescriptionNode> wnode =
        std::make_unique<edm::ParameterWildcard<edm::ParameterSetDescription>>("*", edm::RequireExactlyOne, true);
    wildcardPset.addOptionalNode(std::move(wnode), false);

    edm::ParameterSetDescription wSet1;
    wSet1.add<unsigned int>("Drinks", 5);

    std::unique_ptr<edm::ParameterDescriptionNode> wnode2 =
        std::make_unique<edm::ParameterWildcard<edm::ParameterSetDescription>>(
            "*", edm::RequireAtLeastOne, true, wSet1);
    wildcardPset.addOptionalNode(std::move(wnode2), false);

    std::unique_ptr<edm::ParameterDescriptionNode> wnode3 =
        std::make_unique<edm::ParameterWildcard<std::vector<edm::ParameterSet>>>("*", edm::RequireExactlyOne, true);
    wildcardPset.addOptionalNode(std::move(wnode3), false);

    wSet1.add<unsigned int>("Drinks2", 11);

    std::unique_ptr<edm::ParameterDescriptionNode> wnode4 =
        std::make_unique<edm::ParameterWildcard<std::vector<edm::ParameterSet>>>(
            "*", edm::RequireAtLeastOne, true, wSet1);
    wildcardPset.addOptionalNode(std::move(wnode4), false);

    iDesc.add("wildcardPset", wildcardPset);

    // ---------------------------------------------

    std::vector<int> testIntVector;
    testIntVector.push_back(21);
    testIntVector.push_back(22);
    edm::ParameterSetDescription switchPset;
    pn = switchPset.ifValue(edm::ParameterDescription<int>("iswitch", 1, true),
                            0 >> edm::ParameterDescription<std::vector<int>>("ivalue", testIntVector, true) or
                                1 >> (edm::ParameterDescription<double>("ivalue1", 101.0, true) and
                                      edm::ParameterDescription<double>("ivalue2", 101.0, true)) or
                                2 >> edm::ParameterDescription<std::string>("ivalue", "102", true));
    pn->setComment("Comment for a ParameterSwitch");

    switchPset
        .ifValue(edm::ParameterDescription<bool>("addTeVRefits", true, true),
                 true >> (edm::ParameterDescription<edm::InputTag>("pickySrc", edm::InputTag(), true) and
                          edm::ParameterDescription<edm::InputTag>("tpfmsSrc", edm::InputTag(), true)) or
                     false >> edm::EmptyGroupDescription())
        ->setComment("If TeV refits are added, their sources need to be specified");

    iDesc.add("switchPset", switchPset);

    // -----------------------------------------------

    edm::ParameterSetDescription xorPset;
    xorPset.addNode(edm::ParameterDescription<std::string>("name", "11", true) xor
                    edm::ParameterDescription<unsigned int>("name", 11U, true));

    xorPset.addNode(edm::ParameterDescription<std::string>("name1", "11", true) xor
                    edm::ParameterDescription<unsigned int>("name1", 11U, true));

    xorPset.addOptionalNode(edm::ParameterDescription<std::string>("name2", "11", true) xor
                                edm::ParameterDescription<unsigned int>("name2", 11U, true),
                            false);

    xorPset.addNode(edm::ParameterDescription<std::string>("name3", "11", true) xor
                    edm::ParameterDescription<unsigned int>("name4", 11U, true) xor test101 xor test103);

    iDesc.add("xorPset", xorPset);

    // -----------------------------------------

    edm::ParameterSetDescription orPset;

    orPset.addNode(edm::ParameterDescription<std::string>("x1", "11", true) or
                   edm::ParameterDescription<unsigned int>("x2", 11U, true));

    orPset.addNode(edm::ParameterDescription<std::string>("y1", "11", true) or
                   edm::ParameterDescription<unsigned int>("y2", 11U, true));

    orPset.addOptionalNode(edm::ParameterDescription<std::string>("z1", "11", true) or
                               edm::ParameterDescription<unsigned int>("z2", 11U, true) or test101 or test103,
                           false);

    iDesc.add("orPset", orPset);

    // ------------------------------------------------

    edm::ParameterSetDescription andPset;

    andPset.addNode(edm::ParameterDescription<std::string>("x1", "11", true) and
                    edm::ParameterDescription<unsigned int>("x2", 11U, true));

    andPset.addNode(edm::ParameterDescription<std::string>("y1", "11", true) and
                    edm::ParameterDescription<unsigned int>("y2", 11U, true));

    andPset.addNode(edm::ParameterDescription<std::string>("z1", "11", true) and
                    edm::ParameterDescription<unsigned int>("z2", 11U, true));

    andPset.addOptionalNode(edm::ParameterDescription<std::string>("a1", "11", true) and
                                edm::ParameterDescription<unsigned int>("a2", 11U, true),
                            false);

    andPset.addOptionalNode((edm::ParameterDescription<std::string>("b1", "11", true) and
                             edm::ParameterDescription<unsigned int>("b2", 11U, true)) and
                                edm::ParameterDescription<unsigned int>("b3", 11U, true) and
                                (edm::ParameterDescription<unsigned int>("b4", 11U, true) and
                                 (edm::ParameterDescription<unsigned int>("b5", 11U, true) and
                                  edm::ParameterDescription<unsigned int>("b6", 11U, true))),
                            true);

    iDesc.add("andPset", andPset);

    // --------------------------------------

    edm::ParameterSetDescription ifExistsPset;

    ifExistsPset.ifExists(edm::ParameterDescription<unsigned int>("x1", 11U, true),
                          edm::ParameterDescription<std::string>("x2", "11", true));

    ifExistsPset.ifExistsOptional(edm::ParameterDescription<unsigned int>("y1", 11U, true),
                                  edm::ParameterDescription<std::string>("y2", "11", true),
                                  false);

    ifExistsPset.ifExists(edm::ParameterDescription<unsigned int>("z1", 11U, true),
                          edm::ParameterDescription<std::string>("z2", "11", true));

    iDesc.add("ifExistsPset", ifExistsPset);

    // ------------------------------------------

    edm::ParameterSetDescription allowedLabelsPset;

    allowedLabelsPset.addOptional<int>("p_int_opt", 0);
    allowedLabelsPset.labelsFrom<int>("testAllowedLabels");
    allowedLabelsPset.labelsFromUntracked<unsigned>(std::string("testAllowedLabelsUntracked"));
    allowedLabelsPset.labelsFromOptional<int>("testOptAllowedLabels", false);
    allowedLabelsPset.labelsFromOptionalUntracked<unsigned>(std::string("testOptAllowedLabelsUntracked"), false);
    allowedLabelsPset.labelsFromOptionalUntracked<edm::ParameterSetDescription>(std::string("testWithSet"), true, bar);

    allowedLabelsPset.labelsFromOptionalUntracked<std::vector<edm::ParameterSet>>(
        std::string("testWithVectorOfSets"), true, bar);

    iDesc.add("allowedLabelsPset", allowedLabelsPset);

    edm::ParameterSetDescription noDefaultPset3;

    noDefaultPset3.addOptional<int>(std::string("noDefault1"));
    noDefaultPset3.addOptional<std::vector<int>>("noDefault2");
    noDefaultPset3.addOptional<unsigned>("noDefault3");
    noDefaultPset3.addOptional<std::vector<unsigned>>("noDefault4");
    noDefaultPset3.addOptional<long long>("noDefault5");
    noDefaultPset3.addOptional<std::vector<long long>>("noDefault6");
    noDefaultPset3.addOptional<unsigned long long>("noDefault7");
    noDefaultPset3.addOptional<std::vector<unsigned long long>>("noDefault8");
    noDefaultPset3.addOptional<double>("noDefault9");
    noDefaultPset3.addOptional<std::vector<double>>("noDefault10");
    noDefaultPset3.addOptional<bool>("noDefault11");
    noDefaultPset3.addOptional<std::string>("noDefault12");
    noDefaultPset3.addOptional<std::vector<std::string>>("noDefault13");
    noDefaultPset3.addOptional<edm::EventID>("noDefault14");
    noDefaultPset3.addOptional<std::vector<edm::EventID>>("noDefault15");
    noDefaultPset3.addOptional<edm::LuminosityBlockID>("noDefault16");
    noDefaultPset3.addOptional<std::vector<edm::LuminosityBlockID>>("noDefault17");
    noDefaultPset3.addOptional<edm::InputTag>("noDefault18");
    noDefaultPset3.addOptional<std::vector<edm::InputTag>>("noDefault19");
    noDefaultPset3.addOptional<edm::FileInPath>("noDefault20");
    noDefaultPset3.addOptional<edm::LuminosityBlockRange>("noDefault21");
    noDefaultPset3.addOptional<std::vector<edm::LuminosityBlockRange>>("noDefault22");
    noDefaultPset3.addOptional<edm::EventRange>("noDefault23");
    noDefaultPset3.addOptional<std::vector<edm::EventRange>>("noDefault24");

    iDesc.add("noDefaultPset3", noDefaultPset3);

    edm::ParameterSetDescription noDefaultPset4;

    noDefaultPset4.addOptionalUntracked<int>(std::string("noDefault1"));
    noDefaultPset4.addOptionalUntracked<std::vector<int>>("noDefault2");
    noDefaultPset4.addOptionalUntracked<unsigned>("noDefault3");
    noDefaultPset4.addOptionalUntracked<std::vector<unsigned>>("noDefault4");
    noDefaultPset4.addOptionalUntracked<long long>("noDefault5");
    noDefaultPset4.addOptionalUntracked<std::vector<long long>>("noDefault6");
    noDefaultPset4.addOptionalUntracked<unsigned long long>("noDefault7");
    noDefaultPset4.addOptionalUntracked<std::vector<unsigned long long>>("noDefault8");
    noDefaultPset4.addOptionalUntracked<double>("noDefault9");
    noDefaultPset4.addOptionalUntracked<std::vector<double>>("noDefault10");
    noDefaultPset4.addOptionalUntracked<bool>("noDefault11");
    noDefaultPset4.addOptionalUntracked<std::string>("noDefault12");
    noDefaultPset4.addOptionalUntracked<std::vector<std::string>>("noDefault13");
    noDefaultPset4.addOptionalUntracked<edm::EventID>("noDefault14");
    noDefaultPset4.addOptionalUntracked<std::vector<edm::EventID>>("noDefault15");
    noDefaultPset4.addOptionalUntracked<edm::LuminosityBlockID>("noDefault16");
    noDefaultPset4.addOptionalUntracked<std::vector<edm::LuminosityBlockID>>("noDefault17");
    noDefaultPset4.addOptionalUntracked<edm::InputTag>("noDefault18");
    noDefaultPset4.addOptionalUntracked<std::vector<edm::InputTag>>("noDefault19");
    noDefaultPset4.addOptionalUntracked<edm::FileInPath>("noDefault20");
    noDefaultPset4.addOptionalUntracked<edm::LuminosityBlockRange>("noDefault21");
    noDefaultPset4.addOptionalUntracked<std::vector<edm::LuminosityBlockRange>>("noDefault22");
    noDefaultPset4.addOptionalUntracked<edm::EventRange>("noDefault23");
    noDefaultPset4.addOptionalUntracked<std::vector<edm::EventRange>>("noDefault24");

    iDesc.add("noDefaultPset4", noDefaultPset4);

    edm::ParameterSetDescription pluginDesc;
    pluginDesc.addNode(edm::PluginDescription<AnotherIntFactory>("type", "edmtestAnotherValueMaker", true));
    iDesc.add<edm::ParameterSetDescription>("plugin", pluginDesc);

    edm::ParameterSetDescription pluginDesc1;
    pluginDesc1.addNode(edm::PluginDescription<AnotherIntFactory>("type", true));
    iDesc.add<edm::ParameterSetDescription>("plugin1", pluginDesc1);

    edm::ParameterSetDescription pluginDesc2;
    pluginDesc2.addNode(edm::PluginDescription<AnotherIntFactory>("type", true));
    std::vector<edm::ParameterSet> vDefaultsPlugins2;
    iDesc.addVPSet("plugin2", pluginDesc2, vDefaultsPlugins2);

    edm::ParameterSetDescription pluginDesc3;
    pluginDesc3.addNode(edm::PluginDescription<AnotherIntFactory>("type", true));
    std::vector<edm::ParameterSet> vDefaultsPlugins3;
    edm::ParameterSet vpsetDefault0;
    vpsetDefault0.addParameter<std::string>("type", "edmtestAnotherOneMaker");
    vDefaultsPlugins3.push_back(vpsetDefault0);
    edm::ParameterSet vpsetDefault1;
    vpsetDefault1.addParameter<std::string>("type", "edmtestAnotherValueMaker");
    vpsetDefault1.addParameter<int>("value", 11);
    vDefaultsPlugins3.push_back(vpsetDefault1);

    iDesc.addVPSet("plugin3", pluginDesc3, vDefaultsPlugins3);

    // ------------------------------------------

    descriptions.add("testProducerWithPsetDesc", iDesc);

    // ------------------------------------------

    edm::ParameterSetDescription iDesc1;
    iDesc1.add<int>("p_int", 1);
    iDesc1.setAllowAnything();
    iDesc1.setComment("A comment for a ParameterSetDescription");

    edm::ParameterSetDescription noDefaultPset1;

    noDefaultPset1.add<int>(std::string("noDefault1"));
    noDefaultPset1.add<std::vector<int>>("noDefault2");
    noDefaultPset1.add<unsigned>("noDefault3");
    noDefaultPset1.add<std::vector<unsigned>>("noDefault4");
    noDefaultPset1.add<long long>("noDefault5");
    noDefaultPset1.add<std::vector<long long>>("noDefault6");
    noDefaultPset1.add<unsigned long long>("noDefault7");
    noDefaultPset1.add<std::vector<unsigned long long>>("noDefault8");
    noDefaultPset1.add<double>("noDefault9");
    noDefaultPset1.add<std::vector<double>>("noDefault10");
    noDefaultPset1.add<bool>("noDefault11");
    noDefaultPset1.add<std::string>("noDefault12");
    noDefaultPset1.add<std::vector<std::string>>("noDefault13");
    noDefaultPset1.add<edm::EventID>("noDefault14");
    noDefaultPset1.add<std::vector<edm::EventID>>("noDefault15");
    noDefaultPset1.add<edm::LuminosityBlockID>("noDefault16");
    noDefaultPset1.add<std::vector<edm::LuminosityBlockID>>("noDefault17");
    noDefaultPset1.add<edm::InputTag>("noDefault18");
    noDefaultPset1.add<std::vector<edm::InputTag>>("noDefault19");
    noDefaultPset1.add<edm::FileInPath>("noDefault20");
    noDefaultPset1.add<edm::LuminosityBlockRange>("noDefault21");
    noDefaultPset1.add<std::vector<edm::LuminosityBlockRange>>("noDefault22");
    noDefaultPset1.add<edm::EventRange>("noDefault23");
    noDefaultPset1.add<std::vector<edm::EventRange>>("noDefault24");

    iDesc1.add("noDefaultPset1", noDefaultPset1);

    edm::ParameterSetDescription noDefaultPset2;

    noDefaultPset2.addUntracked<int>(std::string("noDefault1"));
    noDefaultPset2.addUntracked<std::vector<int>>("noDefault2");
    noDefaultPset2.addUntracked<unsigned>("noDefault3");
    noDefaultPset2.addUntracked<std::vector<unsigned>>("noDefault4");
    noDefaultPset2.addUntracked<long long>("noDefault5");
    noDefaultPset2.addUntracked<std::vector<long long>>("noDefault6");
    noDefaultPset2.addUntracked<unsigned long long>("noDefault7");
    noDefaultPset2.addUntracked<std::vector<unsigned long long>>("noDefault8");
    noDefaultPset2.addUntracked<double>("noDefault9");
    noDefaultPset2.addUntracked<std::vector<double>>("noDefault10");
    noDefaultPset2.addUntracked<bool>("noDefault11");
    noDefaultPset2.addUntracked<std::string>("noDefault12");
    noDefaultPset2.addUntracked<std::vector<std::string>>("noDefault13");
    noDefaultPset2.addUntracked<edm::EventID>("noDefault14");
    noDefaultPset2.addUntracked<std::vector<edm::EventID>>("noDefault15");
    noDefaultPset2.addUntracked<edm::LuminosityBlockID>("noDefault16");
    noDefaultPset2.addUntracked<std::vector<edm::LuminosityBlockID>>("noDefault17");
    noDefaultPset2.addUntracked<edm::InputTag>("noDefault18");
    noDefaultPset2.addUntracked<std::vector<edm::InputTag>>("noDefault19");
    noDefaultPset2.addUntracked<edm::FileInPath>("noDefault20");
    noDefaultPset2.addUntracked<edm::LuminosityBlockRange>("noDefault21");
    noDefaultPset2.addUntracked<std::vector<edm::LuminosityBlockRange>>("noDefault22");
    noDefaultPset2.addUntracked<edm::EventRange>("noDefault23");
    noDefaultPset2.addUntracked<std::vector<edm::EventRange>>("noDefault24");

    iDesc1.add("noDefaultPset2", noDefaultPset2);
    descriptions.add("testLabel1", iDesc1);

    // ------------------------------------------

    edm::ParameterSetDescription iDesc2;
    iDesc2.add<int>("p_int", 2);
    descriptions.addDefault(iDesc2);

    // ------------------------------------------

    edm::ParameterSetDescription iDesc3;
    iDesc3.add<int>("p_int", 3);
    descriptions.addWithDefaultLabel(iDesc3);
  }
}  // namespace edmtest
using edmtest::ProducerWithPSetDesc;
DEFINE_FWK_MODULE(ProducerWithPSetDesc);
