Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-17 09:11:23

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