Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:42

0001 
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 
0006 #include "JANA/Components/JComponentFwd.h"
0007 #include "JANA/JApplicationFwd.h"
0008 #include "JANA/JFactory.h"
0009 #include "catch.hpp"
0010 #include "JFactoryTests.h"
0011 
0012 #include <JANA/JEvent.h>
0013 #include <JANA/JFactoryT.h>
0014 
0015 TEST_CASE("JFactoryTests") {
0016 
0017 
0018     SECTION("CreateAndGetData calls Init, ChangeRun, and Process as needed") {
0019 
0020         JFactoryTestDummyFactory sut;
0021         auto event = std::make_shared<JEvent>();
0022 
0023         // The first time it is run, Init, ChangeRun, and Process each get run once
0024         sut.CreateAndGetData(event);
0025         REQUIRE(sut.init_call_count == 1);
0026         REQUIRE(sut.change_run_call_count == 1);
0027         REQUIRE(sut.process_call_count == 1);
0028 
0029         // We can getOrCreate as many times as we want and nothing will happen
0030         // until somebody clears the factory (assuming persistence flag is unset)
0031         sut.CreateAndGetData(event);
0032         REQUIRE(sut.init_call_count == 1);
0033         REQUIRE(sut.change_run_call_count == 1);
0034         REQUIRE(sut.process_call_count == 1);
0035 
0036         // Once we clear the factory, Process gets called again but Init and ChangeRun do not.
0037         sut.ClearData();
0038         sut.CreateAndGetData(event);
0039         REQUIRE(sut.init_call_count == 1);
0040         REQUIRE(sut.change_run_call_count == 1);
0041         REQUIRE(sut.process_call_count == 2);
0042 
0043     }
0044 
0045     SECTION("If no factory is present and nothing inserted, GetObjects called") {
0046 
0047         // The event hasn't been given any DummyFactory, nor has anything been inserted.
0048         // Instead, the JEvent knows to go down to the JEventSource.
0049         auto event = std::make_shared<JEvent>();
0050         JFactoryTestDummySource sut;
0051 
0052         // Empty factory needed for GetObjects() to work
0053         event->GetFactorySet()->Add(new JFactoryT<JFactoryTestDummyObject>());
0054         event->SetJEventSource(&sut);
0055 
0056         auto data = event->Get<JFactoryTestDummyObject>("");
0057         REQUIRE(data[0]->data == 8);
0058         REQUIRE(data[1]->data == 88);
0059     }
0060 
0061     SECTION("ChangeRun called only when run number changes") {
0062         auto event = std::make_shared<JEvent>();
0063         JFactoryTestDummyFactory sut;
0064 
0065         // For the first event, ChangeRun() always gets called
0066         event->SetEventNumber(1);
0067         event->SetRunNumber(22);
0068         sut.CreateAndGetData(event);
0069         REQUIRE(sut.change_run_call_count == 1);
0070 
0071         // Subsequent events with the same run number do not trigger ChangeRun()
0072         event->SetEventNumber(2);
0073         sut.ClearData();
0074         sut.CreateAndGetData(event);
0075 
0076         event->SetEventNumber(3);
0077         sut.ClearData();
0078         sut.CreateAndGetData(event);
0079         REQUIRE(sut.change_run_call_count == 1);
0080 
0081         // As soon as the run number changes, ChangeRun() gets called again
0082         event->SetEventNumber(4);
0083         event->SetRunNumber(49);
0084         sut.ClearData();
0085         sut.CreateAndGetData(event);
0086         REQUIRE(sut.change_run_call_count == 2);
0087 
0088         // This keeps happening
0089         event->SetEventNumber(5);
0090         event->SetRunNumber(6180);
0091         sut.ClearData();
0092         sut.CreateAndGetData(event);
0093         REQUIRE(sut.change_run_call_count == 3);
0094     }
0095 
0096     SECTION("not PERSISTENT && not NOT_OBJECT_OWNER => JObject is cleared and deleted") {
0097         auto event = std::make_shared<JEvent>();
0098         JFactoryT<JFactoryTestDummyObject> sut; // Process() is a no-op
0099         bool deleted_flag = false;
0100         sut.ClearFactoryFlag(JFactory::PERSISTENT);
0101         sut.ClearFactoryFlag(JFactory::NOT_OBJECT_OWNER);
0102         sut.Insert(new JFactoryTestDummyObject(42, &deleted_flag));
0103         sut.ClearData();
0104         auto results = sut.CreateAndGetData(event);
0105         REQUIRE(std::distance(results.first, results.second) == 0);
0106         REQUIRE(deleted_flag == true);
0107     }
0108 
0109     SECTION("not PERSISTENT && NOT_OBJECT_OWNER => JObject is cleared but not deleted") {
0110         auto event = std::make_shared<JEvent>();
0111         JFactoryT<JFactoryTestDummyObject> sut; // Process() is a no-op
0112         bool deleted_flag = false;
0113         sut.ClearFactoryFlag(JFactory::PERSISTENT);
0114         sut.SetFactoryFlag(JFactory::NOT_OBJECT_OWNER);
0115         sut.Insert(new JFactoryTestDummyObject(42, &deleted_flag));
0116         sut.ClearData();
0117         auto results = sut.CreateAndGetData(event);
0118         REQUIRE(std::distance(results.first, results.second) == 0);
0119         REQUIRE(deleted_flag == false);
0120     }
0121 
0122     SECTION("PERSISTENT && not NOT_OBJECT_OWNER => JObject is neither cleared nor deleted") {
0123         JFactoryT<JFactoryTestDummyObject> sut; // Process() is a no-op
0124         auto event = std::make_shared<JEvent>();
0125         bool deleted_flag = false;
0126         sut.SetFactoryFlag(JFactory::PERSISTENT);
0127         sut.ClearFactoryFlag(JFactory::NOT_OBJECT_OWNER);
0128         sut.Insert(new JFactoryTestDummyObject(42, &deleted_flag));
0129         sut.ClearData();
0130         auto results = sut.CreateAndGetData(event);
0131         REQUIRE(std::distance(results.first, results.second) == 1);
0132         REQUIRE(deleted_flag == false);
0133     }
0134 
0135     SECTION("PERSISTENT && NOT_OBJECT_OWNER => JObject is neither cleared nor deleted") {
0136         JFactoryT<JFactoryTestDummyObject> sut; // Process() is a no-op
0137         auto event = std::make_shared<JEvent>();
0138         bool deleted_flag = false;
0139         sut.SetFactoryFlag(JFactory::PERSISTENT);
0140         sut.SetFactoryFlag(JFactory::NOT_OBJECT_OWNER);
0141         sut.Insert(new JFactoryTestDummyObject(42, &deleted_flag));
0142         sut.ClearData();
0143         auto results = sut.CreateAndGetData(event);
0144         REQUIRE(std::distance(results.first, results.second) == 1);
0145         REQUIRE(deleted_flag == false);
0146     }
0147 
0148     struct Issue135Factory : public JFactoryT<JFactoryTestDummyObject> {
0149         void Process(const std::shared_ptr<const JEvent>&) override {
0150             mData.emplace_back(new JFactoryTestDummyObject(3));
0151             mData.emplace_back(new JFactoryTestDummyObject(4));
0152             mData.emplace_back(new JFactoryTestDummyObject(5));
0153             Set(mData);
0154         }
0155     };
0156     SECTION("Issue 135: Users modifying mData directly and calling Set() afterwards") {
0157         // Unfortunately, we are giving users the ability to access mData directly.
0158         // If they do this, they might think they should call Set() directly afterwards so that
0159         // the Status and CreationStatus flags get correctly set.
0160         // Previously, this would clear mData before setting it, which would make their data
0161         // disappear, and they'd have to dig deep into the JANA internals to find out why.
0162         // Now, we account for this case. I still think we should clean up this abstraction, though.
0163 
0164         Issue135Factory sut;
0165         auto event = std::make_shared<JEvent>();
0166         auto results = sut.CreateAndGetData(event);
0167         REQUIRE(sut.GetNumObjects() == 3);
0168         REQUIRE(std::distance(results.first, results.second) == 3);
0169 
0170         int data = 3;
0171         for (auto it = results.first; it != results.second; ++it ) {
0172             REQUIRE((*it)->data == data);
0173             data++;
0174         }
0175     }
0176 
0177     struct RegenerateFactory : public JFactoryT<JFactoryTestDummyObject> {
0178         RegenerateFactory() {
0179             SetRegenerateFlag(true);
0180         }
0181         void Process(const std::shared_ptr<const JEvent>&) override {
0182             mData.emplace_back(new JFactoryTestDummyObject(49));
0183             Set(mData);
0184         }
0185     };
0186 
0187     SECTION("Factory regeneration") {
0188         RegenerateFactory sut;
0189         auto event = std::make_shared<JEvent>();
0190 
0191         std::vector<JFactoryTestDummyObject*> inserted_data;
0192         inserted_data.push_back(new JFactoryTestDummyObject(22));
0193         inserted_data.push_back(new JFactoryTestDummyObject(618));
0194         sut.Set(inserted_data);
0195 
0196         REQUIRE(sut.GetStatus() == JFactory::Status::Inserted);
0197 
0198         auto results = sut.CreateAndGetData(event);
0199         auto it = results.first;
0200         REQUIRE((*it)->data == 49);
0201         REQUIRE(sut.GetNumObjects() == 1);
0202     }
0203 
0204     SECTION("Exception in JFactory::Process") {
0205         LOG << "JFactoryTests: Exception in JFactory::Process" << LOG_END;
0206         auto event = std::make_shared<JEvent>();
0207         JFactoryTestExceptingFactory fac;
0208         REQUIRE(fac.GetStatus() == JFactory::Status::Uninitialized);
0209         REQUIRE_THROWS(fac.CreateAndGetData(event));
0210 
0211         REQUIRE(fac.GetStatus() == JFactory::Status::Unprocessed);
0212         REQUIRE_THROWS(fac.CreateAndGetData(event));
0213     }
0214 
0215     SECTION("Exception in JFactory::Init") {
0216         LOG << "JFactoryTests: Exception in JFactory::Init" << LOG_END;
0217         auto event = std::make_shared<JEvent>();
0218         JFactoryTestExceptingInInitFactory fac;
0219         REQUIRE(fac.GetStatus() == JFactory::Status::Uninitialized);
0220         REQUIRE_THROWS(fac.CreateAndGetData(event));
0221 
0222         REQUIRE(fac.GetStatus() == JFactory::Status::Uninitialized);
0223         REQUIRE_THROWS(fac.CreateAndGetData(event));
0224     }
0225 }
0226 
0227 
0228 struct MyExceptingFactory : public JFactoryT<JFactoryTestDummyObject> {
0229     void Process(const std::shared_ptr<const JEvent>&) override {
0230         throw std::runtime_error("Weird mystery!");
0231     }
0232 };
0233 
0234 TEST_CASE("JFactory_Exception") {
0235     JApplication app;
0236     app.Add(new JEventSource);
0237     app.Add(new JFactoryGeneratorT<MyExceptingFactory>());
0238     app.SetParameterValue("autoactivate", "JFactoryTestDummyObject");
0239     bool found_throw = false;
0240     try {
0241         app.Run();
0242     }
0243     catch(JException& ex) {
0244         LOG << ex << LOG_END;
0245         REQUIRE(ex.function_name == "JFactory::Process");
0246         REQUIRE(ex.message == "Weird mystery!");
0247         REQUIRE(ex.exception_type == "std::runtime_error");
0248         REQUIRE(ex.type_name == "MyExceptingFactory");
0249         REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0250         found_throw = true;
0251     }
0252     REQUIRE(found_throw == true);
0253 }
0254 
0255 struct ExceptingInitFactory : public JFactoryT<JFactoryTestDummyObject> {
0256     void Init() override {
0257         throw std::runtime_error("Exception in Init");
0258     }
0259     void Process(const std::shared_ptr<const JEvent>&) override {
0260         throw std::runtime_error("Exception in Process");
0261     }
0262 };
0263 
0264 TEST_CASE("JFactoryTests_ExceptingInitCalledTwice") {
0265     JApplication app;
0266     app.SetParameterValue("jana:loglevel", "error");
0267     app.Add(new JFactoryGeneratorT<ExceptingInitFactory>());
0268     auto event = std::make_shared<JEvent>(&app);
0269 
0270     bool found_throw = false;
0271     try {
0272         event->Get<JFactoryTestDummyObject>();
0273     }
0274     catch(JException& ex) {
0275         LOG << ex << LOG_END;
0276         REQUIRE(ex.function_name == "JFactory::Init");
0277         REQUIRE(ex.message == "Exception in Init");
0278         REQUIRE(ex.exception_type == "std::runtime_error");
0279         REQUIRE(ex.type_name == "ExceptingInitFactory");
0280         REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0281         found_throw = true;
0282     }
0283     REQUIRE(found_throw == true);
0284 
0285     // Second time around should except from Init again, NOT Process()
0286     found_throw = false;
0287     try {
0288         event->Get<JFactoryTestDummyObject>();
0289     }
0290     catch(JException& ex) {
0291         LOG << ex << LOG_END;
0292         REQUIRE(ex.function_name == "JFactory::Init");
0293         REQUIRE(ex.message == "Exception in Init");
0294         REQUIRE(ex.exception_type == "std::runtime_error");
0295         REQUIRE(ex.type_name == "ExceptingInitFactory");
0296         REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0297         found_throw = true;
0298     }
0299     REQUIRE(found_throw == true);
0300 }
0301 
0302 
0303 struct MyLoggedFactory : public JFactoryT<JFactoryTestDummyObject> {
0304     MyLoggedFactory() {
0305         SetPrefix("myfac");
0306     }
0307     void Process(const std::shared_ptr<const JEvent>&) override {
0308         LOG_INFO(GetLogger()) << "Process ran!" << LOG_END;
0309         REQUIRE(GetLogger().level == JLogger::Level::DEBUG);
0310     }
0311 };
0312 TEST_CASE("JFactory_Logger") {
0313     JApplication app;
0314     app.Add(new JEventSource);
0315     app.Add(new JFactoryGeneratorT<MyLoggedFactory>());
0316     app.SetParameterValue("jana:loglevel", "off");
0317     app.SetParameterValue("myfac:loglevel", "debug");
0318     app.SetParameterValue("jana:nevents", "1");
0319     app.SetParameterValue("autoactivate", "JFactoryTestDummyObject");
0320     app.Run();
0321 }
0322 
0323 std::vector<std::string> factory_with_finish_log;
0324 
0325 struct SourceWithRunNumberChange : public JEventSource {
0326     SourceWithRunNumberChange() {
0327         SetCallbackStyle(CallbackStyle::ExpertMode);
0328     }
0329     Result Emit(JEvent& event) {
0330         if (GetEmittedEventCount() < 2) {
0331             event.SetRunNumber(48);
0332         }
0333         else {
0334             event.SetRunNumber(49);
0335         }
0336         return Result::Success;
0337     }
0338 };
0339 
0340 struct FactoryWithFinish : public JFactoryT<JFactoryTestDummyObject> {
0341     Parameter<bool> except_on_init {this, "except_on_init", false, "Except on init"};
0342     Parameter<bool> except_on_beginrun {this, "except_on_beginrun", false, "Except on beginrun"};
0343     Parameter<bool> except_on_process {this, "except_on_process", false, "Except on process"};
0344     Parameter<bool> except_on_endrun {this, "except_on_endrun", false, "Except on endrun"};
0345     Parameter<bool> except_on_finish {this, "except_on_finish", false, "Except on finish"};
0346 
0347     void Init() override {
0348         LOG_INFO(GetLogger()) << "FactoryWithFinish::Init: " << this << LOG_END;
0349         factory_with_finish_log.push_back("init");
0350         if (*except_on_init) throw std::runtime_error("Mystery");
0351     }
0352     void BeginRun(const std::shared_ptr<const JEvent>&) override {
0353         LOG_INFO(GetLogger()) << "FactoryWithFinish::BeginRun: " << this << LOG_END;
0354         factory_with_finish_log.push_back("beginrun");
0355         if (*except_on_beginrun) throw std::runtime_error("Mystery");
0356     }
0357     void Process(const std::shared_ptr<const JEvent>&) override {
0358         LOG_INFO(GetLogger()) << "FactoryWithFinish::Process: " << this << LOG_END;
0359         factory_with_finish_log.push_back("process");
0360         if (*except_on_process) throw std::runtime_error("Mystery");
0361     }
0362     void EndRun() override {
0363         LOG_INFO(GetLogger()) << "FactoryWithFinish::EndRun: " << this << LOG_END;
0364         factory_with_finish_log.push_back("endrun");
0365         if (*except_on_endrun) throw std::runtime_error("Mystery");
0366     }
0367     void Finish() override {
0368         LOG_INFO(GetLogger()) << "FactoryWithFinish::Finish: " << this << LOG_END;
0369         factory_with_finish_log.push_back("finish");
0370         if (*except_on_finish) throw std::runtime_error("Mystery");
0371     }
0372 };
0373 
0374 TEST_CASE("JFactory_CallbackSequence") {
0375     JApplication app;
0376     app.Add(new JFactoryGeneratorT<FactoryWithFinish>());
0377     app.SetParameterValue("autoactivate", "JFactoryTestDummyObject");
0378     app.SetParameterValue("jana:max_inflight_events", 1);
0379     
0380     SECTION("NoRunNumber") {
0381         app.Add(new JEventSource);
0382         app.SetParameterValue("jana:nevents", 2);
0383         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0384         factory_with_finish_log.clear();
0385         app.Run();
0386         for (auto& s : factory_with_finish_log) {
0387             std::cout << s << std::endl;
0388         }
0389         REQUIRE(factory_with_finish_log.size() == 6);
0390         REQUIRE(factory_with_finish_log.at(0) == "init");
0391         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0392         REQUIRE(factory_with_finish_log.at(2) == "process");
0393         REQUIRE(factory_with_finish_log.at(3) == "process");
0394         REQUIRE(factory_with_finish_log.at(4) == "endrun");
0395         REQUIRE(factory_with_finish_log.at(5) == "finish");
0396     }
0397     SECTION("ConstantRunNumber") {
0398         app.Add(new SourceWithRunNumberChange);
0399         app.SetParameterValue("jana:nevents", 2);
0400         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0401         factory_with_finish_log.clear();
0402         app.Run();
0403         REQUIRE(factory_with_finish_log.size() == 6);
0404         REQUIRE(factory_with_finish_log.at(0) == "init");
0405         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0406         REQUIRE(factory_with_finish_log.at(2) == "process");
0407         REQUIRE(factory_with_finish_log.at(3) == "process");
0408         REQUIRE(factory_with_finish_log.at(4) == "endrun");
0409         REQUIRE(factory_with_finish_log.at(5) == "finish");
0410     }
0411     SECTION("MultipleRunNumbers") {
0412         app.Add(new SourceWithRunNumberChange);
0413         app.SetParameterValue("jana:nevents", 5);
0414         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0415         factory_with_finish_log.clear();
0416         app.Run();
0417         REQUIRE(factory_with_finish_log.size() == 11);
0418         REQUIRE(factory_with_finish_log.at(0) == "init");
0419         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0420         REQUIRE(factory_with_finish_log.at(2) == "process");
0421         REQUIRE(factory_with_finish_log.at(3) == "process");
0422         REQUIRE(factory_with_finish_log.at(4) == "endrun");
0423         REQUIRE(factory_with_finish_log.at(5) == "beginrun");
0424         REQUIRE(factory_with_finish_log.at(6) == "process");
0425         REQUIRE(factory_with_finish_log.at(7) == "process");
0426         REQUIRE(factory_with_finish_log.at(8) == "process");
0427         REQUIRE(factory_with_finish_log.at(9) == "endrun");
0428         REQUIRE(factory_with_finish_log.at(10) == "finish");
0429     }
0430 }
0431 
0432 TEST_CASE("JFactory_ExceptionHandling") {
0433     JApplication app;
0434     app.Add(new JFactoryGeneratorT<FactoryWithFinish>());
0435     app.SetParameterValue("autoactivate", "JFactoryTestDummyObject");
0436     app.SetParameterValue("jana:max_inflight_events", 1);
0437 
0438     SECTION("ExceptOnInit") {
0439         app.Add(new SourceWithRunNumberChange);
0440         app.SetParameterValue("jana:nevents", 2);
0441         app.SetParameterValue("JFactoryTestDummyObject:except_on_init", true);
0442         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0443         factory_with_finish_log.clear();
0444         bool found_throw = false;
0445         try {
0446             app.Run();
0447         }
0448         catch(JException& ex) {
0449             LOG << ex << LOG_END;
0450             REQUIRE(ex.function_name == "JFactory::Init");
0451             REQUIRE(ex.message == "Mystery");
0452             REQUIRE(ex.exception_type == "std::runtime_error");
0453             REQUIRE(ex.type_name == "FactoryWithFinish");
0454             REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0455             found_throw = true;
0456         }
0457         REQUIRE(found_throw == true);
0458         REQUIRE(factory_with_finish_log.size() == 1);
0459         REQUIRE(factory_with_finish_log.at(0) == "init");
0460     }
0461 
0462     SECTION("ExceptOnBeginRun") {
0463         app.Add(new SourceWithRunNumberChange);
0464         app.SetParameterValue("jana:nevents", 2);
0465         app.SetParameterValue("JFactoryTestDummyObject:except_on_beginrun", true);
0466         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0467         factory_with_finish_log.clear();
0468         bool found_throw = false;
0469         try {
0470             app.Run();
0471         }
0472         catch(JException& ex) {
0473             LOG << ex << LOG_END;
0474             REQUIRE(ex.function_name == "JFactory::BeginRun");
0475             REQUIRE(ex.message == "Mystery");
0476             REQUIRE(ex.exception_type == "std::runtime_error");
0477             REQUIRE(ex.type_name == "FactoryWithFinish");
0478             REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0479             found_throw = true;
0480         }
0481         REQUIRE(found_throw == true);
0482         REQUIRE(factory_with_finish_log.size() == 2);
0483         REQUIRE(factory_with_finish_log.at(0) == "init");
0484         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0485     }
0486 
0487     SECTION("ExceptOnProcess") {
0488         app.Add(new SourceWithRunNumberChange);
0489         app.SetParameterValue("jana:nevents", 2);
0490         app.SetParameterValue("JFactoryTestDummyObject:except_on_process", true);
0491         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0492         factory_with_finish_log.clear();
0493         bool found_throw = false;
0494         try {
0495             app.Run();
0496         }
0497         catch(JException& ex) {
0498             LOG << ex << LOG_END;
0499             REQUIRE(ex.function_name == "JFactory::Process");
0500             REQUIRE(ex.message == "Mystery");
0501             REQUIRE(ex.exception_type == "std::runtime_error");
0502             REQUIRE(ex.type_name == "FactoryWithFinish");
0503             REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0504             found_throw = true;
0505         }
0506         REQUIRE(found_throw == true);
0507         REQUIRE(factory_with_finish_log.size() == 3);
0508         REQUIRE(factory_with_finish_log.at(0) == "init");
0509         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0510         REQUIRE(factory_with_finish_log.at(2) == "process");
0511     }
0512 
0513     SECTION("ExceptOnEndRun") {
0514         app.Add(new SourceWithRunNumberChange);
0515         app.SetParameterValue("jana:nevents", 2);
0516         app.SetParameterValue("JFactoryTestDummyObject:except_on_endrun", true);
0517         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0518         factory_with_finish_log.clear();
0519         bool found_throw = false;
0520         try {
0521             app.Run();
0522         }
0523         catch(JException& ex) {
0524             LOG << ex << LOG_END;
0525             REQUIRE(ex.function_name == "JFactory::EndRun");
0526             REQUIRE(ex.message == "Mystery");
0527             REQUIRE(ex.exception_type == "std::runtime_error");
0528             REQUIRE(ex.type_name == "FactoryWithFinish");
0529             REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0530             found_throw = true;
0531         }
0532         REQUIRE(found_throw == true);
0533         REQUIRE(factory_with_finish_log.size() == 5);
0534         REQUIRE(factory_with_finish_log.at(0) == "init");
0535         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0536         REQUIRE(factory_with_finish_log.at(2) == "process");
0537         REQUIRE(factory_with_finish_log.at(3) == "process");
0538         REQUIRE(factory_with_finish_log.at(4) == "endrun");
0539     }
0540     SECTION("ExceptOnFinish") {
0541         app.Add(new SourceWithRunNumberChange);
0542         app.SetParameterValue("jana:nevents", 2);
0543         app.SetParameterValue("JFactoryTestDummyObject:except_on_finish", true);
0544         app.Initialize(); // This init()s a throwaway JFactoryT, which we immediately clear from the log
0545         factory_with_finish_log.clear();
0546         bool found_throw = false;
0547         try {
0548             app.Run();
0549         }
0550         catch(JException& ex) {
0551             LOG << ex << LOG_END;
0552             REQUIRE(ex.function_name == "JFactory::Finish");
0553             REQUIRE(ex.message == "Mystery");
0554             REQUIRE(ex.exception_type == "std::runtime_error");
0555             REQUIRE(ex.type_name == "FactoryWithFinish");
0556             REQUIRE(ex.instance_name == "JFactoryTestDummyObject");
0557             found_throw = true;
0558         }
0559         REQUIRE(found_throw == true);
0560         REQUIRE(factory_with_finish_log.size() == 6);
0561         REQUIRE(factory_with_finish_log.at(0) == "init");
0562         REQUIRE(factory_with_finish_log.at(1) == "beginrun");
0563         REQUIRE(factory_with_finish_log.at(2) == "process");
0564         REQUIRE(factory_with_finish_log.at(3) == "process");
0565         REQUIRE(factory_with_finish_log.at(4) == "endrun");
0566         REQUIRE(factory_with_finish_log.at(5) == "finish");
0567     }
0568 }
0569 
0570 TEST_CASE("JFactory_GetObjects_Caching") {
0571     JApplication app;
0572     app.Add(new JFactoryGeneratorT<JFactoryT<JFactoryTestDummyObject>>());
0573     app.Add(new JFactoryGeneratorT<JFactoryT<DifferentDummyObject>>());
0574     auto source = new JFactoryTestDummySource;
0575     auto event = std::make_shared<JEvent>(&app);
0576     event->SetJEventSource(source);
0577 
0578     SECTION("RepeatedGetObjectsAreCached") {
0579         auto dummies = event->Get<JFactoryTestDummyObject>();
0580         REQUIRE(dummies.at(0)->data == 8);
0581         REQUIRE(source->get_objects_count == 1);
0582         REQUIRE(source->get_objects_dummy_count == 1);
0583 
0584         dummies = event->Get<JFactoryTestDummyObject>();
0585         REQUIRE(dummies.at(0)->data == 8);
0586         REQUIRE(source->get_objects_count == 1);
0587         REQUIRE(source->get_objects_dummy_count == 1);
0588     }
0589 
0590     SECTION("DifferentGetObjectsAreNotCached") {
0591         auto dummies = event->Get<JFactoryTestDummyObject>();
0592         REQUIRE(dummies.at(0)->data == 8);
0593         REQUIRE(source->get_objects_count == 1);
0594         REQUIRE(source->get_objects_dummy_count == 1);
0595         REQUIRE(source->get_objects_different_count == 0);
0596 
0597         auto different = event->Get<DifferentDummyObject>();
0598         REQUIRE(different.at(0)->E == 123.0);
0599         REQUIRE(source->get_objects_count == 2);
0600         REQUIRE(source->get_objects_dummy_count == 1);
0601         REQUIRE(source->get_objects_different_count == 1);
0602 
0603         different = event->Get<DifferentDummyObject>();
0604         REQUIRE(different.at(0)->E == 123.0);
0605         REQUIRE(source->get_objects_count == 2);
0606         REQUIRE(source->get_objects_dummy_count == 1);
0607         REQUIRE(source->get_objects_different_count == 1);
0608     }
0609 }