LCOV - code coverage report
Current view: top level - test - testOutput.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 97.0 % 165 160
Test Date: 2026-06-18 09:49:19 Functions: 94.4 % 18 17

            Line data    Source code
       1              : /** Unit tests for Output modules of CRPropa
       2              :     Output
       3              :     TextOutput
       4              :     ParticleCollector
       5              :  */
       6              : 
       7              : #include "CRPropa.h"
       8              : 
       9              : #include "gtest/gtest.h"
      10              : #include <iostream>
      11              : #include <string>
      12              : 
      13              : 
      14              : #ifdef CRPROPA_HAVE_HDF5
      15              : #include <hdf5.h>
      16              : #endif
      17              : 
      18              : // compare two arrays (intead of using Google Mock)
      19              : // https://stackoverflow.com/a/10062016/6819103
      20              : template <typename T, size_t size>
      21            1 : ::testing::AssertionResult ArraysMatch(const T (&expected)[size],
      22              :                                        const T (&actual)[size]) {
      23           11 :         for (size_t i(0); i < size; ++i) {
      24           10 :                 if (expected[i] != actual[i]) {
      25              :                         return ::testing::AssertionFailure()
      26            0 :                                << "array[" << i << "] (" << actual[i] << ") != expected["
      27            0 :                                << i << "] (" << expected[i] << ")";
      28              :                 }
      29              :         }
      30              : 
      31            1 :         return ::testing::AssertionSuccess();
      32              : }
      33              : 
      34              : namespace crpropa {
      35              : 
      36              : //-- Output
      37            1 : TEST(Output, size) {
      38            1 :         Candidate c;
      39            1 :         Output output;
      40            6 :         for (int it = 0; it < 5; ++it, output.process(&c));
      41              : 
      42            1 :         EXPECT_EQ(output.size(), 5);
      43            1 : }
      44              : 
      45              : //-- TextOutput
      46            1 : TEST(TextOutput, printHeader_Trajectory1D) {
      47            1 :         Candidate c;
      48            1 :         TextOutput output(Output::Trajectory1D);
      49              : 
      50            1 :         ::testing::internal::CaptureStdout();
      51            1 :         output.process(&c);
      52            1 :         std::string captured = testing::internal::GetCapturedStdout();
      53              : 
      54            2 :         EXPECT_EQ(captured.substr(0, captured.find("\n")), "#\tID\tE\tX");
      55            1 : }
      56              : 
      57            1 : TEST(TextOutput, printHeader_Event1D) {
      58            1 :         Candidate c;
      59            1 :         TextOutput output(Output::Event1D);
      60              : 
      61            1 :         ::testing::internal::CaptureStdout();
      62            1 :         output.process(&c);
      63            1 :         std::string captured = testing::internal::GetCapturedStdout();
      64              : 
      65            2 :         EXPECT_EQ(captured.substr(0, captured.find("\n")), "#\tD\tID\tE\tID0\tE0");
      66            1 : }
      67              : 
      68            1 : TEST(TextOutput, printHeader_Trajectory3D) {
      69            1 :         Candidate c;
      70            1 :         TextOutput output(Output::Trajectory3D);
      71              : 
      72            1 :         ::testing::internal::CaptureStdout();
      73            1 :         output.process(&c);
      74            1 :         std::string captured = testing::internal::GetCapturedStdout();
      75              : 
      76            2 :         EXPECT_EQ(captured.substr(0, captured.find("\n")),
      77              :                   "#\tD\tID\tE\tX\tY\tZ\tPx\tPy\tPz");
      78            1 : }
      79              : 
      80            1 : TEST(TextOutput, printHeader_Event3D) {
      81            1 :         Candidate c;
      82            1 :         TextOutput output(Output::Event3D);
      83              : 
      84            1 :         ::testing::internal::CaptureStdout();
      85            1 :         output.process(&c);
      86            1 :         std::string captured = testing::internal::GetCapturedStdout();
      87              : 
      88            2 :         EXPECT_EQ(
      89              :             captured.substr(0, captured.find("\n")),
      90              :             "#\tD\tID\tE\tX\tY\tZ\tPx\tPy\tPz\tID0\tE0\tX0\tY0\tZ0\tP0x\tP0y\tP0z");
      91            1 : }
      92              : 
      93            1 : TEST(TextOutput, printHeader_Custom) {
      94            1 :         Candidate c;
      95            1 :         TextOutput output(Output::Event1D);
      96              : 
      97            1 :         output.enable(Output::SerialNumberColumn);
      98            1 :         output.disable(Output::TrajectoryLengthColumn);
      99            1 :         output.set(Output::RedshiftColumn, false);
     100            1 :         output.enable(Output::CandidateTagColumn);
     101            1 :         output.enable(Output::TimeColumn);
     102              : 
     103            1 :         ::testing::internal::CaptureStdout();
     104            1 :         output.process(&c);
     105            1 :         std::string captured = testing::internal::GetCapturedStdout();
     106              : 
     107            2 :         EXPECT_EQ(captured.substr(0, captured.find("\n")),
     108              :                   "#\ttime\tSN\tID\tE\tSN0\tID0\tE0\tSN1\ttag");
     109            1 : }
     110              : 
     111            1 : TEST(TextOutput, printProperty) {
     112            1 :         Candidate c;
     113            1 :         TextOutput output(Output::Event1D);
     114            1 :         output.disableAll();
     115            2 :         output.enableProperty("foo", 2.0, "Bar");
     116              : 
     117            1 :         ::testing::internal::CaptureStdout();
     118            1 :         output.process(&c);
     119            1 :         std::string captured = testing::internal::GetCapturedStdout();
     120              : 
     121              :         // name in first line of header
     122            2 :         EXPECT_EQ(captured.substr(0, captured.find("\n")), "#\tfoo");
     123            1 : }
     124              : 
     125            1 : TEST(TextOutput, printHeader_Version) {
     126            1 :         Candidate c;
     127            1 :         TextOutput output(Output::Event1D);
     128              : 
     129            1 :         ::testing::internal::CaptureStdout();
     130            1 :         output.process(&c);
     131            1 :         std::string captured = testing::internal::GetCapturedStdout();
     132              : 
     133              :         // length of the prefix is 19 chars
     134            1 :         size_t version_pos = captured.find("# CRPropa version: ") + 19;
     135              : 
     136            2 :         EXPECT_EQ(captured.substr(version_pos,
     137              :                                   captured.find("\n", version_pos) - version_pos),
     138              :                   g_GIT_DESC);
     139            1 : }
     140              : 
     141              : #ifndef CRPROPA_TESTS_SKIP_EXCEPTIONS
     142            1 : TEST(TextOutput, failOnIllegalOutputFile) {
     143            2 :         EXPECT_THROW(
     144              :             TextOutput output("THIS_FOLDER_MUST_NOT_EXISTS_12345+/FILE.txt"),
     145              :             std::runtime_error);
     146            1 : }
     147              : #endif
     148              : 
     149              : #ifdef CRPROPA_HAVE_HDF5
     150              : #ifndef CRPROPA_TESTS_SKIP_EXCEPTIONS
     151            1 : TEST(HDF5Output, failOnIllegalOutputFile) {
     152            1 :         HDF5Output out;
     153              :         // disable default error output of HDF5
     154            1 :         H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
     155            2 :         EXPECT_THROW(out.open("THIS_FOLDER_MUST_NOT_EXISTS_12345+/FILE.h5"),
     156              :                      std::runtime_error);
     157            1 : }
     158              : #endif
     159              : #endif
     160              : 
     161              : //-- ParticleCollector
     162            1 : TEST(ParticleCollector, size) {
     163            1 :         ref_ptr<Candidate> c = new Candidate();
     164            1 :         ParticleCollector output;
     165              : 
     166            6 :         for (int it = 0; it < 5; ++it, output.process(c))
     167              :                 ;
     168              : 
     169            1 :         EXPECT_EQ(output.size(), 5);
     170            2 : }
     171              : 
     172            1 : TEST(ParticleCollector, fetchItem) {
     173            1 :         ref_ptr<Candidate> c = new Candidate(nucleusId(1, 1), 1 * EeV);
     174            1 :         ParticleCollector output;
     175              : 
     176            1 :         output.process(c);
     177              : 
     178            2 :         EXPECT_EQ(output[0], c);
     179            2 : }
     180              : 
     181            1 : TEST(ParticleCollector, reprocess) {
     182            1 :         ref_ptr<Candidate> c = new Candidate(nucleusId(1, 1), 1 * EeV);
     183            1 :         ParticleCollector collector;
     184            1 :         ParticleCollector output;
     185              : 
     186            1 :         collector.process(c);
     187            1 :         collector.reprocess(&output);
     188              : 
     189            2 :         EXPECT_EQ(output[0], c);
     190            2 : }
     191              : 
     192            1 : TEST(ParticleCollector, dumpload) {
     193            1 :         ref_ptr<Candidate> c = new Candidate(nucleusId(1, 1), 1.234 * EeV);
     194            1 :         c->current.setPosition(Vector3d(1, 2, 3));
     195            1 :         c->current.setDirection(Vector3d(-1, -1, -1));
     196            1 :         c->setTrajectoryLength(1 * Mpc);
     197            1 :         c->setRedshift(2);
     198            1 :         c->setTime(3 * Myr);
     199              : 
     200            1 :         ParticleCollector input;
     201            1 :         ParticleCollector output;
     202              : 
     203           12 :         for (int i = 0; i <= 10; ++i) {
     204           22 :                 input.process(c);
     205              :         }
     206              : 
     207              :         // Well, it would be nicer if we don't need to receate any file
     208            1 :         input.dump("ParticleCollector_DumpTest.txt");
     209            1 :         output.load("ParticleCollector_DumpTest.txt");
     210              : 
     211            1 :         EXPECT_EQ(input.size(), output.size());
     212            2 :         EXPECT_EQ(output[0]->current.getEnergy(), c->current.getEnergy());
     213            2 :         EXPECT_EQ(output[1]->getTrajectoryLength(), c->getTrajectoryLength());
     214            2 :         EXPECT_EQ(output[2]->current.getId(), c->current.getId());
     215            2 :         EXPECT_EQ(output[3]->getRedshift(), c->getRedshift());
     216            2 :         EXPECT_EQ(output[4]->getTime(), c->getTime());
     217            2 : }
     218              : 
     219              : // Just test if the trajectory is on a line for rectilinear propagation
     220            1 : TEST(ParticleCollector, getTrajectory) {
     221              :         int pos_x[10];
     222            1 :         int pos_x_expected[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
     223              : 
     224            1 :         ParticleState p;
     225            1 :         p.setPosition(Vector3d(10, 0, 0));
     226            1 :         p.setDirection(Vector3d(-1, 0, 0));
     227            1 :         ref_ptr<Candidate> c = new Candidate(p);
     228              : 
     229            1 :         ref_ptr<ParticleCollector> output = new ParticleCollector();
     230            1 :         ref_ptr<ParticleCollector> trajectory = new ParticleCollector();
     231            1 :         trajectory->setClone(true);
     232              : 
     233            1 :         ref_ptr<ModuleList> sim = new ModuleList();
     234            1 :         sim->add(new SimplePropagation(1, 1));
     235              : 
     236            1 :         ref_ptr<Observer> obs = new Observer();
     237            1 :         obs->add(new Observer1D());
     238            1 :         obs->onDetection(output);
     239            1 :         sim->add(obs);
     240              : 
     241            2 :         sim->run(c);
     242              : 
     243            2 :         output->getTrajectory(sim, 0, trajectory);
     244              : 
     245              :         Vector3d pos;
     246              :         int i = 0;
     247              : 
     248            1 :         for (ParticleCollector::iterator itr = trajectory->begin();
     249           11 :              itr != trajectory->end(); ++itr) {
     250           10 :                 pos = (*(itr->get())).current.getPosition();
     251           10 :                 pos_x[i] = pos.getX();
     252           10 :                 ++i;
     253              :         }
     254              : 
     255            1 :         EXPECT_TRUE(ArraysMatch(pos_x_expected, pos_x));
     256            1 : }
     257              : 
     258            1 : TEST(ParticleCollector, runModuleList) {
     259            1 :         ModuleList modules;
     260            1 :         modules.add(new SimplePropagation());
     261            1 :         modules.add(new MaximumTrajectoryLength(1 * Mpc));
     262              : 
     263            1 :         ParticleState p;
     264            1 :         p.setPosition(Vector3d(10, 0, 0));
     265            1 :         p.setDirection(Vector3d(-1, 0, 0));
     266            1 :         ref_ptr<Candidate> c = new Candidate(p);
     267              : 
     268            1 :         ref_ptr<ParticleCollector> collector = new ParticleCollector();
     269              : 
     270            1 :         collector->process(c);
     271              : 
     272            1 :         modules.setShowProgress(false);
     273            1 :         auto candidates = collector->getContainer();
     274            1 :         modules.run(&candidates);
     275            2 : }
     276              : 
     277            0 : int main(int argc, char **argv) {
     278            0 :         ::testing::InitGoogleTest(&argc, argv);
     279            0 :         return RUN_ALL_TESTS();
     280              : }
     281              : 
     282              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1