LCOV - code coverage report
Current view: top level - core/tests - test_DataHandlers.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 391 391 100.0 %
Date: 2022-02-28 03:37:41 Functions: 90 90 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_DataHandlers.cpp
       3             :  *
       4             :  * @brief Common tests for DataHandlers class
       5             :  *
       6             :  * @author David Frank - initial code
       7             :  * @author Tobias Lasser - rewrite and code coverage
       8             :  * @author Jens Petit - refactoring to general DataHandler test
       9             :  */
      10             : 
      11             : #include "doctest/doctest.h"
      12             : #include "DataHandlerCPU.h"
      13             : #include "DataHandlerMapCPU.h"
      14             : #include "testHelpers.h"
      15             : 
      16             : #ifdef ELSA_CUDA_VECTOR
      17             : #include "DataHandlerGPU.h"
      18             : #include "DataHandlerMapGPU.h"
      19             : #endif
      20             : 
      21             : template <typename data_t>
      22         181 : long elsa::useCount(const DataHandlerCPU<data_t>& dh)
      23             : {
      24         181 :     return dh._data.use_count();
      25             : }
      26             : 
      27             : #ifdef ELSA_CUDA_VECTOR
      28             : template <typename data_t>
      29             : long elsa::useCount(const DataHandlerGPU<data_t>& dh)
      30             : {
      31             :     return dh._data.use_count();
      32             : }
      33             : #endif
      34             : 
      35             : using namespace elsa;
      36             : using namespace doctest;
      37             : 
      38             : using CPUTypeTuple =
      39             :     std::tuple<DataHandlerCPU<float>, DataHandlerCPU<double>, DataHandlerCPU<complex<float>>,
      40             :                DataHandlerCPU<complex<double>>, DataHandlerCPU<index_t>>;
      41             : 
      42         288 : TYPE_TO_STRING(DataHandlerCPU<float>);
      43         252 : TYPE_TO_STRING(DataHandlerCPU<double>);
      44         252 : TYPE_TO_STRING(DataHandlerCPU<index_t>);
      45         252 : TYPE_TO_STRING(DataHandlerCPU<complex<float>>);
      46         252 : TYPE_TO_STRING(DataHandlerCPU<complex<double>>);
      47             : 
      48             : #ifdef ELSA_CUDA_VECTOR
      49             : using GPUTypeTuple =
      50             :     std::tuple<DataHandlerGPU<float>, DataHandlerGPU<double>, DataHandlerGPU<complex<float>>,
      51             :                DataHandlerGPU<complex<double>>, DataHandlerGPU<index_t>>;
      52             : 
      53             : TYPE_TO_STRING(DataHandlerGPU<float>);
      54             : TYPE_TO_STRING(DataHandlerGPU<double>);
      55             : TYPE_TO_STRING(DataHandlerGPU<index_t>);
      56             : TYPE_TO_STRING(DataHandlerGPU<complex<float>>);
      57             : TYPE_TO_STRING(DataHandlerGPU<complex<double>>);
      58             : #endif
      59             : 
      60             : TEST_SUITE_BEGIN("core");
      61             : 
      62         236 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing Construction", TestType, datahandler_construction)
      63             : {
      64             :     using data_t = typename TestType::value_type;
      65             : 
      66          40 :     GIVEN("a certain size")
      67             :     {
      68          20 :         index_t size = 314;
      69             : 
      70          25 :         WHEN("constructing")
      71             :         {
      72          10 :             const TestType dh{size};
      73             : 
      74           5 :             THEN("it has the correct size") { REQUIRE_EQ(size, dh.getSize()); }
      75             :         }
      76             : 
      77          25 :         WHEN("constructing with a given vector")
      78             :         {
      79          10 :             auto randVec = generateRandomMatrix<data_t>(size);
      80          10 :             const TestType dh{randVec};
      81             : 
      82        1575 :             for (index_t i = 0; i < size; ++i)
      83        1570 :                 REQUIRE_UNARY(checkApproxEq(dh[i], randVec(i)));
      84             :         }
      85             : 
      86          25 :         WHEN("copy constructing")
      87             :         {
      88          10 :             auto randVec = generateRandomMatrix<data_t>(size);
      89          10 :             const TestType dh{randVec};
      90          10 :             const auto dhView = dh.getBlock(0, size);
      91             : 
      92          10 :             TestType dh2 = dh;
      93             : 
      94          10 :             THEN("a shallow copy is created")
      95             :             {
      96           5 :                 REQUIRE_EQ(dh2, dh);
      97           5 :                 REQUIRE_EQ(useCount(dh), 2);
      98             : 
      99          10 :                 const auto dh2View = dh2.getBlock(0, size);
     100          10 :                 AND_THEN("associated maps are not transferred")
     101             :                 {
     102           5 :                     dh2[0] = data_t(1);
     103           5 :                     REQUIRE_UNARY(checkApproxEq(dh2[0], 1));
     104           5 :                     REQUIRE_UNARY(checkApproxEq((*dhView)[0], randVec[0]));
     105           5 :                     REQUIRE_UNARY(checkApproxEq((*dh2View)[0], 1));
     106             :                 }
     107             :             }
     108             :         }
     109             : 
     110          25 :         WHEN("move constructing")
     111             :         {
     112          10 :             auto randVec = generateRandomMatrix<data_t>(size);
     113          10 :             TestType dh{randVec};
     114          10 :             const auto dhView = dh.getBlock(0, size);
     115          10 :             TestType testDh{randVec};
     116             : 
     117          10 :             const TestType dh2 = std::move(dh);
     118             : 
     119          10 :             THEN("data and associated maps are moved to the new handler")
     120             :             {
     121           5 :                 REQUIRE_EQ(useCount(dh2), 1);
     122           5 :                 REQUIRE_EQ(dh2, testDh);
     123           5 :                 REQUIRE_EQ(&(*dhView)[0], &dh2[0]);
     124             :             }
     125             :         }
     126             :     }
     127          20 : }
     128             : 
     129         236 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing equality operator", TestType, datahandler_equality)
     130             : {
     131             :     using data_t = typename TestType::value_type;
     132             : 
     133          40 :     GIVEN("some DataHandler")
     134             :     {
     135          20 :         const index_t size = 314;
     136          40 :         auto randVec = generateRandomMatrix<data_t>(size);
     137          40 :         const TestType dh{randVec};
     138             : 
     139          25 :         WHEN("comparing to a handler with a different size")
     140             :         {
     141          10 :             const TestType dh2{size + 1};
     142          10 :             THEN("the result is false")
     143             :             {
     144           5 :                 REQUIRE_NE(dh, dh2);
     145           5 :                 REQUIRE_NE(dh, *dh2.getBlock(0, size + 1));
     146             :             }
     147             :         }
     148             : 
     149          25 :         WHEN("comparing to a shallow copy or view of the handler")
     150             :         {
     151          10 :             const auto dh2 = dh;
     152          10 :             THEN("the result is true")
     153             :             {
     154           5 :                 REQUIRE_EQ(dh, dh2);
     155           5 :                 REQUIRE_EQ(dh, *dh.getBlock(0, size));
     156             :             }
     157             :         }
     158             : 
     159          25 :         WHEN("comparing to a deep copy or a view of the deep copy")
     160             :         {
     161          10 :             const TestType dh2{randVec};
     162          10 :             THEN("the result is true")
     163             :             {
     164           5 :                 REQUIRE_EQ(dh, dh2);
     165           5 :                 REQUIRE_EQ(dh, *dh2.getBlock(0, size));
     166             :             }
     167             :         }
     168             : 
     169          25 :         WHEN("comparing to a handler or map with different data")
     170             :         {
     171           5 :             randVec[0] += 1;
     172          10 :             const TestType dh2{randVec};
     173          10 :             THEN("the result is false")
     174             :             {
     175           5 :                 REQUIRE_NE(dh, dh2);
     176           5 :                 REQUIRE_NE(dh, *dh2.getBlock(0, size));
     177             :             }
     178             :         }
     179             :     }
     180          20 : }
     181             : 
     182         296 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Assigning to DataHandlerCPU", TestType,
     183             :                           datahandler_assigncpu)
     184             : {
     185             :     using data_t = typename TestType::value_type;
     186             : 
     187         160 :     GIVEN("a DataHandlerCPU with an associated map")
     188             :     {
     189          80 :         const index_t size = 314;
     190         160 :         DataHandlerCPU<data_t> dh{size};
     191         160 :         auto dhMap = dh.getBlock(size / 2, size / 3);
     192             : 
     193          90 :         WHEN("copy assigning")
     194             :         {
     195             : 
     196          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     197          20 :             const DataHandlerCPU dh2{randVec};
     198          20 :             const auto dh2Map = dh2.getBlock(size / 2, size / 3);
     199             : 
     200          15 :             THEN("sizes must match")
     201             :             {
     202          10 :                 const DataHandlerCPU<data_t> bigDh{2 * size};
     203          10 :                 REQUIRE_THROWS(dh = bigDh);
     204             :             }
     205             : 
     206          10 :             dh = dh2;
     207          15 :             THEN("a shallow copy is performed and associated Maps are updated")
     208             :             {
     209           5 :                 REQUIRE_EQ(useCount(dh), 2);
     210           5 :                 REQUIRE_EQ(dh, dh2);
     211           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     212             :             }
     213             :         }
     214             : 
     215          90 :         WHEN("move assigning")
     216             :         {
     217          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     218          20 :             DataHandlerCPU dh2{randVec};
     219          20 :             const auto dh2View = dh2.getBlock(0, size);
     220          20 :             DataHandlerCPU testDh{randVec};
     221             : 
     222          15 :             THEN("sizes must match")
     223             :             {
     224          10 :                 DataHandlerCPU<data_t> bigDh{2 * size};
     225          10 :                 REQUIRE_THROWS(dh = std::move(bigDh));
     226             :             }
     227             : 
     228          10 :             dh = std::move(dh2);
     229          15 :             THEN("data is moved, associated maps are merged")
     230             :             {
     231           5 :                 REQUIRE_EQ(useCount(dh), 1);
     232           5 :                 REQUIRE_EQ(dh, testDh);
     233           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     234           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     235           5 :                 REQUIRE_EQ(&(*dh2View)[0], &dh[0]);
     236           5 :                 REQUIRE_EQ(dh2View->getSize(), size);
     237             :             }
     238             :         }
     239             : 
     240          90 :         WHEN("copy assigning a DataHandlerCPU through base pointers")
     241             :         {
     242          10 :             DataHandler<data_t>* dhPtr = &dh;
     243             : 
     244          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     245          20 :             const auto dh2Ptr = std::make_unique<const DataHandlerCPU<data_t>>(randVec);
     246          20 :             const auto dh2Map = dh2Ptr->getBlock(size / 2, size / 3);
     247             : 
     248          15 :             THEN("sizes must match")
     249             :             {
     250          10 :                 std::unique_ptr<DataHandler<data_t>> bigDh =
     251           5 :                     std::make_unique<DataHandlerCPU<data_t>>(2 * size);
     252          10 :                 REQUIRE_THROWS(*dhPtr = *bigDh);
     253             :             }
     254             : 
     255          10 :             *dhPtr = *dh2Ptr;
     256          15 :             THEN("a shallow copy is performed and associated Maps are updated")
     257             :             {
     258           5 :                 REQUIRE_EQ(useCount(dh), 2);
     259           5 :                 REQUIRE_EQ(dh, *dh2Ptr);
     260           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     261           5 :                 dh[0] = 1;
     262           5 :                 REQUIRE_NE(&dh[0], &(*dh2Ptr)[0]);
     263           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     264           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     265             :             }
     266             :         }
     267             : 
     268          90 :         WHEN("copy assigning a partial DataHandlerMapCPU through base pointers")
     269             :         {
     270          10 :             DataHandler<data_t>* dhPtr = &dh;
     271          20 :             const auto dhCopy = dh;
     272             : 
     273          20 :             auto randVec = generateRandomMatrix<data_t>(2 * size);
     274          20 :             const DataHandlerCPU<data_t> dh2{randVec};
     275          20 :             const auto dh2Map = dh2.getBlock(0, size);
     276             : 
     277          15 :             THEN("sizes must match")
     278             :             {
     279          10 :                 const auto bigDh = dh2.getBlock(0, size + 1);
     280          10 :                 REQUIRE_THROWS(*dhPtr = *bigDh);
     281             :             }
     282             : 
     283          10 :             *dhPtr = *dh2Map;
     284          15 :             THEN("a deep copy is performed")
     285             :             {
     286           5 :                 REQUIRE_EQ(useCount(dh), 1);
     287           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     288           5 :                 REQUIRE_EQ(dh, *dh2Map);
     289           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     290           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     291             :             }
     292             :         }
     293             : 
     294          90 :         WHEN("copy assigning a full DataHandlerMapCPU (aka a view) through base pointers")
     295             :         {
     296          10 :             DataHandler<data_t>* dhPtr = &dh;
     297             : 
     298          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     299          20 :             const DataHandlerCPU<data_t> dh2{randVec};
     300          20 :             const auto dh2View = dh2.getBlock(0, size);
     301          20 :             const auto dh2Map = dh2.getBlock(size / 2, size / 3);
     302             : 
     303          15 :             THEN("sizes must match")
     304             :             {
     305          10 :                 std::unique_ptr<DataHandler<data_t>> bigDh =
     306           5 :                     std::make_unique<DataHandlerCPU<data_t>>(2 * size);
     307          10 :                 auto bigDhView = bigDh->getBlock(0, 2 * size);
     308          10 :                 REQUIRE_THROWS(*dhPtr = *bigDhView);
     309             :             }
     310             : 
     311          10 :             *dhPtr = *dh2View;
     312          15 :             THEN("a shallow copy is performed and associated maps are updated")
     313             :             {
     314           5 :                 REQUIRE_EQ(useCount(dh), 2);
     315           5 :                 REQUIRE_EQ(dh, *dh2View);
     316           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     317           5 :                 dh[0] = 1;
     318           5 :                 REQUIRE_NE(&dh[0], &(*dh2View)[0]);
     319           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     320           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     321             :             }
     322             :         }
     323             : 
     324          90 :         WHEN("move assigning a DataHandlerCPU through base pointers")
     325             :         {
     326          10 :             DataHandler<data_t>* dhPtr = &dh;
     327             : 
     328          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     329          20 :             std::unique_ptr<DataHandler<data_t>> dh2Ptr =
     330             :                 std::make_unique<DataHandlerCPU<data_t>>(randVec);
     331          20 :             const auto dh2View = dh2Ptr->getBlock(0, size);
     332          20 :             DataHandlerCPU<data_t> testDh{randVec};
     333             : 
     334          15 :             THEN("sizes must match")
     335             :             {
     336          10 :                 std::unique_ptr<DataHandler<data_t>> bigDh =
     337           5 :                     std::make_unique<DataHandlerCPU<data_t>>(2 * size);
     338          10 :                 REQUIRE_THROWS(*dhPtr = std::move(*bigDh));
     339             :             }
     340             : 
     341          10 :             *dhPtr = std::move(*dh2Ptr);
     342          15 :             THEN("data is moved and associated Maps are updated")
     343             :             {
     344           5 :                 REQUIRE_EQ(useCount(dh), 1);
     345           5 :                 REQUIRE_EQ(dh, testDh);
     346           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     347           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     348           5 :                 REQUIRE_EQ(&(*dh2View)[0], &dh[0]);
     349           5 :                 REQUIRE_EQ(dh2View->getSize(), size);
     350             :             }
     351             :         }
     352             : 
     353          90 :         WHEN("\"move\" assigning a partial DataHandlerMapCPU through base pointers")
     354             :         {
     355          10 :             DataHandler<data_t>* dhPtr = &dh;
     356          20 :             const auto dhCopy = dh;
     357             : 
     358          20 :             auto randVec = generateRandomMatrix<data_t>(2 * size);
     359          20 :             DataHandlerCPU<data_t> dh2{randVec};
     360          20 :             const auto dh2Map = dh2.getBlock(0, size);
     361             : 
     362          15 :             THEN("sizes must match")
     363             :             {
     364          15 :                 REQUIRE_THROWS(*dhPtr = std::move(*dh2.getBlock(0, 2 * size)));
     365             :             }
     366             : 
     367          10 :             *dhPtr = std::move(*dh2Map);
     368          15 :             THEN("a deep copy is performed")
     369             :             {
     370           5 :                 REQUIRE_EQ(useCount(dh), 1);
     371           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     372           5 :                 REQUIRE_EQ(dh, *dh2.getBlock(0, size));
     373           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     374           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     375             :             }
     376             :         }
     377             : 
     378          90 :         WHEN("\"move\" assigning a full DataHandlerMapCPU (aka a view) through base pointers")
     379             :         {
     380          10 :             DataHandler<data_t>* dhPtr = &dh;
     381             : 
     382          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     383          20 :             DataHandlerCPU<data_t> dh2{randVec};
     384          20 :             const auto dh2View = dh2.getBlock(0, size);
     385          20 :             const auto dh2Map = dh2.getBlock(size / 2, size / 3);
     386             : 
     387          15 :             THEN("sizes must match")
     388             :             {
     389          10 :                 const std::unique_ptr<const DataHandler<data_t>> bigDh =
     390           5 :                     std::make_unique<const DataHandlerCPU<data_t>>(2 * size);
     391          15 :                 REQUIRE_THROWS(*dhPtr = std::move(*bigDh->getBlock(0, 2 * size)));
     392             :             }
     393             : 
     394          10 :             *dhPtr = std::move(*dh2View);
     395          15 :             THEN("a shallow copy is performed and associated maps are updated")
     396             :             {
     397           5 :                 REQUIRE_EQ(useCount(dh), 2);
     398           5 :                 REQUIRE_EQ(dh, *dh2View);
     399           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     400           5 :                 dh[0] = 1;
     401           5 :                 REQUIRE_NE(&dh[0], &dh2[0]);
     402           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     403           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[size / 2]);
     404             :             }
     405             :         }
     406             :     }
     407          80 : }
     408             : 
     409             : #ifdef ELSA_CUDA_VECTOR
     410             : TEST_CASE_TEMPLATE("DataHandlers: Testing clone()", TestType, DataHandlerCPU<float>,
     411             :                    DataHandlerGPU<float>)
     412             : #else
     413          73 : TEST_CASE_TEMPLATE("DataHandlers: Testing clone()", TestType, DataHandlerCPU<float>)
     414             : #endif
     415             : {
     416           2 :     GIVEN("some DataHandler")
     417             :     {
     418           1 :         index_t size = 728;
     419           2 :         TestType dh(size);
     420           1 :         dh = 1.0f;
     421             : 
     422           2 :         WHEN("cloning")
     423             :         {
     424           2 :             auto dhClone = dh.clone();
     425             : 
     426           2 :             THEN("a shallow copy is produced")
     427             :             {
     428           1 :                 REQUIRE_NE(dhClone.get(), &dh);
     429             : 
     430           1 :                 REQUIRE_EQ(useCount(dh), 2);
     431           1 :                 REQUIRE_EQ(*dhClone, dh);
     432             : 
     433           1 :                 REQUIRE_EQ(dhClone->getSize(), dh.getSize());
     434             : 
     435           1 :                 dh[0] = 2.f;
     436           1 :                 REQUIRE_NE(dh, *dhClone);
     437             :             }
     438             :         }
     439             :     }
     440           1 : }
     441             : 
     442         226 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing the reduction operations", TestType,
     443             :                           datahandler_reduction)
     444             : {
     445             :     using data_t = typename TestType::value_type;
     446             : 
     447          20 :     GIVEN("some DataHandler")
     448             :     {
     449          10 :         index_t size = 16;
     450             : 
     451          20 :         WHEN("putting in some random data")
     452             :         {
     453          20 :             auto randVec = generateRandomMatrix<data_t>(size);
     454          20 :             TestType dh(randVec);
     455             : 
     456          15 :             THEN("the reductions work as expected")
     457             :             {
     458           5 :                 auto eps = std::numeric_limits<GetFloatingPointType_t<data_t>>::epsilon();
     459           5 :                 REQUIRE_UNARY(checkApproxEq(dh.sum(), randVec.sum()));
     460           5 :                 REQUIRE_UNARY(
     461             :                     checkApproxEq(dh.l0PseudoNorm(), (randVec.array().cwiseAbs() >= eps).count()));
     462           5 :                 REQUIRE_UNARY(checkApproxEq(dh.l1Norm(), randVec.array().abs().sum()));
     463           5 :                 REQUIRE_UNARY(checkApproxEq(dh.lInfNorm(), randVec.array().abs().maxCoeff()));
     464           5 :                 REQUIRE_UNARY(checkApproxEq(dh.squaredL2Norm(), randVec.squaredNorm()));
     465           5 :                 REQUIRE_UNARY(checkApproxEq(dh.l2Norm(), randVec.norm()));
     466             : 
     467          10 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     468          10 :                 TestType dh2(randVec2);
     469             : 
     470           5 :                 REQUIRE_UNARY(checkApproxEq(dh.dot(dh2), randVec.dot(randVec2)));
     471             : 
     472           5 :                 auto dhMap = dh2.getBlock(0, dh2.getSize());
     473             : 
     474           5 :                 REQUIRE_UNARY(checkApproxEq(dh.dot(*dhMap), randVec.dot(randVec2)));
     475             :             }
     476             : 
     477          15 :             THEN("the dot product expects correctly sized arguments")
     478             :             {
     479           5 :                 index_t wrongSize = size - 1;
     480             : 
     481          10 :                 auto randVec2 = generateRandomMatrix<data_t>(wrongSize);
     482          10 :                 TestType dh2(randVec2);
     483             : 
     484          10 :                 REQUIRE_THROWS_AS(dh.dot(dh2), InvalidArgumentError);
     485             :             }
     486             :         }
     487             :     }
     488          10 : }
     489             : 
     490         231 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing the element-wise operations", TestType,
     491             :                           datahandler_elementwise)
     492             : {
     493             :     using data_t = typename TestType::value_type;
     494             : 
     495          30 :     GIVEN("some DataHandler")
     496             :     {
     497          15 :         index_t size = 567;
     498             : 
     499          30 :         WHEN("putting in some random data")
     500             :         {
     501          30 :             auto randVec = generateRandomMatrix<data_t>(size);
     502          30 :             TestType dh(randVec);
     503             : 
     504          20 :             THEN("the element-wise binary vector operations work as expected")
     505             :             {
     506          10 :                 TestType oldDh = dh;
     507             : 
     508          10 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     509          10 :                 TestType dh2(randVec2);
     510             : 
     511          10 :                 auto dhMap = dh2.getBlock(0, dh2.getSize());
     512             : 
     513          10 :                 TestType bigDh{size + 1};
     514          10 :                 REQUIRE_THROWS(dh += bigDh);
     515          10 :                 REQUIRE_THROWS(dh -= bigDh);
     516          10 :                 REQUIRE_THROWS(dh *= bigDh);
     517          10 :                 REQUIRE_THROWS(dh /= bigDh);
     518             : 
     519           5 :                 dh += dh2;
     520        2840 :                 for (index_t i = 0; i < size; ++i)
     521        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dh2[i]));
     522             : 
     523           5 :                 dh = oldDh;
     524           5 :                 dh += *dhMap;
     525        2840 :                 for (index_t i = 0; i < size; ++i)
     526        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dh2[i]));
     527             : 
     528           5 :                 dh = oldDh;
     529           5 :                 dh -= dh2;
     530        2840 :                 for (index_t i = 0; i < size; ++i)
     531        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dh2[i]));
     532             : 
     533           5 :                 dh = oldDh;
     534           5 :                 dh -= *dhMap;
     535        2840 :                 for (index_t i = 0; i < size; ++i)
     536        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dh2[i]));
     537             : 
     538           5 :                 dh = oldDh;
     539           5 :                 dh *= dh2;
     540        2840 :                 for (index_t i = 0; i < size; ++i)
     541        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dh2[i]));
     542             : 
     543           5 :                 dh = oldDh;
     544           5 :                 dh *= *dhMap;
     545        2840 :                 for (index_t i = 0; i < size; ++i)
     546        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dh2[i]));
     547             : 
     548           5 :                 dh = oldDh;
     549           5 :                 dh /= dh2;
     550        2840 :                 for (index_t i = 0; i < size; ++i)
     551        2835 :                     if (dh2[i] != data_t(0))
     552             :                         // due to floating point arithmetic less precision
     553        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dh2[i]));
     554             : 
     555           5 :                 dh = oldDh;
     556           5 :                 dh /= *dhMap;
     557        2840 :                 for (index_t i = 0; i < size; ++i)
     558        2835 :                     if (dh2[i] != data_t(0))
     559             :                         // due to floating point arithmetic less precision
     560        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dh2[i]));
     561             :             }
     562             : 
     563          20 :             THEN("the element-wise binary scalar operations work as expected")
     564             :             {
     565          10 :                 TestType oldDh = dh;
     566           5 :                 data_t scalar = std::is_integral_v<data_t> ? 3 : 3.5;
     567             : 
     568           5 :                 dh += scalar;
     569        2840 :                 for (index_t i = 0; i < size; ++i)
     570        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + scalar));
     571             : 
     572           5 :                 dh = oldDh;
     573           5 :                 dh -= scalar;
     574        2840 :                 for (index_t i = 0; i < size; ++i)
     575        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - scalar));
     576             : 
     577           5 :                 dh = oldDh;
     578           5 :                 dh *= scalar;
     579        2840 :                 for (index_t i = 0; i < size; ++i)
     580        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * scalar));
     581             : 
     582           5 :                 dh = oldDh;
     583           5 :                 dh /= scalar;
     584        2840 :                 for (index_t i = 0; i < size; ++i)
     585        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / scalar));
     586             :             }
     587             : 
     588          20 :             THEN("the element-wise assignment of a scalar works as expected")
     589             :             {
     590           5 :                 auto scalar = std::is_integral_v<data_t> ? data_t(47) : data_t(47.11f);
     591             : 
     592           5 :                 dh = scalar;
     593        2840 :                 for (index_t i = 0; i < size; ++i)
     594        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], scalar));
     595             :             }
     596             :         }
     597             :     }
     598          15 : }
     599             : 
     600         226 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing referencing blocks", TestType,
     601             :                           datahandler_blockreferencing)
     602             : {
     603             :     using data_t = typename TestType::value_type;
     604             : 
     605          20 :     GIVEN("some DataHandler")
     606             :     {
     607          10 :         index_t size = 728;
     608          20 :         Eigen::Matrix<data_t, Eigen::Dynamic, 1> dataVec(size);
     609          20 :         TestType dh(dataVec);
     610             : 
     611          15 :         WHEN("getting the reference to a block")
     612             :         {
     613          10 :             REQUIRE_THROWS(dh.getBlock(size, 1));
     614          10 :             REQUIRE_THROWS(dh.getBlock(0, size + 1));
     615             : 
     616          10 :             auto dhBlock = dh.getBlock(size / 3, size / 2);
     617             : 
     618          10 :             THEN("returned data handler references the correct elements")
     619             :             {
     620           5 :                 REQUIRE_EQ(dhBlock->getSize(), size / 2);
     621             : 
     622        1825 :                 for (index_t i = 0; i < size / 2; i++)
     623        1820 :                     REQUIRE_UNARY(checkApproxEq(&(*dhBlock)[i], &dh[i + size / 3]));
     624             :             }
     625             :         }
     626             : 
     627          15 :         WHEN("the whole volume is referenced")
     628             :         {
     629          10 :             auto dhBlock = dh.getBlock(0, size);
     630             : 
     631          10 :             THEN("the referenced volume and the actual volume are equal")
     632             :             {
     633             : 
     634           5 :                 REQUIRE_EQ(dh, *dhBlock);
     635             :             }
     636             :         }
     637             :     }
     638          10 : }
     639             : 
     640         271 : TEST_CASE_TEMPLATE_DEFINE("DataHandlers: Testing the copy-on-write mechanism", TestType,
     641             :                           datahandler_copyonwrite)
     642             : {
     643             :     using data_t = typename TestType::value_type;
     644             : 
     645          55 :     const index_t size = 42;
     646             : 
     647         110 :     GIVEN("A random DataContainer")
     648             :     {
     649         110 :         auto randVec = generateRandomMatrix<data_t>(size);
     650         110 :         TestType dh{randVec};
     651             : 
     652          60 :         WHEN("const manipulating a copy constructed shallow copy")
     653             :         {
     654          10 :             TestType dh2 = dh;
     655             : 
     656          10 :             THEN("the data is the same")
     657             :             {
     658           5 :                 REQUIRE_EQ(dh, dh2);
     659           5 :                 REQUIRE_EQ(useCount(dh), 2);
     660             :             }
     661             :         }
     662             : 
     663         100 :         WHEN("non-const manipulating a copy constructed shallow copy")
     664             :         {
     665          90 :             TestType dh2 = dh;
     666          45 :             REQUIRE_EQ(useCount(dh), 2);
     667          45 :             REQUIRE_EQ(useCount(dh2), 2);
     668             : 
     669          50 :             THEN("copy-on-write is invoked")
     670             :             {
     671           5 :                 dh2 += 2;
     672           5 :                 REQUIRE_NE(dh2, dh);
     673           5 :                 REQUIRE_EQ(useCount(dh2), 1);
     674           5 :                 REQUIRE_EQ(useCount(dh), 1);
     675             :             }
     676             : 
     677          50 :             THEN("copy-on-write is invoked")
     678             :             {
     679           5 :                 dh2 += dh;
     680           5 :                 REQUIRE_NE(dh2, dh);
     681           5 :                 REQUIRE_EQ(useCount(dh2), 1);
     682           5 :                 REQUIRE_EQ(useCount(dh), 1);
     683             :             }
     684             : 
     685          50 :             THEN("copy-on-write is invoked")
     686             :             {
     687           5 :                 dh2 -= 2;
     688           5 :                 REQUIRE_NE(dh2, dh);
     689             :             }
     690             : 
     691          50 :             THEN("copy-on-write is invoked")
     692             :             {
     693           5 :                 dh2 -= dh;
     694           5 :                 REQUIRE_NE(dh2, dh);
     695             :             }
     696             : 
     697          50 :             THEN("copy-on-write is invoked")
     698             :             {
     699           5 :                 dh2 /= 2;
     700           5 :                 REQUIRE_NE(dh2, dh);
     701             :             }
     702             : 
     703          50 :             THEN("copy-on-write is invoked")
     704             :             {
     705           5 :                 dh2 /= dh;
     706           5 :                 REQUIRE_NE(dh2, dh);
     707             :             }
     708             : 
     709          50 :             THEN("copy-on-write is invoked")
     710             :             {
     711           5 :                 dh2 *= 2;
     712           5 :                 REQUIRE_NE(dh2, dh);
     713             :             }
     714             : 
     715          50 :             THEN("copy-on-write is invoked")
     716             :             {
     717           5 :                 dh2 *= dh;
     718           5 :                 REQUIRE_NE(dh2, dh);
     719             :             }
     720             : 
     721          50 :             THEN("copy-on-write is invoked")
     722             :             {
     723           5 :                 dh[0] += 2;
     724           5 :                 REQUIRE_NE(dh2, dh);
     725             :             }
     726             :         }
     727             : 
     728          60 :         WHEN("manipulating a non-shallow-copied container")
     729             :         {
     730         215 :             for (index_t i = 0; i < dh.getSize(); ++i) {
     731         210 :                 dh[i] += 2;
     732             :             }
     733             : 
     734           5 :             THEN("copy-on-write should not be invoked") { REQUIRE_EQ(useCount(dh), 1); }
     735             :         }
     736             :     }
     737          55 : }
     738             : 
     739             : // "instantiate" the test templates for cpu types
     740             : TEST_CASE_TEMPLATE_APPLY(datahandler_construction, CPUTypeTuple);
     741             : TEST_CASE_TEMPLATE_APPLY(datahandler_equality, CPUTypeTuple);
     742             : TEST_CASE_TEMPLATE_APPLY(datahandler_assigncpu, CPUTypeTuple);
     743             : TEST_CASE_TEMPLATE_APPLY(datahandler_reduction, CPUTypeTuple);
     744             : TEST_CASE_TEMPLATE_APPLY(datahandler_elementwise, CPUTypeTuple);
     745             : TEST_CASE_TEMPLATE_APPLY(datahandler_blockreferencing, CPUTypeTuple);
     746             : TEST_CASE_TEMPLATE_APPLY(datahandler_copyonwrite, CPUTypeTuple);
     747             : 
     748             : #ifdef ELSA_CUDA_VECTOR
     749             : // "instantiate" the test templates for GPU types
     750             : TEST_CASE_TEMPLATE_APPLY(datahandler_construction, CPUTypeTuple);
     751             : TEST_CASE_TEMPLATE_APPLY(datahandler_equality, CPUTypeTuple);
     752             : TEST_CASE_TEMPLATE_APPLY(datahandler_assigncpu, CPUTypeTuple);
     753             : TEST_CASE_TEMPLATE_APPLY(datahandler_reduction, CPUTypeTuple);
     754             : TEST_CASE_TEMPLATE_APPLY(datahandler_elementwise, CPUTypeTuple);
     755             : TEST_CASE_TEMPLATE_APPLY(datahandler_blockreferencing, CPUTypeTuple);
     756             : TEST_CASE_TEMPLATE_APPLY(datahandler_copyonwrite, CPUTypeTuple);
     757             : #endif
     758             : 
     759             : TEST_SUITE_END();

Generated by: LCOV version 1.15