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

          Line data    Source code
       1             : /**
       2             :  * @file test_DataHandlerMap.cpp
       3             :  *
       4             :  * @brief Tests for DataHandlerMaps - DataHandlerMapCPU and DataHandlerMapGPU
       5             :  *
       6             :  * @author David Frank - initial code
       7             :  * @author Tobias Lasser - rewrite and code coverage
       8             :  * @author Jens Petit - refactoring into TEMPLATE_PRODUCT_TEST_CASE
       9             :  */
      10             : 
      11             : #include "doctest/doctest.h"
      12             : #include "DataHandlerMapCPU.h"
      13             : #include "DataHandlerCPU.h"
      14             : #include "testHelpers.h"
      15             : 
      16             : #ifdef ELSA_CUDA_VECTOR
      17             : #include "DataHandlerGPU.h"
      18             : #include "DataHandlerMapGPU.h"
      19             : #endif
      20             : 
      21             : using namespace elsa;
      22             : using namespace elsa;
      23             : 
      24             : // for testing the copy-on-write mechanism
      25             : template <typename data_t>
      26         125 : long elsa::useCount(const DataHandlerCPU<data_t>& dh)
      27             : {
      28         125 :     return dh._data.use_count();
      29             : }
      30             : 
      31             : #ifdef ELSA_CUDA_VECTOR
      32             : // for testing the copy-on-write mechanism
      33             : template <typename data_t>
      34             : long elsa::useCount(const DataHandlerGPU<data_t>& dh)
      35             : {
      36             :     return dh._data.use_count();
      37             : }
      38             : #endif
      39             : 
      40             : // Helper to provide the correct map based on the handler type
      41             : template <typename Handler>
      42             : struct MapToHandler {
      43             :     using map =
      44             :         std::conditional_t<std::is_same_v<DataHandlerCPU<typename Handler::value_type>, Handler>,
      45             :                            DataHandlerMapCPU<typename Handler::value_type>,
      46             : #ifdef ELSA_CUDA_VECTOR
      47             :                            DataHandlerMapGPU<typename Handler::value_type>>;
      48             : #else
      49             :                            DataHandlerMapCPU<typename Handler::value_type>>;
      50             : #endif
      51             : };
      52             : 
      53             : using CPUTypeTuple =
      54             :     std::tuple<DataHandlerCPU<float>, DataHandlerCPU<double>, DataHandlerCPU<complex<float>>,
      55             :                DataHandlerCPU<complex<double>>, DataHandlerCPU<index_t>>;
      56             : 
      57         245 : TYPE_TO_STRING(DataHandlerCPU<float>);
      58         245 : TYPE_TO_STRING(DataHandlerCPU<double>);
      59         245 : TYPE_TO_STRING(DataHandlerCPU<index_t>);
      60         245 : TYPE_TO_STRING(DataHandlerCPU<complex<float>>);
      61         245 : TYPE_TO_STRING(DataHandlerCPU<complex<double>>);
      62             : 
      63             : #ifdef ELSA_CUDA_VECTOR
      64             : using GPUTypeTuple =
      65             :     std::tuple<DataHandlerGPU<float>, DataHandlerGPU<double>, DataHandlerGPU<complex<float>>,
      66             :                DataHandlerGPU<complex<double>>, DataHandlerGPU<index_t>>;
      67             : 
      68             : TYPE_TO_STRING(DataHandlerGPU<float>);
      69             : TYPE_TO_STRING(DataHandlerGPU<double>);
      70             : TYPE_TO_STRING(DataHandlerGPU<index_t>);
      71             : TYPE_TO_STRING(DataHandlerGPU<complex<float>>);
      72             : TYPE_TO_STRING(DataHandlerGPU<complex<double>>);
      73             : #endif
      74             : 
      75             : TEST_SUITE_BEGIN("core");
      76             : 
      77         220 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing construction", TestType,
      78             :                           datahandlermap_construction)
      79             : {
      80             :     using data_t = typename TestType::value_type;
      81             : 
      82          20 :     GIVEN("a certain size")
      83             :     {
      84          10 :         index_t size = 314;
      85             : 
      86          15 :         WHEN("constructing with a given vector")
      87             :         {
      88          10 :             Vector_t<data_t> randVec{size * 2};
      89           5 :             randVec.setRandom();
      90          10 :             const TestType dh{randVec};
      91          10 :             const auto dhMap = dh.getBlock(size / 3, size / 3);
      92             : 
      93          10 :             THEN("the DataHandlerMap references the actual vector")
      94             :             {
      95           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
      96             : 
      97         525 :                 for (index_t i = 0; i < size / 3; ++i)
      98         520 :                     REQUIRE_EQ(&(*dhMap)[i], &dh[i + size / 3]);
      99             :             }
     100             :         }
     101             : 
     102          15 :         WHEN("copy constructing")
     103             :         {
     104          10 :             Vector_t<data_t> randVec{size * 2};
     105           5 :             randVec.setRandom();
     106          10 :             const TestType dh{randVec};
     107          10 :             const auto dhMap = dh.getBlock(size / 3, size / 3);
     108             : 
     109           5 :             const auto& dhMapRef = static_cast<const typename MapToHandler<TestType>::map&>(*dhMap);
     110             : 
     111          10 :             const auto dhMapCopy = dhMapRef;
     112             : 
     113          10 :             THEN("the copy references the actual vector")
     114             :             {
     115           5 :                 REQUIRE_EQ(dhMap->getSize(), size / 3);
     116             : 
     117         525 :                 for (index_t i = 0; i < size / 3; ++i)
     118         520 :                     REQUIRE_EQ(&dhMapCopy[i], &dh[i + size / 3]);
     119             :             }
     120             :         }
     121             :     }
     122          10 : }
     123             : 
     124         230 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing equality operator", TestType,
     125             :                           datahandlermap_eqoperator)
     126             : {
     127             :     using data_t = typename TestType::value_type;
     128             : 
     129          40 :     GIVEN("some DataHandlerMap")
     130             :     {
     131          20 :         index_t size = 314;
     132          40 :         Vector_t<data_t> randVec{size};
     133          20 :         randVec.setRandom();
     134             : 
     135          40 :         const TestType realDh{randVec};
     136          40 :         const auto dhPtr = realDh.getBlock(0, size);
     137          20 :         const auto& dh = *dhPtr;
     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_FALSE(dh == dh2);
     145           5 :                 REQUIRE_FALSE(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 = realDh;
     152          10 :             THEN("the result is true")
     153             :             {
     154           5 :                 REQUIRE_EQ(dh, dh2);
     155           5 :                 REQUIRE_EQ(dh, *realDh.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_FALSE(dh == dh2);
     176           5 :                 REQUIRE_FALSE(dh == *dh2.getBlock(0, size));
     177             :             }
     178             :         }
     179             :     }
     180          20 : }
     181             : 
     182         350 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing assignment to DataHandlerMap", TestType,
     183             :                           datahandlermap_assign)
     184             : {
     185             :     using data_t = typename TestType::value_type;
     186             :     using MapType = typename MapToHandler<TestType>::map;
     187             : 
     188         140 :     const index_t size = 314;
     189             : 
     190             :     // Constructo DataHandler with 2x the size
     191         280 :     TestType dh{2 * size};
     192         140 :     dh = 0;
     193             : 
     194             :     // Create map to the first half of the DH
     195         280 :     const auto dhMap = dh.getBlock(0, size);
     196             : 
     197         140 :     REQUIRE_EQ(dhMap->getSize(), size);
     198         140 :     REQUIRE_EQ(dhMap->getSize(), dh.getSize() / 2);
     199             : 
     200         150 :     GIVEN("A reference to the concrete DataHandlerMap (TestType)")
     201             :     {
     202          10 :         auto& dhMapRef = static_cast<typename MapToHandler<TestType>::map&>(*dhMap);
     203             : 
     204          15 :         WHEN("Copy-assigning a DataHandler with the same size to the map")
     205             :         {
     206          10 :             Vector_t<data_t> randVec{size};
     207           5 :             randVec.setRandom();
     208          10 :             const TestType dh2{randVec};
     209          10 :             const auto dh2Map = dh2.getBlock(0, size);
     210           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     211             : 
     212           5 :             dhMapRef = dh2MapRef;
     213             : 
     214          10 :             THEN("a deep copy is performed")
     215             :             {
     216           5 :                 REQUIRE_EQ(useCount(dh), 1);
     217           5 :                 REQUIRE_EQ(useCount(dh2), 1);
     218             : 
     219           5 :                 REQUIRE_EQ(dhMapRef, dh2);
     220           5 :                 REQUIRE_UNARY(isCwiseApprox(dhMapRef, dh2MapRef));
     221             : 
     222           5 :                 REQUIRE_EQ(&dh[0], &dhMapRef[0]);
     223           5 :                 REQUIRE_NE(&dh[0], &dh2MapRef[0]);
     224             : 
     225             :                 // Changing the original DataHandler, doesn't change the new one
     226           5 :                 dh[0] *= 4;
     227             : 
     228          10 :                 THEN("Changing the original DataHandler doesn't affect the new one")
     229             :                 {
     230           5 :                     REQUIRE_UNARY(checkApproxEq(dh[0], dhMapRef[0]));
     231           5 :                     REQUIRE_UNARY(checkApproxNe(dh[0], dh2[0]));
     232           5 :                     REQUIRE_UNARY(checkApproxNe(dh[0], dh2MapRef[0]));
     233             :                 }
     234             :             }
     235             :         }
     236             : 
     237          15 :         WHEN("Copy-assigning a DataHandler with a different size to the map")
     238             :         {
     239          10 :             const TestType dh2{3 * size};
     240          10 :             const auto dh2Map = dh2.getBlock(0, 3 * size);
     241             :             const auto& dh2MapRef =
     242           5 :                 static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
     243             : 
     244          15 :             THEN("the assignment throws") { REQUIRE_THROWS(dhMapRef = dh2MapRef); }
     245             :         }
     246             :     }
     247             : 
     248         200 :     GIVEN("Given the base pointer to the map")
     249             :     {
     250         120 :         Vector_t<data_t> randVec{size};
     251          60 :         randVec.setRandom();
     252         120 :         const std::unique_ptr<const DataHandler<data_t>> dh2Ptr =
     253             :             std::make_unique<const TestType>(randVec);
     254             : 
     255          65 :         WHEN("Copy-assigning a DataHandler base pointer of the same size")
     256             :         {
     257             :             // TODO: why do we need dhCopy?
     258          10 :             const auto dhCopy = dh;
     259           5 :             *dhMap = *dh2Ptr;
     260          10 :             THEN("a deep copy is performed")
     261             :             {
     262           5 :                 REQUIRE_EQ(useCount(dh), 1);
     263           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     264             : 
     265        1575 :                 for (index_t i = 0; i < size; i++)
     266        1570 :                     REQUIRE_EQ(dh[i], (*dh2Ptr)[i]);
     267             : 
     268           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     269           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     270             : 
     271             :                 // Changing the original DataHandler, doesn't change the new one
     272           5 :                 dh[0] *= 2;
     273             : 
     274          10 :                 THEN("Changing the original DataHandler doesn't affect the new one")
     275             :                 {
     276           5 :                     REQUIRE_UNARY(checkApproxEq((*dhMap)[0], dh[0]));
     277           5 :                     REQUIRE_UNARY(checkApproxNe((*dhMap)[0], (*dh2Ptr)[0]));
     278             :                 }
     279             :             }
     280             :         }
     281             : 
     282          65 :         WHEN("Copy-assigning a DataHandler base pointer of a different size")
     283             :         {
     284          10 :             const std::unique_ptr<DataHandler<data_t>> bigDh = std::make_unique<TestType>(2 * size);
     285          15 :             THEN("The assigning throws") { REQUIRE_THROWS(*dhMap = *bigDh); }
     286             :         }
     287             : 
     288          70 :         WHEN("Copy-assigning a block of a DataHandlerMap though the base pointer")
     289             :         {
     290          20 :             const auto dhCopy = dh;
     291          20 :             Vector_t<data_t> randVec{2 * size};
     292          10 :             randVec.setRandom();
     293             : 
     294          20 :             const TestType dh2{randVec};
     295          20 :             const auto dh2Map = dh2.getBlock(0, size);
     296             : 
     297          15 :             WHEN("The sizes of the block and DataHandler are the same")
     298             :             {
     299           5 :                 *dhMap = *dh2Map;
     300          10 :                 THEN("a deep copy is performed")
     301             :                 {
     302           5 :                     REQUIRE_EQ(useCount(dh), 1);
     303           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     304             : 
     305        1575 :                     for (index_t i = 0; i < size; i++)
     306        1570 :                         REQUIRE_EQ(dh[i], dh2[i]);
     307             : 
     308           5 :                     REQUIRE_EQ(*dhMap, *dh2Map);
     309           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     310             :                 }
     311             :             }
     312             : 
     313          15 :             WHEN("The sizes of the block and DataHandler are different")
     314             :             {
     315          10 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     316          15 :                 THEN("Assignment throws") { REQUIRE_THROWS(*dhMap = *bigDh); }
     317             :             }
     318             :         }
     319             : 
     320          70 :         WHEN("Copy-assigning a full DataHandlerMap (aka a view) through the base pointers")
     321             :         {
     322          20 :             const auto dhCopy = dh;
     323          20 :             Vector_t<data_t> randVec{size};
     324          10 :             randVec.setRandom();
     325             : 
     326          20 :             const TestType dh2{randVec};
     327          20 :             const auto dh2Map = dh2.getBlock(0, size);
     328             : 
     329          15 :             WHEN("The sizes are the same")
     330             :             {
     331           5 :                 *dhMap = *dh2Map;
     332          10 :                 THEN("a deep copy is performed")
     333             :                 {
     334           5 :                     REQUIRE_EQ(useCount(dh), 1);
     335           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     336             : 
     337        1575 :                     for (index_t i = 0; i < size; i++)
     338        1570 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     339             : 
     340           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     341             :                 }
     342             :             }
     343             : 
     344          15 :             WHEN("The sizes are different")
     345             :             {
     346          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     347           5 :                     std::make_unique<TestType>(2 * size);
     348          20 :                 THEN("sizes must match") { REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size)); }
     349             :             }
     350             :         }
     351             : 
     352          70 :         WHEN("\"move\" assigning a DataHandlerMap through the base pointer")
     353             :         {
     354          20 :             Vector_t<data_t> randVec{size};
     355          10 :             randVec.setRandom();
     356          20 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     357             : 
     358          15 :             WHEN("The sizes are the same")
     359             :             {
     360          10 :                 const auto dhCopy = dh;
     361             : 
     362           5 :                 *dhMap = std::move(*dh2Ptr);
     363          10 :                 THEN("a deep copy is performed")
     364             :                 {
     365           5 :                     REQUIRE_EQ(useCount(dh), 1);
     366           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     367             : 
     368        1575 :                     for (index_t i = 0; i < size; i++)
     369        1570 :                         REQUIRE_UNARY(checkApproxEq(dh[i], (*dh2Ptr)[i]));
     370             : 
     371           5 :                     REQUIRE_EQ(*dhMap, *dh2Ptr);
     372           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     373             :                 }
     374             :             }
     375             : 
     376          15 :             WHEN("The sizes are different")
     377             :             {
     378          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     379           5 :                     std::make_unique<TestType>(2 * size);
     380          15 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     381             :             }
     382             :         }
     383             : 
     384          70 :         WHEN("\"move\" assigning a block of a  DataHandlerMap through the base pointer")
     385             :         {
     386          20 :             const auto dhCopy = dh;
     387          20 :             Vector_t<data_t> randVec{2 * size};
     388          10 :             randVec.setRandom();
     389          20 :             TestType dh2{randVec};
     390          20 :             const auto dh2Map = dh2.getBlock(0, size);
     391             : 
     392          15 :             WHEN("The sizes are the same")
     393             :             {
     394           5 :                 *dhMap = std::move(*dh2Map);
     395          10 :                 THEN("a deep copy is performed")
     396             :                 {
     397           5 :                     REQUIRE_EQ(useCount(dh), 1);
     398           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     399             : 
     400        1575 :                     for (index_t i = 0; i < size; i++)
     401        1570 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     402             : 
     403           5 :                     REQUIRE_EQ(*dhMap, *dh2Map);
     404           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     405             :                 }
     406             :             }
     407             : 
     408          15 :             WHEN("The sizes are different")
     409             :             {
     410          10 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     411          15 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     412             :             }
     413             :         }
     414             : 
     415          70 :         WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through the base pointer")
     416             :         {
     417          20 :             const auto dhCopy = dh;
     418          20 :             Vector_t<data_t> randVec{size};
     419          10 :             randVec.setRandom();
     420          20 :             TestType dh2{randVec};
     421          20 :             const auto dh2Map = dh2.getBlock(0, size);
     422             : 
     423          15 :             WHEN("The sizes are the same")
     424             :             {
     425           5 :                 *dhMap = std::move(*dh2Map);
     426          10 :                 THEN("a deep copy is performed")
     427             :                 {
     428           5 :                     REQUIRE_EQ(useCount(dh), 1);
     429           5 :                     REQUIRE_EQ(useCount(dhCopy), 1);
     430             : 
     431        1575 :                     for (index_t i = 0; i < size; i++)
     432        1570 :                         REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     433             : 
     434           5 :                     REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     435             :                 }
     436             :             }
     437             : 
     438          15 :             WHEN("The sizes are different")
     439             :             {
     440          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     441           5 :                     std::make_unique<TestType>(2 * size);
     442          15 :                 THEN("the assignment throws") { REQUIRE_THROWS(*dhMap = std::move(*bigDh)); }
     443             :             }
     444             :         }
     445             :     }
     446             : 
     447         150 :     GIVEN("A reference to a full concrete DataHandlerMap (aka a view)")
     448             :     {
     449          10 :         index_t size = 314;
     450          20 :         TestType dh{size};
     451          20 :         const auto dhMap = dh.getBlock(0, size);
     452          10 :         auto& dhMapRef = static_cast<MapType&>(*dhMap);
     453             : 
     454          15 :         WHEN("Copy-assigning an equally sized view to the map")
     455             :         {
     456          10 :             const TestType dh2{size};
     457          10 :             const auto dh2Map = dh2.getBlock(0, size);
     458           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     459           5 :             dhMapRef = dh2MapRef;
     460             : 
     461          10 :             THEN("a shallow copy is performed")
     462             :             {
     463           5 :                 REQUIRE_EQ(useCount(dh), 2);
     464           5 :                 REQUIRE_EQ(dh, dh2);
     465           5 :                 REQUIRE_EQ(dh, dhMapRef);
     466           5 :                 REQUIRE_EQ(dh, dh2MapRef);
     467           5 :                 dhMapRef[0] = 1;
     468           5 :                 REQUIRE_EQ(&dhMapRef[0], &dh[0]);
     469           5 :                 REQUIRE_NE(&dhMapRef[0], &dh2MapRef[0]);
     470             :             }
     471             :         }
     472          15 :         WHEN("Copy-assigning an differently sized view to the map")
     473             :         {
     474          10 :             const TestType dh2{3 * size};
     475          10 :             const auto dh2Map = dh2.getBlock(0, 3 * size);
     476           5 :             const auto& dh2MapRef = static_cast<const MapType&>(*dh2Map);
     477             : 
     478          15 :             THEN("The assigning throws") { REQUIRE_THROWS(dhMapRef = dh2MapRef); }
     479             :         }
     480             :     }
     481             : 
     482         200 :     GIVEN("a full DataHandlerMap (aka a view)")
     483             :     {
     484          60 :         index_t size = 314;
     485         120 :         TestType dh{size};
     486         120 :         const auto dhMap = dh.getBlock(0, size);
     487             : 
     488          70 :         WHEN("copy assigning a DataHandlerMap through base pointers")
     489             :         {
     490          20 :             Vector_t<data_t> randVec{size};
     491          10 :             randVec.setRandom();
     492          20 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     493             : 
     494          15 :             THEN("sizes must match")
     495             :             {
     496          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     497           5 :                     std::make_unique<TestType>(2 * size);
     498          10 :                 REQUIRE_THROWS(*dhMap = *bigDh);
     499             :             }
     500             : 
     501          10 :             *dhMap = *dh2Ptr;
     502          15 :             THEN("a shallow copy is performed")
     503             :             {
     504           5 :                 REQUIRE_EQ(useCount(dh), 2);
     505           5 :                 REQUIRE_EQ(dh, *dh2Ptr);
     506           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     507           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     508           5 :                 dh[0] = 1;
     509           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     510           5 :                 REQUIRE_NE(&dh[0], &(*dh2Ptr)[0]);
     511             :             }
     512             :         }
     513             : 
     514          70 :         WHEN("copy assigning a partial DataHandlerMap through base pointers")
     515             :         {
     516          20 :             const auto dhCopy = dh;
     517          20 :             Vector_t<data_t> randVec{2 * size};
     518          10 :             randVec.setRandom();
     519          20 :             const TestType dh2{randVec};
     520          20 :             const auto dh2Map = dh2.getBlock(0, size);
     521             : 
     522          15 :             THEN("sizes must match")
     523             :             {
     524          10 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     525          10 :                 REQUIRE_THROWS(*dhMap = *bigDh);
     526             :             }
     527             : 
     528          10 :             *dhMap = *dh2Map;
     529          15 :             THEN("a deep copy is performed")
     530             :             {
     531           5 :                 REQUIRE_EQ(useCount(dh), 1);
     532           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     533             : 
     534        1575 :                 for (index_t i = 0; i < size; i++)
     535        1570 :                     REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     536             : 
     537           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     538           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     539             :             }
     540             :         }
     541             : 
     542          70 :         WHEN("copy assigning a full DataHandlerMap (aka a view) through base pointers")
     543             :         {
     544          20 :             Vector_t<data_t> randVec{size};
     545          10 :             randVec.setRandom();
     546          20 :             const TestType dh2{randVec};
     547          20 :             const auto dh2Map = dh2.getBlock(0, size);
     548             : 
     549          15 :             THEN("sizes must match")
     550             :             {
     551          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     552           5 :                     std::make_unique<TestType>(2 * size);
     553          15 :                 REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size));
     554             :             }
     555             : 
     556          10 :             *dhMap = *dh2Map;
     557          15 :             THEN("a shallow copy is performed")
     558             :             {
     559           5 :                 REQUIRE_EQ(useCount(dh), 2);
     560           5 :                 REQUIRE_EQ(dh, dh2);
     561           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     562           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     563           5 :                 dh[0] = 1;
     564           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     565           5 :                 REQUIRE_NE(&dh[0], &dh2[0]);
     566             :             }
     567             :         }
     568             : 
     569          70 :         WHEN("\"move\" assigning a DataHandler through base pointers")
     570             :         {
     571          20 :             Vector_t<data_t> randVec{size};
     572          10 :             randVec.setRandom();
     573          20 :             const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
     574             : 
     575          15 :             THEN("sizes must match")
     576             :             {
     577          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     578           5 :                     std::make_unique<TestType>(2 * size);
     579          10 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh));
     580             :             }
     581             : 
     582          10 :             *dhMap = std::move(*dh2Ptr);
     583          15 :             THEN("a shallow copy is performed")
     584             :             {
     585           5 :                 REQUIRE_EQ(useCount(dh), 2);
     586           5 :                 REQUIRE_EQ(dh, *dh2Ptr);
     587           5 :                 REQUIRE_EQ(*dhMap, *dh2Ptr);
     588           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     589           5 :                 dh[0] = 1;
     590           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     591           5 :                 REQUIRE_NE(&dh[0], &(*dh2Ptr)[0]);
     592             :             }
     593             :         }
     594             : 
     595          70 :         WHEN("\"move\" assigning a partial DataHandlerMap through base pointers")
     596             :         {
     597          20 :             const auto dhCopy = dh;
     598          20 :             Vector_t<data_t> randVec{2 * size};
     599          10 :             randVec.setRandom();
     600          20 :             TestType dh2{randVec};
     601          20 :             const auto dh2Map = dh2.getBlock(0, size);
     602             : 
     603          15 :             THEN("sizes must match")
     604             :             {
     605          10 :                 const auto bigDh = dh2.getBlock(0, 2 * size);
     606          10 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh));
     607             :             }
     608             : 
     609          10 :             *dhMap = std::move(*dh2Map);
     610          15 :             THEN("a deep copy is performed")
     611             :             {
     612           5 :                 REQUIRE_EQ(useCount(dh), 1);
     613           5 :                 REQUIRE_EQ(useCount(dhCopy), 1);
     614             : 
     615        1575 :                 for (index_t i = 0; i < size; i++)
     616        1570 :                     REQUIRE_UNARY(checkApproxEq(dh[i], dh2[i]));
     617             : 
     618           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     619           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     620             :             }
     621             :         }
     622             : 
     623          70 :         WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through base pointers")
     624             :         {
     625          20 :             Vector_t<data_t> randVec{size};
     626          10 :             randVec.setRandom();
     627          20 :             TestType dh2{randVec};
     628          20 :             const auto dh2Map = dh2.getBlock(0, size);
     629             : 
     630          15 :             THEN("sizes must match")
     631             :             {
     632          10 :                 const std::unique_ptr<DataHandler<data_t>> bigDh =
     633           5 :                     std::make_unique<TestType>(2 * size);
     634          15 :                 REQUIRE_THROWS(*dhMap = std::move(*bigDh->getBlock(0, 2 * size)));
     635             :             }
     636             : 
     637          10 :             *dhMap = std::move(*dh2Map);
     638          15 :             THEN("a shallow copy is performed")
     639             :             {
     640           5 :                 REQUIRE_EQ(useCount(dh), 2);
     641           5 :                 REQUIRE_EQ(dh, dh2);
     642           5 :                 REQUIRE_EQ(*dhMap, *dh2Map);
     643           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     644           5 :                 dh[0] = 1;
     645           5 :                 REQUIRE_EQ(&(*dhMap)[0], &dh[0]);
     646           5 :                 REQUIRE_NE(&dh[0], &dh2[0]);
     647             :             }
     648             :         }
     649             :     }
     650         140 : }
     651             : 
     652         220 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing clone()", TestType, datahandlermap_clone)
     653             : {
     654             :     using data_t = typename TestType::value_type;
     655             : 
     656          15 :     GIVEN("a full DataHandlerMap (aka a view)")
     657             :     {
     658           5 :         index_t size = 728;
     659          10 :         Vector_t<data_t> dataVec(size);
     660           5 :         dataVec.setRandom();
     661          10 :         TestType realDh(dataVec);
     662          10 :         auto dhPtr = realDh.getBlock(0, size);
     663           5 :         auto& dh = *dhPtr;
     664             : 
     665          10 :         WHEN("cloning")
     666             :         {
     667          10 :             auto dhClone = dh.clone();
     668             : 
     669          10 :             THEN("a shallow copy is produced")
     670             :             {
     671           5 :                 REQUIRE_NE(dhClone.get(), &dh);
     672             : 
     673           5 :                 REQUIRE_EQ(dhClone->getSize(), dh.getSize());
     674             : 
     675           5 :                 REQUIRE_EQ(useCount(realDh), 2);
     676             : 
     677           5 :                 REQUIRE_EQ(*dhClone, dh);
     678             : 
     679           5 :                 dh[0] = 1;
     680           5 :                 REQUIRE_NE(*dhClone, dh);
     681             :             }
     682             :         }
     683             :     }
     684             : 
     685          15 :     GIVEN("a partial DataHandlerMap")
     686             :     {
     687           5 :         index_t size = 728;
     688          10 :         Vector_t<data_t> dataVec(size);
     689           5 :         dataVec.setRandom();
     690          10 :         TestType realDh(dataVec);
     691          10 :         auto dhPtr = realDh.getBlock(0, size / 2);
     692           5 :         auto& dh = *dhPtr;
     693             : 
     694          10 :         WHEN("a deep copy is produced")
     695             :         {
     696          10 :             auto dhClone = dh.clone();
     697             : 
     698          10 :             THEN("everything matches")
     699             :             {
     700           5 :                 REQUIRE_NE(dhClone.get(), &dh);
     701             : 
     702           5 :                 REQUIRE_EQ(dhClone->getSize(), dh.getSize());
     703             : 
     704           5 :                 REQUIRE_EQ(useCount(realDh), 1);
     705             : 
     706           5 :                 REQUIRE_EQ(dh, *dhClone);
     707             :             }
     708             :         }
     709             :     }
     710          10 : }
     711             : 
     712         220 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing the reduction operations", TestType,
     713             :                           datahandlermap_reduction)
     714             : {
     715             :     using data_t = typename TestType::value_type;
     716             : 
     717          20 :     GIVEN("some DataHandlerMap")
     718             :     {
     719          10 :         index_t size = 284;
     720             : 
     721          20 :         WHEN("putting in some random data")
     722             :         {
     723          20 :             auto randVec = generateRandomMatrix<data_t>(size * 2);
     724          20 :             TestType realDh(randVec);
     725          20 :             auto dhPtr = realDh.getBlock(size / 3, size);
     726          10 :             auto& dh = *dhPtr;
     727             : 
     728          15 :             THEN("the reductions work as expected")
     729             :             {
     730           5 :                 REQUIRE_UNARY(checkApproxEq(dh.sum(), randVec.middleRows(size / 3, size).sum()));
     731           5 :                 REQUIRE_EQ(dh.l0PseudoNorm(),
     732             :                            (randVec.middleRows(size / 3, size).array().cwiseAbs()
     733             :                             >= std::numeric_limits<GetFloatingPointType_t<data_t>>::epsilon())
     734             :                                .count());
     735           5 :                 REQUIRE_UNARY(checkApproxEq(
     736             :                     dh.l1Norm(), randVec.middleRows(size / 3, size).array().abs().sum()));
     737           5 :                 REQUIRE_UNARY(checkApproxEq(
     738             :                     dh.lInfNorm(), randVec.middleRows(size / 3, size).array().abs().maxCoeff()));
     739           5 :                 REQUIRE_UNARY(checkApproxEq(dh.squaredL2Norm(),
     740             :                                             randVec.middleRows(size / 3, size).squaredNorm()));
     741           5 :                 REQUIRE_UNARY(
     742             :                     checkApproxEq(dh.l2Norm(), randVec.middleRows(size / 3, size).norm()));
     743             : 
     744          10 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     745          10 :                 TestType realDh2(randVec2);
     746          10 :                 auto dh2Ptr = realDh2.getBlock(0, size);
     747           5 :                 auto& dh2 = *dh2Ptr;
     748           5 :                 REQUIRE_UNARY(
     749             :                     checkApproxEq(dh.dot(dh2), randVec.middleRows(size / 3, size).dot(randVec2)));
     750             : 
     751           5 :                 TestType dhCPU(randVec2);
     752           5 :                 REQUIRE_UNARY(
     753             :                     checkApproxEq(dh.dot(dhCPU), randVec.middleRows(size / 3, size).dot(randVec2)));
     754             :             }
     755             : 
     756          15 :             THEN("the dot product expects correctly sized arguments")
     757             :             {
     758           5 :                 index_t wrongSize = size - 1;
     759          10 :                 Vector_t<data_t> randVec2(wrongSize);
     760           5 :                 randVec2.setRandom();
     761          10 :                 TestType dh2(randVec2);
     762             : 
     763          10 :                 REQUIRE_THROWS_AS(dh.dot(dh2), InvalidArgumentError);
     764             :             }
     765             :         }
     766             :     }
     767          10 : }
     768             : 
     769         225 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing the element-wise operations", TestType,
     770             :                           datahandlermap_elemwise)
     771             : {
     772             :     using data_t = typename TestType::value_type;
     773             : 
     774          30 :     GIVEN("some DataHandlerMap")
     775             :     {
     776          15 :         index_t size = 567;
     777             : 
     778          30 :         WHEN("putting in some random data")
     779             :         {
     780          30 :             auto randVec = generateRandomMatrix<data_t>(size);
     781          30 :             TestType realDh(randVec);
     782             : 
     783          30 :             auto dhPtr = realDh.getBlock(0, size);
     784          15 :             auto& dh = static_cast<typename MapToHandler<TestType>::map&>(*dhPtr);
     785             : 
     786          20 :             THEN("the element-wise binary vector operations work as expected")
     787             :             {
     788          10 :                 TestType bigDh{2 * size};
     789             : 
     790          10 :                 REQUIRE_THROWS(dh += bigDh);
     791          10 :                 REQUIRE_THROWS(dh -= bigDh);
     792          10 :                 REQUIRE_THROWS(dh *= bigDh);
     793          10 :                 REQUIRE_THROWS(dh /= bigDh);
     794             : 
     795          10 :                 TestType realOldDh(randVec);
     796          10 :                 auto oldDhPtr = realOldDh.getBlock(0, size);
     797           5 :                 auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
     798             : 
     799          10 :                 auto randVec2 = generateRandomMatrix<data_t>(size);
     800             : 
     801          10 :                 TestType dhCPU(randVec2);
     802          10 :                 auto dh2Ptr = dhCPU.getBlock(0, size);
     803           5 :                 auto& dh2 = *dh2Ptr;
     804             : 
     805           5 :                 dh += dh2;
     806        2840 :                 for (index_t i = 0; i < size; ++i)
     807        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dh2[i]));
     808             : 
     809           5 :                 dh = oldDh;
     810           5 :                 dh += dhCPU;
     811        2840 :                 for (index_t i = 0; i < size; ++i)
     812        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + dhCPU[i]));
     813             : 
     814           5 :                 dh = oldDh;
     815           5 :                 dh -= dh2;
     816        2840 :                 for (index_t i = 0; i < size; ++i)
     817        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dh2[i]));
     818             : 
     819           5 :                 dh = oldDh;
     820           5 :                 dh -= dhCPU;
     821        2840 :                 for (index_t i = 0; i < size; ++i)
     822        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - dhCPU[i]));
     823             : 
     824           5 :                 dh = oldDh;
     825           5 :                 dh *= dh2;
     826        2840 :                 for (index_t i = 0; i < size; ++i)
     827        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dh2[i]));
     828             : 
     829           5 :                 dh = oldDh;
     830           5 :                 dh *= dhCPU;
     831        2840 :                 for (index_t i = 0; i < size; ++i)
     832        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * dhCPU[i]));
     833             : 
     834           5 :                 dh = oldDh;
     835           5 :                 dh /= dh2;
     836        2840 :                 for (index_t i = 0; i < size; ++i)
     837        2835 :                     if (dh2[i] != data_t(0))
     838             :                         // due to floating point arithmetic less precision
     839        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dh2[i]));
     840             : 
     841           5 :                 dh = oldDh;
     842           5 :                 dh /= dhCPU;
     843        2840 :                 for (index_t i = 0; i < size; ++i)
     844        2835 :                     if (dhCPU[i] != data_t(0))
     845             :                         // due to floating point arithmetic less precision
     846        2835 :                         REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / dhCPU[i]));
     847             :             }
     848             : 
     849          20 :             THEN("the element-wise binary scalar operations work as expected")
     850             :             {
     851          10 :                 TestType realOldDh(randVec);
     852          10 :                 auto oldDhPtr = realOldDh.getBlock(0, size);
     853           5 :                 auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
     854           5 :                 data_t scalar = std::is_integral_v<data_t> ? 3 : data_t(3.5f);
     855             : 
     856           5 :                 dh += scalar;
     857        2840 :                 for (index_t i = 0; i < size; ++i)
     858        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] + scalar));
     859             : 
     860           5 :                 dh = oldDh;
     861           5 :                 dh -= scalar;
     862        2840 :                 for (index_t i = 0; i < size; ++i)
     863        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] - scalar));
     864             : 
     865           5 :                 dh = oldDh;
     866           5 :                 dh *= scalar;
     867        2840 :                 for (index_t i = 0; i < size; ++i)
     868        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] * scalar));
     869             : 
     870           5 :                 dh = oldDh;
     871           5 :                 dh /= scalar;
     872        2840 :                 for (index_t i = 0; i < size; ++i)
     873        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], oldDh[i] / scalar));
     874             :             }
     875             : 
     876          20 :             THEN("the element-wise assignment of a scalar works as expected")
     877             :             {
     878           5 :                 auto scalar = std::is_integral_v<data_t> ? data_t(47) : data_t(47.11f);
     879             : 
     880           5 :                 dh = scalar;
     881        2840 :                 for (index_t i = 0; i < size; ++i)
     882        2835 :                     REQUIRE_UNARY(checkApproxEq(dh[i], scalar));
     883             :             }
     884             :         }
     885             :     }
     886          15 : }
     887             : 
     888         220 : TEST_CASE_TEMPLATE_DEFINE("DataHandlerMap: Testing referencing blocks", TestType,
     889             :                           datahandlermap_blockref)
     890             : {
     891             :     using data_t = typename TestType::value_type;
     892             : 
     893          15 :     GIVEN("some DataHandlerMap")
     894             :     {
     895           5 :         index_t size = 728;
     896          10 :         Vector_t<data_t> dataVec(size);
     897          10 :         TestType realDh(dataVec);
     898          10 :         auto dhPtr = realDh.getBlock(0, size);
     899           5 :         auto& dh = *dhPtr;
     900             : 
     901          10 :         WHEN("getting the reference to a block")
     902             :         {
     903          10 :             REQUIRE_THROWS(dh.getBlock(size, 1));
     904          10 :             REQUIRE_THROWS(dh.getBlock(0, size + 1));
     905             : 
     906          10 :             auto dhBlock = dh.getBlock(size / 3, size / 2);
     907             : 
     908          10 :             THEN("returned data handler references the correct elements")
     909             :             {
     910           5 :                 REQUIRE_EQ(dhBlock->getSize(), size / 2);
     911             : 
     912        1825 :                 for (index_t i = 0; i < size / 2; i++)
     913        1820 :                     REQUIRE_EQ(&(*dhBlock)[i], &dh[i + size / 3]);
     914             :             }
     915             :         }
     916             :     }
     917             : 
     918          15 :     GIVEN("a const DataHandlerMap")
     919             :     {
     920           5 :         index_t size = 728;
     921          10 :         Vector_t<data_t> dataVec(size);
     922          10 :         const TestType realDh(dataVec);
     923          10 :         auto dhPtr = realDh.getBlock(0, size);
     924           5 :         auto& dh = *dhPtr;
     925             : 
     926          10 :         WHEN("getting the reference to a block")
     927             :         {
     928          10 :             REQUIRE_THROWS(dh.getBlock(size, 1));
     929          10 :             REQUIRE_THROWS(dh.getBlock(0, size + 1));
     930             : 
     931          10 :             auto dhBlock = dh.getBlock(size / 3, size / 2);
     932             : 
     933          10 :             THEN("returned data handler references the correct elements")
     934             :             {
     935           5 :                 REQUIRE_EQ(dhBlock->getSize(), size / 2);
     936             : 
     937        1825 :                 for (index_t i = 0; i < size / 2; i++)
     938        1820 :                     REQUIRE_EQ(&(*dhBlock)[i], &dh[i + size / 3]);
     939             :             }
     940             :         }
     941             :     }
     942          10 : }
     943             : 
     944             : // "instantiate" the test templates for CPU types
     945             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_construction, CPUTypeTuple);
     946             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_eqoperator, CPUTypeTuple);
     947             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_assign, CPUTypeTuple);
     948             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_clone, CPUTypeTuple);
     949             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_reduction, CPUTypeTuple);
     950             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_elemwise, CPUTypeTuple);
     951             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_blockref, CPUTypeTuple);
     952             : 
     953             : #ifdef ELSA_CUDA_VECTOR
     954             : // "instantiate" the test templates for GPU types
     955             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_construction, GPUTypeTuple);
     956             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_eqoperator, GPUTypeTuple);
     957             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_assign, GPUTypeTuple);
     958             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_clone, GPUTypeTuple);
     959             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_reduction, GPUTypeTuple);
     960             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_elemwise, GPUTypeTuple);
     961             : TEST_CASE_TEMPLATE_APPLY(datahandlermap_blockref, GPUTypeTuple);
     962             : #endif
     963             : 
     964             : TEST_SUITE_END();

Generated by: LCOV version 1.15