winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

FileEntityTests.cpp (30527B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 
      4 #include "../../../util/SFSExceptionMatcher.h"
      5 #include "../../../util/TestHelper.h"
      6 #include "ReportingHandler.h"
      7 #include "entity/FileEntity.h"
      8 #include "sfsclient/AppFile.h"
      9 #include "sfsclient/File.h"
     10 
     11 #include <catch2/catch_test_macros.hpp>
     12 #include <nlohmann/json.hpp>
     13 
     14 #define TEST(...) TEST_CASE("[FileEntityTests] " __VA_ARGS__)
     15 
     16 using namespace SFS;
     17 using namespace SFS::details;
     18 using namespace SFS::test;
     19 using json = nlohmann::json;
     20 
     21 // GenericFileEntity constants
     22 const std::string c_fileId = "fileId";
     23 const std::string c_url = "url";
     24 const uint64_t c_size = 123;
     25 const std::string c_sha1 = "sha1";
     26 const std::string c_sha256 = "sha256";
     27 
     28 // AppFileEntity constants
     29 const std::string c_fileMoniker = "fileMoniker";
     30 const std::string c_arch = "amd64";
     31 const std::string c_applicability = "app";
     32 ApplicabilityDetailsEntity c_appDetailsEntity{{c_arch}, {c_applicability}};
     33 
     34 TEST("Testing FileEntity::FromJson()")
     35 {
     36     ReportingHandler handler;
     37     handler.SetLoggingCallback(LogCallbackToTest);
     38 
     39     SECTION("Generic File Entity")
     40     {
     41         std::unique_ptr<FileEntity> entity;
     42         SECTION("Correct")
     43         {
     44             const json fileEntity = {{"FileId", c_fileId},
     45                                      {"Url", c_url},
     46                                      {"SizeInBytes", c_size},
     47                                      {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
     48 
     49             REQUIRE_NOTHROW(entity = FileEntity::FromJson(fileEntity, handler));
     50             REQUIRE(entity != nullptr);
     51             REQUIRE(entity->GetContentType() == ContentType::Generic);
     52             REQUIRE(entity->fileId == c_fileId);
     53             REQUIRE(entity->url == c_url);
     54             REQUIRE(entity->sizeInBytes == c_size);
     55             REQUIRE(entity->hashes.size() == 2);
     56             REQUIRE(entity->hashes.at("Sha1") == c_sha1);
     57             REQUIRE(entity->hashes.at("Sha256") == c_sha256);
     58         }
     59 
     60         SECTION("Missing fields")
     61         {
     62             SECTION("Missing FileId")
     63             {
     64                 const json fileEntity = {{"Url", c_url},
     65                                          {"SizeInBytes", c_size},
     66                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
     67                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
     68                                         ServiceInvalidResponse,
     69                                         "Missing File.FileId in response");
     70             }
     71 
     72             SECTION("Missing Url")
     73             {
     74                 const json fileEntity = {{"FileId", c_fileId},
     75                                          {"SizeInBytes", c_size},
     76                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
     77                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
     78                                         ServiceInvalidResponse,
     79                                         "Missing File.Url in response");
     80             }
     81 
     82             SECTION("Missing SizeInBytes")
     83             {
     84                 const json fileEntity = {{"FileId", c_fileId},
     85                                          {"Url", c_url},
     86                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
     87                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
     88                                         ServiceInvalidResponse,
     89                                         "Missing File.SizeInBytes in response");
     90             }
     91 
     92             SECTION("Missing Hashes")
     93             {
     94                 const json fileEntity = {{"FileId", c_fileId}, {"Url", c_url}, {"SizeInBytes", c_size}};
     95                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
     96                                         ServiceInvalidResponse,
     97                                         "Missing File.Hashes in response");
     98             }
     99         }
    100 
    101         SECTION("Wrong types")
    102         {
    103             SECTION("FileId")
    104             {
    105                 const json fileEntity = {{"FileId", 1},
    106                                          {"Url", c_url},
    107                                          {"SizeInBytes", c_size},
    108                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
    109                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    110                                         ServiceInvalidResponse,
    111                                         "File.FileId is not a string");
    112             }
    113 
    114             SECTION("Url")
    115             {
    116                 const json fileEntity = {{"FileId", c_fileId},
    117                                          {"Url", 1},
    118                                          {"SizeInBytes", c_size},
    119                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
    120                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    121                                         ServiceInvalidResponse,
    122                                         "File.Url is not a string");
    123             }
    124 
    125             SECTION("SizeInBytes")
    126             {
    127                 const json fileEntity = {{"FileId", c_fileId},
    128                                          {"Url", c_url},
    129                                          {"SizeInBytes", "size"},
    130                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
    131                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    132                                         ServiceInvalidResponse,
    133                                         "File.SizeInBytes is not an unsigned number");
    134             }
    135 
    136             SECTION("Hashes not an object")
    137             {
    138                 const json fileEntity = {{"FileId", c_fileId}, {"Url", c_url}, {"SizeInBytes", c_size}, {"Hashes", 1}};
    139                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    140                                         ServiceInvalidResponse,
    141                                         "File.Hashes is not an object");
    142             }
    143 
    144             SECTION("Hashes.Sha1")
    145             {
    146                 const json fileEntity = {{"FileId", c_fileId},
    147                                          {"Url", c_url},
    148                                          {"SizeInBytes", c_size},
    149                                          {"Hashes", {{"Sha1", 1}}}};
    150                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    151                                         ServiceInvalidResponse,
    152                                         "File.Hashes object value is not a string");
    153             }
    154         }
    155     }
    156 
    157     SECTION("App File Entity")
    158     {
    159         std::unique_ptr<FileEntity> entity;
    160         const json applicabilityDetails = {{"Architectures", json::array({c_arch})},
    161                                            {"PlatformApplicabilityForPackage", json::array({c_applicability})}};
    162 
    163         SECTION("Correct")
    164         {
    165             const json fileEntity = {{"FileId", c_fileId},
    166                                      {"Url", c_url},
    167                                      {"SizeInBytes", c_size},
    168                                      {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    169                                      {"FileMoniker", c_fileMoniker},
    170                                      {"ApplicabilityDetails", applicabilityDetails}};
    171 
    172             REQUIRE_NOTHROW(entity = FileEntity::FromJson(fileEntity, handler));
    173             REQUIRE(entity != nullptr);
    174             REQUIRE(entity->GetContentType() == ContentType::App);
    175             REQUIRE(entity->fileId == c_fileId);
    176             REQUIRE(entity->url == c_url);
    177             REQUIRE(entity->sizeInBytes == c_size);
    178             REQUIRE(entity->hashes.size() == 2);
    179             REQUIRE(entity->hashes.at("Sha1") == c_sha1);
    180             REQUIRE(entity->hashes.at("Sha256") == c_sha256);
    181 
    182             AppFileEntity* appEntity = dynamic_cast<AppFileEntity*>(entity.get());
    183             REQUIRE(appEntity->fileMoniker == c_fileMoniker);
    184             REQUIRE(appEntity->applicabilityDetails.architectures.size() == 1);
    185             REQUIRE(appEntity->applicabilityDetails.architectures[0] == c_arch);
    186             REQUIRE(appEntity->applicabilityDetails.platformApplicabilityForPackage.size() == 1);
    187             REQUIRE(appEntity->applicabilityDetails.platformApplicabilityForPackage[0] == c_applicability);
    188         }
    189 
    190         SECTION("Missing fields")
    191         {
    192             SECTION("Missing ApplicabilityDetails")
    193             {
    194                 const json fileEntity = {{"FileId", c_fileId},
    195                                          {"Url", c_url},
    196                                          {"SizeInBytes", c_size},
    197                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    198                                          {"FileMoniker", c_fileMoniker}};
    199                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    200                                         ServiceInvalidResponse,
    201                                         "Missing File.ApplicabilityDetails in response");
    202             }
    203 
    204             SECTION("Missing ApplicabilityDetails.Architectures")
    205             {
    206                 const json wrongApplicabilityDetails = {
    207                     {"PlatformApplicabilityForPackage", json::array({c_applicability})}};
    208                 const json fileEntity = {{"FileId", c_fileId},
    209                                          {"Url", c_url},
    210                                          {"SizeInBytes", c_size},
    211                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    212                                          {"FileMoniker", c_fileMoniker},
    213                                          {"ApplicabilityDetails", wrongApplicabilityDetails}};
    214                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    215                                         ServiceInvalidResponse,
    216                                         "Missing File.ApplicabilityDetails.Architectures in response");
    217             }
    218 
    219             SECTION("Missing ApplicabilityDetails.PlatformApplicabilityForPackage")
    220             {
    221                 const json wrongApplicabilityDetails = {{"Architectures", json::array({c_arch})}};
    222                 const json fileEntity = {{"FileId", c_fileId},
    223                                          {"Url", c_url},
    224                                          {"SizeInBytes", c_size},
    225                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    226                                          {"FileMoniker", c_fileMoniker},
    227                                          {"ApplicabilityDetails", wrongApplicabilityDetails}};
    228                 REQUIRE_THROWS_CODE_MSG(
    229                     FileEntity::FromJson(fileEntity, handler),
    230                     ServiceInvalidResponse,
    231                     "Missing File.ApplicabilityDetails.PlatformApplicabilityForPackage in response");
    232             }
    233         }
    234 
    235         SECTION("Wrong types")
    236         {
    237             SECTION("FileMoniker")
    238             {
    239                 const json fileEntity = {{"FileId", c_fileId},
    240                                          {"Url", c_url},
    241                                          {"SizeInBytes", c_size},
    242                                          {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    243                                          {"FileMoniker", 1},
    244                                          {"ApplicabilityDetails", applicabilityDetails}};
    245                 REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    246                                         ServiceInvalidResponse,
    247                                         "File.FileMoniker is not a string");
    248             }
    249 
    250             SECTION("ApplicabilityDetails")
    251             {
    252                 SECTION("Not an object")
    253                 {
    254                     const json fileEntity = {{"FileId", c_fileId},
    255                                              {"Url", c_url},
    256                                              {"SizeInBytes", c_size},
    257                                              {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    258                                              {"FileMoniker", c_fileMoniker},
    259                                              {"ApplicabilityDetails", c_fileId}};
    260                     REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    261                                             ServiceInvalidResponse,
    262                                             "File.ApplicabilityDetails is not an object");
    263                 }
    264 
    265                 SECTION("Architectures is not an array")
    266                 {
    267                     const json wrongApplicabilityDetails = {
    268                         {"Architectures", c_fileId},
    269                         {"PlatformApplicabilityForPackage", json::array({c_applicability})}};
    270                     const json fileEntity = {{"FileId", c_fileId},
    271                                              {"Url", c_url},
    272                                              {"SizeInBytes", c_size},
    273                                              {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    274                                              {"FileMoniker", c_fileMoniker},
    275                                              {"ApplicabilityDetails", wrongApplicabilityDetails}};
    276                     REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    277                                             ServiceInvalidResponse,
    278                                             "File.ApplicabilityDetails.Architectures is not an array");
    279                 }
    280 
    281                 SECTION("Architectures array value is not a string")
    282                 {
    283                     const json wrongApplicabilityDetails = {
    284                         {"Architectures", json::array({1})},
    285                         {"PlatformApplicabilityForPackage", json::array({c_applicability})}};
    286                     const json fileEntity = {{"FileId", c_fileId},
    287                                              {"Url", c_url},
    288                                              {"SizeInBytes", c_size},
    289                                              {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    290                                              {"FileMoniker", c_fileMoniker},
    291                                              {"ApplicabilityDetails", wrongApplicabilityDetails}};
    292                     REQUIRE_THROWS_CODE_MSG(FileEntity::FromJson(fileEntity, handler),
    293                                             ServiceInvalidResponse,
    294                                             "File.ApplicabilityDetails.Architectures array value is not a string");
    295                 }
    296 
    297                 SECTION("PlatformApplicabilityForPackage is not an array")
    298                 {
    299                     const json wrongApplicabilityDetails = {{"Architectures", json::array({c_arch})},
    300                                                             {"PlatformApplicabilityForPackage", c_fileId}};
    301                     const json fileEntity = {{"FileId", c_fileId},
    302                                              {"Url", c_url},
    303                                              {"SizeInBytes", c_size},
    304                                              {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    305                                              {"FileMoniker", c_fileMoniker},
    306                                              {"ApplicabilityDetails", wrongApplicabilityDetails}};
    307                     REQUIRE_THROWS_CODE_MSG(
    308                         FileEntity::FromJson(fileEntity, handler),
    309                         ServiceInvalidResponse,
    310                         "File.ApplicabilityDetails.PlatformApplicabilityForPackage is not an array");
    311                 }
    312 
    313                 SECTION("PlatformApplicabilityForPackage array value is not a string")
    314                 {
    315                     const json wrongApplicabilityDetails = {{"Architectures", json::array({c_arch})},
    316                                                             {"PlatformApplicabilityForPackage", json::array({1})}};
    317                     const json fileEntity = {{"FileId", c_fileId},
    318                                              {"Url", c_url},
    319                                              {"SizeInBytes", c_size},
    320                                              {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    321                                              {"FileMoniker", c_fileMoniker},
    322                                              {"ApplicabilityDetails", wrongApplicabilityDetails}};
    323                     REQUIRE_THROWS_CODE_MSG(
    324                         FileEntity::FromJson(fileEntity, handler),
    325                         ServiceInvalidResponse,
    326                         "File.ApplicabilityDetails.PlatformApplicabilityForPackage array value is not a string");
    327                 }
    328             }
    329         }
    330     }
    331 }
    332 
    333 TEST("Testing GenericFileEntity conversions")
    334 {
    335     ReportingHandler handler;
    336     handler.SetLoggingCallback(LogCallbackToTest);
    337 
    338     auto CheckFile = [&](const File& file) {
    339         REQUIRE(file.GetFileId() == c_fileId);
    340         REQUIRE(file.GetUrl() == c_url);
    341         REQUIRE(file.GetSizeInBytes() == c_size);
    342         REQUIRE(file.GetHashes().size() == 2);
    343         REQUIRE(file.GetHashes().at(HashType::Sha1) == c_sha1);
    344         REQUIRE(file.GetHashes().at(HashType::Sha256) == c_sha256);
    345     };
    346 
    347     SECTION("GenericFileEntity::ToFile()")
    348     {
    349         SECTION("Success")
    350         {
    351             std::unique_ptr<FileEntity> entity = std::make_unique<GenericFileEntity>();
    352             entity->fileId = c_fileId;
    353             entity->url = c_url;
    354             entity->sizeInBytes = c_size;
    355             entity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    356 
    357             auto file = GenericFileEntity::ToFile(std::move(*entity), handler);
    358             CheckFile(*file);
    359         }
    360 
    361         SECTION("Wrong type")
    362         {
    363             std::unique_ptr<FileEntity> wrongEntity = std::make_unique<AppFileEntity>();
    364             wrongEntity->fileId = c_fileId;
    365             wrongEntity->url = c_url;
    366             wrongEntity->sizeInBytes = c_size;
    367             wrongEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    368 
    369             REQUIRE_THROWS_CODE_MSG(
    370                 GenericFileEntity::ToFile(std::move(*wrongEntity), handler),
    371                 ServiceUnexpectedContentType,
    372                 R"(The service returned file "fileId" with content type [App] while the expected type was [Generic])");
    373         }
    374     }
    375 
    376     SECTION("GenericFileEntity::FileEntitiesToFileVector()")
    377     {
    378         SECTION("Success")
    379         {
    380             std::unique_ptr<FileEntity> entity = std::make_unique<GenericFileEntity>();
    381             entity->fileId = c_fileId;
    382             entity->url = c_url;
    383             entity->sizeInBytes = c_size;
    384             entity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    385 
    386             FileEntities entities;
    387             entities.push_back(std::move(entity));
    388 
    389             std::vector<File> files;
    390             SECTION("1 file")
    391             {
    392                 REQUIRE_NOTHROW(files = GenericFileEntity::FileEntitiesToFileVector(std::move(entities), handler));
    393                 REQUIRE(files.size() == 1);
    394                 CheckFile(files[0]);
    395             }
    396 
    397             SECTION("2 files")
    398             {
    399                 std::unique_ptr<FileEntity> entity2 = std::make_unique<GenericFileEntity>();
    400                 entity2->fileId = c_fileId;
    401                 entity2->url = c_url;
    402                 entity2->sizeInBytes = c_size;
    403                 entity2->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    404 
    405                 entities.push_back(std::move(entity2));
    406                 REQUIRE_NOTHROW(files = GenericFileEntity::FileEntitiesToFileVector(std::move(entities), handler));
    407                 REQUIRE(files.size() == 2);
    408                 CheckFile(files[0]);
    409                 CheckFile(files[1]);
    410             }
    411         }
    412 
    413         SECTION("Wrong type, fails")
    414         {
    415             std::unique_ptr<FileEntity> wrongEntity = std::make_unique<AppFileEntity>();
    416             wrongEntity->fileId = c_fileId;
    417             wrongEntity->url = c_url;
    418             wrongEntity->sizeInBytes = c_size;
    419             wrongEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    420 
    421             FileEntities wrongEntities;
    422             wrongEntities.push_back(std::move(wrongEntity));
    423             REQUIRE_THROWS_CODE_MSG(
    424                 GenericFileEntity::FileEntitiesToFileVector(std::move(wrongEntities), handler),
    425                 ServiceUnexpectedContentType,
    426                 R"(The service returned file "fileId" with content type [App] while the expected type was [Generic])");
    427         }
    428     }
    429 }
    430 
    431 TEST("Testing AppFileEntity conversions")
    432 {
    433     ReportingHandler handler;
    434     handler.SetLoggingCallback(LogCallbackToTest);
    435 
    436     auto CheckAppFile = [&](const AppFile& file) {
    437         REQUIRE(file.GetFileId() == c_fileId);
    438         REQUIRE(file.GetUrl() == c_url);
    439         REQUIRE(file.GetSizeInBytes() == c_size);
    440         REQUIRE(file.GetHashes().size() == 2);
    441         REQUIRE(file.GetHashes().at(HashType::Sha1) == c_sha1);
    442         REQUIRE(file.GetHashes().at(HashType::Sha256) == c_sha256);
    443         REQUIRE(file.GetFileMoniker() == c_fileMoniker);
    444         REQUIRE(file.GetApplicabilityDetails().GetArchitectures().size() == 1);
    445         REQUIRE(file.GetApplicabilityDetails().GetArchitectures()[0] == Architecture::Amd64);
    446         REQUIRE(file.GetApplicabilityDetails().GetPlatformApplicabilityForPackage().size() == 1);
    447         REQUIRE(file.GetApplicabilityDetails().GetPlatformApplicabilityForPackage()[0] == c_applicability);
    448     };
    449 
    450     SECTION("AppFileEntity::ToAppFile()")
    451     {
    452         SECTION("Success")
    453         {
    454             std::unique_ptr<FileEntity> entity = std::make_unique<AppFileEntity>();
    455             auto appEntity = dynamic_cast<AppFileEntity*>(entity.get());
    456             appEntity->fileId = c_fileId;
    457             appEntity->url = c_url;
    458             appEntity->sizeInBytes = c_size;
    459             appEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    460             appEntity->fileMoniker = c_fileMoniker;
    461             appEntity->applicabilityDetails = c_appDetailsEntity;
    462 
    463             auto file = AppFileEntity::ToAppFile(std::move(*entity), handler);
    464             CheckAppFile(*file);
    465         }
    466 
    467         SECTION("Wrong type")
    468         {
    469             std::unique_ptr<FileEntity> wrongEntity = std::make_unique<GenericFileEntity>();
    470             wrongEntity->fileId = c_fileId;
    471             wrongEntity->url = c_url;
    472             wrongEntity->sizeInBytes = c_size;
    473             wrongEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    474 
    475             REQUIRE_THROWS_CODE_MSG(
    476                 AppFileEntity::ToAppFile(std::move(*wrongEntity), handler),
    477                 ServiceUnexpectedContentType,
    478                 R"(The service returned file "fileId" with content type [Generic] while the expected type was [App])");
    479         }
    480     }
    481 
    482     SECTION("Testing AppFileEntity::FileEntitiesToAppFileVector()")
    483     {
    484         SECTION("Success")
    485         {
    486             std::unique_ptr<FileEntity> entity = std::make_unique<AppFileEntity>();
    487             auto appEntity = dynamic_cast<AppFileEntity*>(entity.get());
    488             appEntity->fileId = c_fileId;
    489             appEntity->url = c_url;
    490             appEntity->sizeInBytes = c_size;
    491             appEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    492             appEntity->fileMoniker = c_fileMoniker;
    493             appEntity->applicabilityDetails = c_appDetailsEntity;
    494 
    495             FileEntities entities;
    496             entities.push_back(std::move(entity));
    497 
    498             std::vector<AppFile> files;
    499             SECTION("1 file")
    500             {
    501                 REQUIRE_NOTHROW(files = AppFileEntity::FileEntitiesToAppFileVector(std::move(entities), handler));
    502                 REQUIRE(files.size() == 1);
    503                 CheckAppFile(files[0]);
    504             }
    505 
    506             SECTION("2 files")
    507             {
    508                 std::unique_ptr<FileEntity> entity2 = std::make_unique<AppFileEntity>();
    509                 auto appEntity2 = dynamic_cast<AppFileEntity*>(entity2.get());
    510                 appEntity2->fileId = c_fileId;
    511                 appEntity2->url = c_url;
    512                 appEntity2->sizeInBytes = c_size;
    513                 appEntity2->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    514                 appEntity2->fileMoniker = c_fileMoniker;
    515                 appEntity2->applicabilityDetails = c_appDetailsEntity;
    516 
    517                 entities.push_back(std::move(entity2));
    518                 REQUIRE_NOTHROW(files = AppFileEntity::FileEntitiesToAppFileVector(std::move(entities), handler));
    519                 REQUIRE(files.size() == 2);
    520                 CheckAppFile(files[0]);
    521                 CheckAppFile(files[1]);
    522             }
    523         }
    524 
    525         SECTION("Wrong type, fails")
    526         {
    527             std::unique_ptr<FileEntity> wrongEntity = std::make_unique<GenericFileEntity>();
    528             wrongEntity->fileId = c_fileId;
    529             wrongEntity->url = c_url;
    530             wrongEntity->sizeInBytes = c_size;
    531             wrongEntity->hashes = {{"Sha1", c_sha1}, {"Sha256", c_sha256}};
    532 
    533             FileEntities wrongEntities;
    534             wrongEntities.push_back(std::move(wrongEntity));
    535             REQUIRE_THROWS_CODE_MSG(
    536                 AppFileEntity::FileEntitiesToAppFileVector(std::move(wrongEntities), handler),
    537                 ServiceUnexpectedContentType,
    538                 R"(The service returned file "fileId" with content type [Generic] while the expected type was [App])");
    539         }
    540     }
    541 }
    542 
    543 TEST("Testing FileEntity::DownloadInfoResponseToFileEntities()")
    544 {
    545     ReportingHandler handler;
    546     handler.SetLoggingCallback(LogCallbackToTest);
    547 
    548     SECTION("GenericFileEntity")
    549     {
    550         auto CheckEntity = [&](const FileEntity& entity) {
    551             REQUIRE(entity.GetContentType() == ContentType::Generic);
    552             REQUIRE(entity.fileId == c_fileId);
    553             REQUIRE(entity.url == c_url);
    554             REQUIRE(entity.sizeInBytes == c_size);
    555             REQUIRE(entity.hashes.size() == 2);
    556             REQUIRE(entity.hashes.at("Sha1") == c_sha1);
    557             REQUIRE(entity.hashes.at("Sha256") == c_sha256);
    558         };
    559 
    560         SECTION("Correct")
    561         {
    562             const json fileJson = {{"FileId", c_fileId},
    563                                    {"Url", c_url},
    564                                    {"SizeInBytes", c_size},
    565                                    {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}}};
    566 
    567             SECTION("1 file")
    568             {
    569                 const json downloadInfoResponse = json::array({fileJson});
    570                 auto entities = FileEntity::DownloadInfoResponseToFileEntities(downloadInfoResponse, handler);
    571                 REQUIRE(entities.size() == 1);
    572                 REQUIRE(entities[0] != nullptr);
    573                 CheckEntity(*entities[0]);
    574             }
    575 
    576             SECTION("2 files")
    577             {
    578                 const json downloadInfoResponse = json::array({fileJson, fileJson});
    579                 auto entities = FileEntity::DownloadInfoResponseToFileEntities(downloadInfoResponse, handler);
    580                 REQUIRE(entities.size() == 2);
    581                 REQUIRE(entities[0] != nullptr);
    582                 CheckEntity(*entities[0]);
    583                 REQUIRE(entities[1] != nullptr);
    584                 CheckEntity(*entities[1]);
    585             }
    586         }
    587     }
    588 
    589     SECTION("AppFileEntity")
    590     {
    591         const json applicabilityDetails = {{"Architectures", json::array({c_arch})},
    592                                            {"PlatformApplicabilityForPackage", json::array({c_applicability})}};
    593 
    594         auto CheckEntity = [&](const AppFileEntity& entity) {
    595             REQUIRE(entity.GetContentType() == ContentType::App);
    596             REQUIRE(entity.fileId == c_fileId);
    597             REQUIRE(entity.url == c_url);
    598             REQUIRE(entity.sizeInBytes == c_size);
    599             REQUIRE(entity.hashes.size() == 2);
    600             REQUIRE(entity.hashes.at("Sha1") == c_sha1);
    601             REQUIRE(entity.hashes.at("Sha256") == c_sha256);
    602             REQUIRE(entity.fileMoniker == c_fileMoniker);
    603             REQUIRE(entity.applicabilityDetails.architectures.size() == 1);
    604             REQUIRE(entity.applicabilityDetails.architectures[0] == c_arch);
    605             REQUIRE(entity.applicabilityDetails.platformApplicabilityForPackage.size() == 1);
    606             REQUIRE(entity.applicabilityDetails.platformApplicabilityForPackage[0] == c_applicability);
    607         };
    608 
    609         SECTION("Correct")
    610         {
    611             const json fileJson = {{"FileId", c_fileId},
    612                                    {"Url", c_url},
    613                                    {"SizeInBytes", c_size},
    614                                    {"Hashes", {{"Sha1", c_sha1}, {"Sha256", c_sha256}}},
    615                                    {"FileMoniker", c_fileMoniker},
    616                                    {"ApplicabilityDetails", applicabilityDetails}};
    617 
    618             SECTION("1 file")
    619             {
    620                 const json downloadInfoResponse = json::array({fileJson});
    621                 auto entities = FileEntity::DownloadInfoResponseToFileEntities(downloadInfoResponse, handler);
    622                 REQUIRE(entities.size() == 1);
    623                 REQUIRE(entities[0] != nullptr);
    624                 CheckEntity(dynamic_cast<AppFileEntity&>(*entities[0]));
    625             }
    626 
    627             SECTION("2 files")
    628             {
    629                 const json downloadInfoResponse = json::array({fileJson, fileJson});
    630                 auto entities = FileEntity::DownloadInfoResponseToFileEntities(downloadInfoResponse, handler);
    631                 REQUIRE(entities.size() == 2);
    632                 REQUIRE(entities[0] != nullptr);
    633                 CheckEntity(dynamic_cast<AppFileEntity&>(*entities[0]));
    634                 REQUIRE(entities[1] != nullptr);
    635                 CheckEntity(dynamic_cast<AppFileEntity&>(*entities[1]));
    636             }
    637         }
    638     }
    639 }