winget-cli

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

InstallerMetadataCollectionContext.cpp (62080B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "TestCommon.h"
      5 #include "TestSource.h"
      6 #include "TestHooks.h"
      7 
      8 #include <winget/InstallerMetadataCollectionContext.h>
      9 
     10 using namespace AppInstaller;
     11 using namespace AppInstaller::Repository;
     12 using namespace AppInstaller::Repository::Correlation;
     13 using namespace AppInstaller::Repository::Metadata;
     14 using namespace TestCommon;
     15 
     16 namespace
     17 {
     18     // Indicates to set minimal defaults on TestInput
     19     struct MinimalDefaults_t {} MinimalDefaults;
     20 
     21     struct TestInput
     22     {
     23         TestInput() = default;
     24 
     25         TestInput(MinimalDefaults_t)
     26         {
     27             Version = "1.0";
     28             SupportedMetadataVersion = "1.0";
     29             SubmissionIdentifier = "1";
     30             InstallerHash = "ABCD";
     31             PackageData = std::make_optional<Manifest::Manifest>();
     32             PackageData->DefaultLocalization.Locale = "en-us";
     33             PackageData->DefaultLocalization.Add<Manifest::Localization::PackageName>("Name");
     34             PackageData->DefaultLocalization.Add<Manifest::Localization::Publisher>("Publisher");
     35         }
     36 
     37         TestInput(MinimalDefaults_t, const std::string& productVersion, const std::string& productCode, Manifest::InstallerTypeEnum installerType) : TestInput(MinimalDefaults)
     38         {
     39             CurrentMetadata = std::make_optional<ProductMetadata>();
     40             CurrentMetadata->SchemaVersion.Assign("1.0");
     41             CurrentMetadata->ProductVersionMin.Assign(productVersion);
     42             CurrentMetadata->ProductVersionMax.Assign(productVersion);
     43             auto& installerMetadata = CurrentMetadata->InstallerMetadataMap[InstallerHash.value()];
     44             installerMetadata.SubmissionIdentifier = SubmissionIdentifier.value();
     45             installerMetadata.AppsAndFeaturesEntries.push_back({});
     46             auto& entry = installerMetadata.AppsAndFeaturesEntries.back();
     47             entry.DisplayName = PackageData->DefaultLocalization.Get<Manifest::Localization::PackageName>();
     48             entry.Publisher = PackageData->DefaultLocalization.Get<Manifest::Localization::Publisher>();
     49             entry.DisplayVersion = productVersion;
     50             entry.ProductCode = productCode;
     51             entry.InstallerType = installerType;
     52         }
     53 
     54         std::optional<std::string> Version;
     55         std::optional<std::string> SupportedMetadataVersion;
     56         std::optional<ProductMetadata> CurrentMetadata;
     57         std::optional<web::json::value> SubmissionData;
     58         std::optional<std::string> SubmissionIdentifier;
     59         std::optional<std::string> InstallerHash;
     60         // Schema 1.0 only cares about DefaultLocale and Locales
     61         std::optional<Manifest::Manifest> PackageData;
     62 
     63         std::wstring ToJSON()
     64         {
     65             web::json::value json;
     66 
     67             if (Version)
     68             {
     69                 json[L"version"] = JSON::GetStringValue(Version.value());
     70             }
     71 
     72             if (SupportedMetadataVersion)
     73             {
     74                 json[L"supportedMetadataVersion"] = JSON::GetStringValue(SupportedMetadataVersion.value());
     75             }
     76 
     77             if (CurrentMetadata)
     78             {
     79                 json[L"currentMetadata"] = CurrentMetadata->ToJson(CurrentMetadata->SchemaVersion, 0);
     80             }
     81 
     82             if (SubmissionData)
     83             {
     84                 json[L"submissionData"] = SubmissionData.value();
     85             }
     86             else if (SubmissionIdentifier)
     87             {
     88                 web::json::value submissionData;
     89                 submissionData[L"submissionIdentifier"] = JSON::GetStringValue(SubmissionIdentifier.value());
     90                 json[L"submissionData"] = std::move(submissionData);
     91             }
     92 
     93             if (InstallerHash || PackageData)
     94             {
     95                 web::json::value packageData;
     96 
     97                 if (InstallerHash)
     98                 {
     99                     packageData[L"installerHash"] = JSON::GetStringValue(InstallerHash.value());
    100                 }
    101 
    102                 if (PackageData)
    103                 {
    104                     packageData[L"DefaultLocale"] = LocaleToJSON(PackageData->DefaultLocalization);
    105 
    106                     // TODO: Implement other locales
    107                 }
    108 
    109                 json[L"packageData"] = std::move(packageData);
    110             }
    111 
    112             return json.serialize();
    113         }
    114 
    115     private:
    116         web::json::value LocaleToJSON(const Manifest::ManifestLocalization& localization) const
    117         {
    118             web::json::value locale;
    119 
    120             locale[L"PackageLocale"] = JSON::GetStringValue(localization.Locale);
    121 
    122             if (localization.Contains(Manifest::Localization::PackageName))
    123             {
    124                 locale[L"PackageName"] = JSON::GetStringValue(localization.Get<Manifest::Localization::PackageName>());
    125             }
    126 
    127             if (localization.Contains(Manifest::Localization::Publisher))
    128             {
    129                 locale[L"Publisher"] = JSON::GetStringValue(localization.Get<Manifest::Localization::Publisher>());
    130             }
    131 
    132             // TODO: Implement any other needed fields
    133 
    134             return locale;
    135         }
    136     };
    137 
    138     struct TestOutput
    139     {
    140         TestOutput(const std::string& json) : OriginalJSON(json)
    141         {
    142             web::json::value input = web::json::value::parse(Utility::ConvertToUTF16(json));
    143 
    144             auto versionString = JSON::GetRawStringValueFromJsonNode(input, L"version");
    145             if (versionString)
    146             {
    147                 Version = std::move(versionString);
    148             }
    149 
    150             auto submissionDataValue = JSON::GetJsonValueFromNode(input, L"submissionData");
    151             if (submissionDataValue)
    152             {
    153                 SubmissionData = submissionDataValue.value();
    154             }
    155 
    156             auto installerHashString = JSON::GetRawStringValueFromJsonNode(input, L"installerHash");
    157             if (installerHashString)
    158             {
    159                 InstallerHash = std::move(installerHashString);
    160             }
    161 
    162             auto statusString = JSON::GetRawStringValueFromJsonNode(input, L"status");
    163             if (statusString)
    164             {
    165                 Status = std::move(statusString);
    166             }
    167 
    168             auto metadataValue = JSON::GetJsonValueFromNode(input, L"metadata");
    169             if (metadataValue && !metadataValue->get().is_null())
    170             {
    171                 Metadata = std::make_optional<ProductMetadata>();
    172                 Metadata->FromJson(metadataValue->get());
    173             }
    174 
    175             auto diagnosticsValue = JSON::GetJsonValueFromNode(input, L"diagnostics");
    176             if (diagnosticsValue)
    177             {
    178                 auto errorHRNumber = JSON::GetRawIntValueFromJsonNode(diagnosticsValue.value(), L"errorHR");
    179                 if (errorHRNumber)
    180                 {
    181                     ErrorHR = std::move(errorHRNumber);
    182                 }
    183 
    184                 auto errorTextString = JSON::GetRawStringValueFromJsonNode(diagnosticsValue.value(), L"errorText");
    185                 if (errorTextString)
    186                 {
    187                     ErrorText = std::move(errorTextString);
    188                 }
    189             }
    190         }
    191 
    192         std::string OriginalJSON;
    193 
    194         std::optional<std::string> Version;
    195         std::optional<web::json::value> SubmissionData;
    196         std::optional<std::string> InstallerHash;
    197         std::optional<std::string> Status;
    198         std::optional<ProductMetadata> Metadata;
    199         std::optional<HRESULT> ErrorHR;
    200         std::optional<std::string> ErrorText;
    201 
    202         bool IsError() const
    203         {
    204             return Status && Status.value() == "Error";
    205         }
    206 
    207         bool IsSuccess() const
    208         {
    209             return Status && Status.value() == "Success";
    210         }
    211 
    212         bool IsLowConfidence() const
    213         {
    214             return Status && Status.value() == "LowConfidence";
    215         }
    216 
    217         void ValidateFieldPresence() const
    218         {
    219             REQUIRE(Version);
    220             REQUIRE(SubmissionData);
    221             REQUIRE(InstallerHash);
    222             REQUIRE(Status);
    223 
    224             REQUIRE(IsSuccess() == Metadata.has_value());
    225 
    226             REQUIRE(IsError() == ErrorHR.has_value());
    227             REQUIRE(IsError() == ErrorText.has_value());
    228         }
    229     };
    230 
    231     struct TestARPCorrelationData : public ARPCorrelationData
    232     {
    233         ARPCorrelationResult CorrelateForNewlyInstalled(const Manifest::Manifest&, const ARPCorrelationSettings&) override
    234         {
    235             return CorrelateForNewlyInstalledResult;
    236         }
    237 
    238         ARPCorrelationResult CorrelateForNewlyInstalledResult;
    239     };
    240 
    241     struct TestInstalledFilesCorrelation : public InstalledFilesCorrelation
    242     {
    243         Correlation::InstallationMetadata CorrelateForNewlyInstalled(const Manifest::Manifest&, const std::string&) override
    244         {
    245             return InstallationMetadata;
    246         }
    247 
    248         void StartFileWatcher() override {}
    249 
    250         void StopFileWatcher() override {}
    251 
    252         Correlation::InstallationMetadata InstallationMetadata;
    253     };
    254 
    255     InstallerMetadataCollectionContext CreateTestContext(
    256         std::unique_ptr<ARPCorrelationData>&& data,
    257         std::unique_ptr<InstalledFilesCorrelation>&& installedFiles,
    258         TestInput& input)
    259     {
    260         return { std::move(data), std::move(installedFiles), input.ToJSON() };
    261     }
    262 
    263     InstallerMetadataCollectionContext CreateTestContext(std::unique_ptr<ARPCorrelationData>&& data, TestInput& input)
    264     {
    265         return { std::move(data), std::make_unique<TestInstalledFilesCorrelation>(), input.ToJSON()};
    266     }
    267 
    268     InstallerMetadataCollectionContext CreateTestContext(TestInput& input)
    269     {
    270         return CreateTestContext(std::make_unique<TestARPCorrelationData>(), input);
    271     }
    272 
    273     TestOutput GetOutput(InstallerMetadataCollectionContext& context)
    274     {
    275         std::ostringstream strstr;
    276         context.Complete(strstr);
    277 
    278         return { strstr.str() };
    279     }
    280 
    281     TestOutput GetOutput(TestInput& input)
    282     {
    283         InstallerMetadataCollectionContext context = CreateTestContext(input);
    284         return GetOutput(context);
    285     }
    286 
    287     void BadInputTest(TestInput& input)
    288     {
    289         TestOutput output = GetOutput(input);
    290         REQUIRE(output.IsError());
    291         output.ValidateFieldPresence();
    292     }
    293 
    294     ProductMetadata MakeProductMetadata(std::string_view submissionIdentifier = "Submission 1", const std::string& installerHash = "ABCD")
    295     {
    296         ProductMetadata result;
    297         result.SchemaVersion.Assign("1.0");
    298         result.ProductVersionMin.Assign("1.0");
    299         result.ProductVersionMax.Assign("1.0");
    300         auto& installerMetadata = result.InstallerMetadataMap[installerHash];
    301         installerMetadata.SubmissionIdentifier = submissionIdentifier;
    302         installerMetadata.AppsAndFeaturesEntries.push_back({});
    303         auto& entry = installerMetadata.AppsAndFeaturesEntries.back();
    304         entry.DisplayName = "Name";
    305         entry.Publisher = "Publisher";
    306         entry.DisplayVersion = "1.0";
    307         entry.ProductCode = "{guid}";
    308         entry.InstallerType = Manifest::InstallerTypeEnum::Msi;
    309         return result;
    310     }
    311 
    312     struct TestMerge
    313     {
    314         TestMerge() = default;
    315 
    316         TestMerge(MinimalDefaults_t)
    317         {
    318             Version = "1.0";
    319             Metadatas = std::make_optional<std::vector<ProductMetadata>>();
    320             Metadatas->emplace_back(MakeProductMetadata());
    321         }
    322 
    323         std::optional<std::string> Version;
    324         std::optional<std::vector<ProductMetadata>> Metadatas;
    325 
    326         std::wstring ToJSON()
    327         {
    328             web::json::value json;
    329 
    330             if (Version)
    331             {
    332                 json[L"version"] = JSON::GetStringValue(Version.value());
    333             }
    334 
    335             if (Metadatas)
    336             {
    337                 web::json::value metadatasArray;
    338 
    339                 if (Metadatas->empty())
    340                 {
    341                     metadatasArray = web::json::value::array();
    342                 }
    343                 else
    344                 {
    345                     size_t index = 0;
    346                     for (auto& value : Metadatas.value())
    347                     {
    348                         metadatasArray[index++] = value.ToJson(value.SchemaVersion, 0);
    349                     }
    350                 }
    351 
    352                 json[L"metadatas"] = std::move(metadatasArray);
    353             }
    354 
    355             return json.serialize();
    356         }
    357     };
    358 }
    359 
    360 TEST_CASE("MetadataCollection_MinimumInput", "[metadata_collection]")
    361 {
    362     TestInput input(MinimalDefaults);
    363     TestOutput output = GetOutput(input);
    364     REQUIRE(!output.IsError());
    365     output.ValidateFieldPresence();
    366 
    367     REQUIRE(output.Version.value() == input.Version.value());
    368     REQUIRE(output.InstallerHash.value() == input.InstallerHash.value());
    369 }
    370 
    371 TEST_CASE("MetadataCollection_SubmissionDataCopied", "[metadata_collection]")
    372 {
    373     TestInput input(MinimalDefaults);
    374 
    375     web::json::value submissionData;
    376     std::wstring testValueName = L"testValueName";
    377     std::string testValueValue = "Test value value";
    378     submissionData[L"submissionIdentifier"] = JSON::GetStringValue("Required identifier");
    379     submissionData[testValueName] = JSON::GetStringValue(testValueValue);
    380 
    381     input.SubmissionData = submissionData;
    382 
    383     TestOutput output = GetOutput(input);
    384     REQUIRE(!output.IsError());
    385     output.ValidateFieldPresence();
    386 
    387     REQUIRE(output.Version.value() == input.Version.value());
    388     REQUIRE(output.InstallerHash.value() == input.InstallerHash.value());
    389     auto outputValue = JSON::GetRawStringValueFromJsonNode(output.SubmissionData.value(), testValueName);
    390     REQUIRE(outputValue);
    391     REQUIRE(outputValue.value() == testValueValue);
    392 }
    393 
    394 TEST_CASE("MetadataCollection_BadInput", "[metadata_collection]")
    395 {
    396     TestInput input(MinimalDefaults);
    397 
    398 #define RESET_FIELD_SECTION(_field_) \
    399     SECTION("No " #_field_) \
    400     { \
    401         input._field_.reset(); \
    402         BadInputTest(input); \
    403     }
    404 
    405     RESET_FIELD_SECTION(Version);
    406     RESET_FIELD_SECTION(SupportedMetadataVersion);
    407     RESET_FIELD_SECTION(SubmissionIdentifier);
    408     RESET_FIELD_SECTION(InstallerHash);
    409     RESET_FIELD_SECTION(PackageData);
    410 
    411 #undef RESET_FIELD_SECTION
    412 }
    413 
    414 TEST_CASE("MetadataCollection_LowConfidence", "[metadata_collection]")
    415 {
    416     TestInput input(MinimalDefaults);
    417     // The default test correlation object won't have a package correlation set
    418     TestOutput output = GetOutput(input);
    419     REQUIRE(output.IsLowConfidence());
    420     REQUIRE(!output.Metadata);
    421     output.ValidateFieldPresence();
    422 }
    423 
    424 TEST_CASE("MetadataCollection_NewPackage", "[metadata_collection]")
    425 {
    426     TestInput input(MinimalDefaults);
    427     auto correlationData = std::make_unique<TestARPCorrelationData>();
    428 
    429     Manifest::Manifest manifest;
    430     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Test Package Name");
    431     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>("Test Publisher");
    432     manifest.Version = "1.2.3";
    433     manifest.Installers.push_back({});
    434     manifest.Installers[0].ProductCode = "{guid}";
    435 
    436     IPackageVersion::Metadata metadata;
    437     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(Manifest::InstallerTypeEnum::Msi);
    438     metadata[PackageVersionMetadata::InstalledScope] = Manifest::ScopeToString(Manifest::ScopeEnum::User);
    439 
    440     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    441 
    442     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    443     TestOutput output = GetOutput(context);
    444 
    445     REQUIRE(output.IsSuccess());
    446     output.ValidateFieldPresence();
    447 
    448     REQUIRE(output.Metadata->ProductVersionMin.ToString() == output.Metadata->ProductVersionMax.ToString());
    449     REQUIRE(output.Metadata->ProductVersionMin.ToString() == manifest.Version);
    450     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    451     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    452     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    453     REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    454     REQUIRE(entry.Scope.empty());
    455     REQUIRE(entry.AppsAndFeaturesEntries.size() == 1);
    456     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    457     REQUIRE(entry.AppsAndFeaturesEntries[0].Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    458     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayVersion == manifest.Version);
    459     REQUIRE(entry.AppsAndFeaturesEntries[0].ProductCode == manifest.Installers[0].ProductCode);
    460     REQUIRE(entry.AppsAndFeaturesEntries[0].InstallerType == Manifest::InstallerTypeEnum::Msi);
    461     REQUIRE(output.Metadata->HistoricalMetadataList.empty());
    462 }
    463 
    464 TEST_CASE("MetadataCollection_SameSubmission_SameInstaller", "[metadata_collection]")
    465 {
    466     std::string version = "1.3.5";
    467     std::string productCode = "{guid}";
    468     Manifest::InstallerTypeEnum installerType = Manifest::InstallerTypeEnum::Msi;
    469 
    470     TestInput input(MinimalDefaults, version, productCode, installerType);
    471     auto correlationData = std::make_unique<TestARPCorrelationData>();
    472 
    473     Manifest::Manifest manifest;
    474     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Different Language Name");
    475     // Same publisher
    476     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].Publisher);
    477     manifest.Version = version;
    478     manifest.Installers.push_back({});
    479     manifest.Installers[0].ProductCode = productCode;
    480 
    481     IPackageVersion::Metadata metadata;
    482     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(installerType);
    483 
    484     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    485 
    486     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    487     TestOutput output = GetOutput(context);
    488 
    489     REQUIRE(output.IsSuccess());
    490     output.ValidateFieldPresence();
    491 
    492     REQUIRE(output.Metadata->ProductVersionMin.ToString() == output.Metadata->ProductVersionMax.ToString());
    493     REQUIRE(output.Metadata->ProductVersionMin.ToString() == manifest.Version);
    494     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    495     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    496     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    497     REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    498     REQUIRE(entry.AppsAndFeaturesEntries.size() == 2);
    499 
    500     // One should have all values, and the other should have just a different name
    501     // Base which one is which off of whether Publisher is set
    502     for (const auto& featureEntry : entry.AppsAndFeaturesEntries)
    503     {
    504         if (featureEntry.Publisher.empty())
    505         {
    506             REQUIRE(featureEntry.DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    507             REQUIRE(featureEntry.DisplayVersion.empty());
    508             REQUIRE(featureEntry.ProductCode.empty());
    509             REQUIRE(featureEntry.InstallerType == Manifest::InstallerTypeEnum::Unknown);
    510         }
    511         else
    512         {
    513             REQUIRE(featureEntry.DisplayName == input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].DisplayName);
    514             REQUIRE(featureEntry.Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    515             REQUIRE(featureEntry.DisplayVersion == manifest.Version);
    516             REQUIRE(featureEntry.ProductCode == manifest.Installers[0].ProductCode);
    517             REQUIRE(featureEntry.InstallerType == Manifest::InstallerTypeEnum::Msi);
    518         }
    519     }
    520     REQUIRE(output.Metadata->HistoricalMetadataList.empty());
    521 }
    522 
    523 TEST_CASE("MetadataCollection_SameSubmission_NewInstaller", "[metadata_collection]")
    524 {
    525     std::string versionPresent = "1.3.5";
    526     std::string versionIncoming = "1.3.5.1";
    527     std::string productCodePresent = "{guid}";
    528     std::string productCodeIncoming = "{guid_different}";
    529     Manifest::InstallerTypeEnum installerType = Manifest::InstallerTypeEnum::Msi;
    530 
    531     TestInput input(MinimalDefaults, versionPresent, productCodePresent, installerType);
    532     // Change the incoming hash to be new
    533     input.InstallerHash = input.InstallerHash.value() + "_DIFFERENT";
    534     auto correlationData = std::make_unique<TestARPCorrelationData>();
    535 
    536     Manifest::Manifest manifest;
    537     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Name (but different architecture)");
    538     // Same publisher
    539     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].Publisher);
    540     manifest.Version = versionIncoming;
    541     manifest.Installers.push_back({});
    542     manifest.Installers[0].ProductCode = productCodeIncoming;
    543 
    544     IPackageVersion::Metadata metadata;
    545     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(installerType);
    546 
    547     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    548 
    549     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    550     TestOutput output = GetOutput(context);
    551 
    552     REQUIRE(output.IsSuccess());
    553     output.ValidateFieldPresence();
    554 
    555     REQUIRE(output.Metadata->ProductVersionMin.ToString() == versionPresent);
    556     REQUIRE(output.Metadata->ProductVersionMax.ToString() == versionIncoming);
    557     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 2);
    558 
    559     for (const auto& installerMetadata : output.Metadata->InstallerMetadataMap)
    560     {
    561         const auto& entry = installerMetadata.second;
    562 
    563         REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    564         REQUIRE(entry.AppsAndFeaturesEntries.size() == 1);
    565 
    566         const auto& featureEntry = entry.AppsAndFeaturesEntries.front();
    567         REQUIRE(featureEntry.Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    568 
    569         if (featureEntry.ProductCode == productCodePresent)
    570         {
    571             REQUIRE(featureEntry.DisplayName == input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].DisplayName);
    572             REQUIRE(featureEntry.DisplayVersion == versionPresent);
    573             REQUIRE(featureEntry.InstallerType == Manifest::InstallerTypeEnum::Msi);
    574         }
    575         else
    576         {
    577             REQUIRE(featureEntry.DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    578             REQUIRE(featureEntry.DisplayVersion == versionIncoming);
    579             REQUIRE(featureEntry.InstallerType == Manifest::InstallerTypeEnum::Msi);
    580             REQUIRE(featureEntry.ProductCode == productCodeIncoming);
    581         }
    582     }
    583 
    584     REQUIRE(output.Metadata->HistoricalMetadataList.empty());
    585 }
    586 
    587 TEST_CASE("MetadataCollection_NewSubmission", "[metadata_collection]")
    588 {
    589     std::string versionPresent = "1.3.5";
    590     std::string versionIncoming = "1.4.0";
    591     std::string productCodePresent = "{guid}";
    592     std::string productCodeIncoming = "{guid_different}";
    593     Manifest::InstallerTypeEnum installerType = Manifest::InstallerTypeEnum::Msi;
    594 
    595     TestInput input(MinimalDefaults, versionPresent, productCodePresent, installerType);
    596     input.SubmissionIdentifier = input.SubmissionIdentifier.value() + "_NEW";
    597     input.InstallerHash = input.InstallerHash.value() + "_DIFFERENT";
    598     auto correlationData = std::make_unique<TestARPCorrelationData>();
    599 
    600     Manifest::Manifest manifest;
    601     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].DisplayName);
    602     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].Publisher);
    603     manifest.Version = versionIncoming;
    604     manifest.Installers.push_back({});
    605     manifest.Installers[0].ProductCode = productCodeIncoming;
    606 
    607     IPackageVersion::Metadata metadata;
    608     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(installerType);
    609 
    610     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    611 
    612     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    613     TestOutput output = GetOutput(context);
    614 
    615     REQUIRE(output.IsSuccess());
    616     output.ValidateFieldPresence();
    617 
    618     REQUIRE(output.Metadata->ProductVersionMin.ToString() == output.Metadata->ProductVersionMax.ToString());
    619     REQUIRE(output.Metadata->ProductVersionMin.ToString() == manifest.Version);
    620     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    621     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    622     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    623     REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    624     REQUIRE(entry.AppsAndFeaturesEntries.size() == 1);
    625     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    626     REQUIRE(entry.AppsAndFeaturesEntries[0].Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    627     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayVersion == manifest.Version);
    628     REQUIRE(entry.AppsAndFeaturesEntries[0].ProductCode == manifest.Installers[0].ProductCode);
    629     REQUIRE(entry.AppsAndFeaturesEntries[0].InstallerType == Manifest::InstallerTypeEnum::Msi);
    630 
    631     REQUIRE(output.Metadata->HistoricalMetadataList.size() == 1);
    632     const auto& historicalEntry = output.Metadata->HistoricalMetadataList[0];
    633     REQUIRE(historicalEntry.ProductVersionMin.ToString() == input.CurrentMetadata->ProductVersionMin.ToString());
    634     REQUIRE(historicalEntry.ProductVersionMax.ToString() == input.CurrentMetadata->ProductVersionMax.ToString());
    635     const auto& appsAndFeaturesEntry = input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries.front();
    636     REQUIRE(historicalEntry.Names.size() == 1);
    637     REQUIRE(*historicalEntry.Names.begin() == appsAndFeaturesEntry.DisplayName);
    638     REQUIRE(historicalEntry.ProductCodes.size() == 1);
    639     REQUIRE(*historicalEntry.ProductCodes.begin() == appsAndFeaturesEntry.ProductCode);
    640     REQUIRE(historicalEntry.Publishers.size() == 1);
    641     REQUIRE(*historicalEntry.Publishers.begin() == appsAndFeaturesEntry.Publisher);
    642 }
    643 
    644 TEST_CASE("MetadataCollection_Merge_Empty", "[metadata_collection]")
    645 {
    646     TestMerge mergeData{ MinimalDefaults };
    647     mergeData.Metadatas->clear();
    648 
    649     REQUIRE_THROWS_HR(InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {}), E_NOT_SET);
    650 }
    651 
    652 TEST_CASE("MetadataCollection_Merge_SubmissionMismatch", "[metadata_collection]")
    653 {
    654     TestMerge mergeData{ MinimalDefaults };
    655     mergeData.Metadatas->emplace_back(MakeProductMetadata("Submission 2"));
    656 
    657     REQUIRE_THROWS_HR(InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {}), E_NOT_VALID_STATE);
    658 }
    659 
    660 TEST_CASE("MetadataCollection_Merge_DifferentInstallers", "[metadata_collection]")
    661 {
    662     TestMerge mergeData{ MinimalDefaults };
    663     mergeData.Metadatas->emplace_back(MakeProductMetadata(mergeData.Metadatas->at(0).InstallerMetadataMap.begin()->second.SubmissionIdentifier, "EFGH"));
    664 
    665     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
    666     REQUIRE(!mergeResult.empty());
    667 
    668     ProductMetadata mergeMetadata;
    669     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
    670 
    671     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 2);
    672     for (const auto& item : mergeMetadata.InstallerMetadataMap)
    673     {
    674         REQUIRE(item.second.AppsAndFeaturesEntries.size() == 1);
    675         REQUIRE(!item.second.AppsAndFeaturesEntries[0].DisplayName.empty());
    676         REQUIRE(!item.second.AppsAndFeaturesEntries[0].Publisher.empty());
    677         REQUIRE(!item.second.AppsAndFeaturesEntries[0].DisplayVersion.empty());
    678         REQUIRE(!item.second.AppsAndFeaturesEntries[0].ProductCode.empty());
    679     }
    680 }
    681 
    682 TEST_CASE("MetadataCollection_Merge_SameInstaller", "[metadata_collection]")
    683 {
    684     TestMerge mergeData{ MinimalDefaults };
    685     mergeData.Metadatas->emplace_back(MakeProductMetadata());
    686 
    687     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
    688     REQUIRE(!mergeResult.empty());
    689 
    690     ProductMetadata mergeMetadata;
    691     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
    692 
    693     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
    694     for (const auto& item : mergeMetadata.InstallerMetadataMap)
    695     {
    696         REQUIRE(item.second.AppsAndFeaturesEntries.size() == 1);
    697         REQUIRE(!item.second.AppsAndFeaturesEntries[0].DisplayName.empty());
    698         REQUIRE(!item.second.AppsAndFeaturesEntries[0].Publisher.empty());
    699         REQUIRE(!item.second.AppsAndFeaturesEntries[0].DisplayVersion.empty());
    700         REQUIRE(!item.second.AppsAndFeaturesEntries[0].ProductCode.empty());
    701     }
    702 }
    703 
    704 TEST_CASE("MetadataCollection_NewPackage_1_1", "[metadata_collection]")
    705 {
    706     TestInput input(MinimalDefaults);
    707     input.SupportedMetadataVersion = "1.1";
    708     auto correlationData = std::make_unique<TestARPCorrelationData>();
    709 
    710     Manifest::Manifest manifest;
    711     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Test Package Name");
    712     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>("Test Publisher");
    713     manifest.Version = "1.2.3";
    714     manifest.Installers.push_back({});
    715     manifest.Installers[0].ProductCode = "{guid}";
    716 
    717     IPackageVersion::Metadata metadata;
    718     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(Manifest::InstallerTypeEnum::Msi);
    719     metadata[PackageVersionMetadata::InstalledScope] = Manifest::ScopeToString(Manifest::ScopeEnum::User);
    720 
    721     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    722 
    723     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    724     TestOutput output = GetOutput(context);
    725 
    726     REQUIRE(output.IsSuccess());
    727     output.ValidateFieldPresence();
    728 
    729     REQUIRE(output.Metadata->ProductVersionMin.ToString() == output.Metadata->ProductVersionMax.ToString());
    730     REQUIRE(output.Metadata->ProductVersionMin.ToString() == manifest.Version);
    731     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    732     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    733     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    734     REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    735     REQUIRE(entry.Scope == metadata[PackageVersionMetadata::InstalledScope]);
    736     REQUIRE(entry.AppsAndFeaturesEntries.size() == 1);
    737     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    738     REQUIRE(entry.AppsAndFeaturesEntries[0].Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    739     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayVersion == manifest.Version);
    740     REQUIRE(entry.AppsAndFeaturesEntries[0].ProductCode == manifest.Installers[0].ProductCode);
    741     REQUIRE(entry.AppsAndFeaturesEntries[0].InstallerType == Manifest::InstallerTypeEnum::Msi);
    742     REQUIRE(output.Metadata->HistoricalMetadataList.empty());
    743 }
    744 
    745 TEST_CASE("MetadataCollection_NewPackage_NoScope", "[metadata_collection]")
    746 {
    747     TestInput input(MinimalDefaults);
    748     input.SupportedMetadataVersion = "1.1";
    749     auto correlationData = std::make_unique<TestARPCorrelationData>();
    750 
    751     Manifest::Manifest manifest;
    752     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Test Package Name");
    753     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>("Test Publisher");
    754     manifest.Version = "1.2.3";
    755     manifest.Installers.push_back({});
    756     manifest.Installers[0].ProductCode = "{guid}";
    757 
    758     IPackageVersion::Metadata metadata;
    759     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(Manifest::InstallerTypeEnum::Msi);
    760 
    761     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    762 
    763     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    764     TestOutput output = GetOutput(context);
    765 
    766     REQUIRE(output.IsSuccess());
    767     output.ValidateFieldPresence();
    768 
    769     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    770     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    771     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    772     REQUIRE(entry.Scope.empty());
    773 }
    774 
    775 TEST_CASE("MetadataCollection_SameSubmission_SameInstaller_Scopes", "[metadata_collection]")
    776 {
    777     std::string version = "1.3.5";
    778     std::string productCode = "{guid}";
    779     Manifest::InstallerTypeEnum installerType = Manifest::InstallerTypeEnum::Msi;
    780     std::string currentScope = GENERATE(std::string{},
    781         Manifest::ScopeToString(Manifest::ScopeEnum::Unknown),
    782         Manifest::ScopeToString(Manifest::ScopeEnum::User),
    783         Manifest::ScopeToString(Manifest::ScopeEnum::Machine));
    784     std::string newScope{ Manifest::ScopeToString(Manifest::ScopeEnum::User) };
    785 
    786     INFO(currentScope);
    787 
    788     TestInput input(MinimalDefaults, version, productCode, installerType);
    789     input.SupportedMetadataVersion = "1.1";
    790     input.CurrentMetadata->SchemaVersion = { "1.1" };
    791     input.CurrentMetadata->InstallerMetadataMap.begin()->second.Scope = currentScope;
    792     auto correlationData = std::make_unique<TestARPCorrelationData>();
    793 
    794     Manifest::Manifest manifest;
    795     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Different Language Name");
    796     // Same publisher
    797     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].Publisher);
    798     manifest.Version = version;
    799     manifest.Installers.push_back({});
    800     manifest.Installers[0].ProductCode = productCode;
    801 
    802     IPackageVersion::Metadata metadata;
    803     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(installerType);
    804     metadata[PackageVersionMetadata::InstalledScope] = newScope;
    805 
    806     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    807 
    808     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    809     TestOutput output = GetOutput(context);
    810 
    811     REQUIRE(output.IsSuccess());
    812     output.ValidateFieldPresence();
    813 
    814     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    815     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    816     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    817 
    818     if (currentScope.empty())
    819     {
    820         REQUIRE(entry.Scope == newScope);
    821     }
    822     else if (currentScope != newScope)
    823     {
    824         // If Unknown, should stay Unknown
    825         // If different, should become Unknown
    826         REQUIRE(entry.Scope == Manifest::ScopeToString(Manifest::ScopeEnum::Unknown));
    827     }
    828     else
    829     {
    830         // If same, should not change
    831         REQUIRE(entry.Scope == currentScope);
    832     }
    833 }
    834 
    835 TEST_CASE("MetadataCollection_Merge_SameInstaller_Scopes", "[metadata_collection]")
    836 {
    837     TestMerge mergeData{ MinimalDefaults };
    838     mergeData.Metadatas->emplace_back(MakeProductMetadata());
    839 
    840     std::string currentScope = GENERATE(std::string{},
    841         Manifest::ScopeToString(Manifest::ScopeEnum::Unknown),
    842         Manifest::ScopeToString(Manifest::ScopeEnum::User),
    843         Manifest::ScopeToString(Manifest::ScopeEnum::Machine));
    844     std::string newScope{ Manifest::ScopeToString(Manifest::ScopeEnum::Machine) };
    845 
    846     INFO(currentScope);
    847 
    848     mergeData.Metadatas->at(0).SchemaVersion = { "1.1" };
    849     mergeData.Metadatas->at(0).InstallerMetadataMap.begin()->second.Scope = currentScope;
    850     mergeData.Metadatas->at(1).SchemaVersion = { "1.1" };
    851     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.Scope = newScope;
    852 
    853     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
    854     REQUIRE(!mergeResult.empty());
    855 
    856     ProductMetadata mergeMetadata;
    857     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
    858 
    859     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
    860     for (const auto& item : mergeMetadata.InstallerMetadataMap)
    861     {
    862         if (currentScope.empty())
    863         {
    864             REQUIRE(item.second.Scope == newScope);
    865         }
    866         else if (currentScope != newScope)
    867         {
    868             // If Unknown, should stay Unknown
    869             // If different, should become Unknown
    870             REQUIRE(item.second.Scope == Manifest::ScopeToString(Manifest::ScopeEnum::Unknown));
    871         }
    872         else
    873         {
    874             // If same, should not change
    875             REQUIRE(item.second.Scope == currentScope);
    876         }
    877     }
    878 }
    879 
    880 TEST_CASE("MetadataCollection_NewPackage_1_2", "[metadata_collection]")
    881 {
    882     TestInput input(MinimalDefaults);
    883     input.SupportedMetadataVersion = "1.2";
    884     auto correlationData = std::make_unique<TestARPCorrelationData>();
    885     auto installedFilesData = std::make_unique<TestInstalledFilesCorrelation>();
    886 
    887     Manifest::Manifest manifest;
    888     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Test Package Name");
    889     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>("Test Publisher");
    890     manifest.Version = "1.2.3";
    891     manifest.Installers.push_back({});
    892     manifest.Installers[0].ProductCode = "{guid}";
    893 
    894     IPackageVersion::Metadata metadata;
    895     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(Manifest::InstallerTypeEnum::Msi);
    896     metadata[PackageVersionMetadata::InstalledScope] = Manifest::ScopeToString(Manifest::ScopeEnum::User);
    897 
    898     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    899 
    900     Correlation::InstallationMetadata installedFiles;
    901     installedFiles.InstalledFiles.DefaultInstallLocation = "%TEMP%\\TestApp";
    902     Manifest::InstalledFile installedFile;
    903     installedFile.RelativeFilePath = "test.exe";
    904     installedFile.FileSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
    905     installedFile.FileType = Manifest::InstalledFileTypeEnum::Launch;
    906     installedFile.InvocationParameter = "invocation";
    907     installedFile.DisplayName = "name";
    908     installedFiles.InstalledFiles.Files.emplace_back(std::move(installedFile));
    909     Correlation::InstalledStartupLinkFile startupLink;
    910     startupLink.RelativeFilePath = "TestApp.lnk";
    911     startupLink.FileType = Manifest::InstalledFileTypeEnum::Launch;
    912     installedFiles.StartupLinkFiles.emplace_back(std::move(startupLink));
    913 
    914     installedFilesData->InstallationMetadata = std::move(installedFiles);
    915 
    916     std::vector<AppInstaller::Repository::ExtractedIconInfo> testIcons;
    917     AppInstaller::Repository::ExtractedIconInfo iconInfo;
    918     iconInfo.IconContent = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b700");
    919     iconInfo.IconSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
    920     iconInfo.IconFileType = Manifest::IconFileTypeEnum::Ico;
    921     iconInfo.IconResolution = Manifest::IconResolutionEnum::Custom;
    922     iconInfo.IconTheme = Manifest::IconThemeEnum::Default;
    923     testIcons.emplace_back(std::move(iconInfo));
    924 
    925     TestHook::SetExtractIconFromArpEntryResult_Override iconsOverride{ testIcons };
    926 
    927     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), std::move(installedFilesData), input);
    928     TestOutput output = GetOutput(context);
    929 
    930     REQUIRE(output.IsSuccess());
    931     output.ValidateFieldPresence();
    932 
    933     REQUIRE(output.Metadata->ProductVersionMin.ToString() == output.Metadata->ProductVersionMax.ToString());
    934     REQUIRE(output.Metadata->ProductVersionMin.ToString() == manifest.Version);
    935     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    936     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    937     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    938     REQUIRE(entry.SubmissionIdentifier == input.SubmissionIdentifier.value());
    939     REQUIRE(entry.Scope == metadata[PackageVersionMetadata::InstalledScope]);
    940     REQUIRE(entry.AppsAndFeaturesEntries.size() == 1);
    941     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayName == manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>());
    942     REQUIRE(entry.AppsAndFeaturesEntries[0].Publisher == manifest.DefaultLocalization.Get<Manifest::Localization::Publisher>());
    943     REQUIRE(entry.AppsAndFeaturesEntries[0].DisplayVersion == manifest.Version);
    944     REQUIRE(entry.AppsAndFeaturesEntries[0].ProductCode == manifest.Installers[0].ProductCode);
    945     REQUIRE(entry.AppsAndFeaturesEntries[0].InstallerType == Manifest::InstallerTypeEnum::Msi);
    946     REQUIRE(entry.InstalledFiles.has_value());
    947     REQUIRE(entry.InstalledFiles->DefaultInstallLocation == "%TEMP%\\TestApp");
    948     REQUIRE(entry.InstalledFiles->Files.size() == 1);
    949     REQUIRE(entry.InstalledFiles->Files[0].RelativeFilePath == "test.exe");
    950     REQUIRE(entry.InstalledFiles->Files[0].FileSha256 == Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759"));
    951     REQUIRE(entry.InstalledFiles->Files[0].FileType == Manifest::InstalledFileTypeEnum::Launch);
    952     REQUIRE(entry.InstalledFiles->Files[0].InvocationParameter == "invocation");
    953     REQUIRE(entry.InstalledFiles->Files[0].DisplayName == "name");
    954     REQUIRE(entry.StartupLinkFiles.has_value());
    955     REQUIRE(entry.StartupLinkFiles->size() == 1);
    956     REQUIRE(entry.StartupLinkFiles->at(0).RelativeFilePath == "TestApp.lnk");
    957     REQUIRE(entry.StartupLinkFiles->at(0).FileType == Manifest::InstalledFileTypeEnum::Launch);
    958     REQUIRE(entry.Icons.size() == 1);
    959     REQUIRE(entry.Icons[0].IconContent == Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b700"));
    960     REQUIRE(entry.Icons[0].IconSha256 == Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759"));
    961     REQUIRE(entry.Icons[0].IconFileType == Manifest::IconFileTypeEnum::Ico);
    962     REQUIRE(entry.Icons[0].IconResolution == Manifest::IconResolutionEnum::Custom);
    963     REQUIRE(entry.Icons[0].IconTheme == Manifest::IconThemeEnum::Default);
    964     REQUIRE(output.Metadata->HistoricalMetadataList.empty());
    965 }
    966 
    967 TEST_CASE("MetadataCollection_NewPackage_NoInstallationMetadata_NoIcons", "[metadata_collection]")
    968 {
    969     TestInput input(MinimalDefaults);
    970     input.SupportedMetadataVersion = "1.2";
    971     auto correlationData = std::make_unique<TestARPCorrelationData>();
    972 
    973     Manifest::Manifest manifest;
    974     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Test Package Name");
    975     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>("Test Publisher");
    976     manifest.Version = "1.2.3";
    977     manifest.Installers.push_back({});
    978     manifest.Installers[0].ProductCode = "{guid}";
    979 
    980     IPackageVersion::Metadata metadata;
    981     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(Manifest::InstallerTypeEnum::Msi);
    982 
    983     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
    984 
    985     std::vector<AppInstaller::Repository::ExtractedIconInfo> testIcons;
    986     TestHook::SetExtractIconFromArpEntryResult_Override iconsOverride{ testIcons };
    987 
    988     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), input);
    989     TestOutput output = GetOutput(context);
    990 
    991     REQUIRE(output.IsSuccess());
    992     output.ValidateFieldPresence();
    993 
    994     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
    995     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
    996     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
    997     REQUIRE(entry.Scope.empty());
    998     REQUIRE_FALSE(entry.InstalledFiles.has_value());
    999     REQUIRE_FALSE(entry.StartupLinkFiles.has_value());
   1000     REQUIRE(entry.Icons.size() == 0);
   1001 }
   1002 
   1003 TEST_CASE("MetadataCollection_SameSubmission_SameInstaller_InstallationMetadata_Icons", "[metadata_collection]")
   1004 {
   1005     std::string version = "1.3.5";
   1006     std::string productCode = "{guid}";
   1007     Manifest::InstallerTypeEnum installerType = Manifest::InstallerTypeEnum::Msi;
   1008 
   1009     TestInput input(MinimalDefaults, version, productCode, installerType);
   1010     input.SupportedMetadataVersion = "1.2";
   1011     input.CurrentMetadata->SchemaVersion = { "1.2" };
   1012 
   1013     Manifest::InstallationMetadataInfo installedFiles;
   1014     installedFiles.DefaultInstallLocation = "%TEMP%\\TestApp";
   1015     Manifest::InstalledFile installedFile;
   1016     installedFile.RelativeFilePath = "test.exe";
   1017     installedFile.FileSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
   1018     installedFile.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1019     installedFile.InvocationParameter = "invocation";
   1020     installedFile.DisplayName = "name";
   1021     installedFiles.Files.emplace_back(std::move(installedFile));
   1022     input.CurrentMetadata->InstallerMetadataMap.begin()->second.InstalledFiles = std::move(installedFiles);
   1023 
   1024     std::vector<InstalledStartupLinkFile> startupLinkFiles;
   1025     Correlation::InstalledStartupLinkFile startupLink;
   1026     startupLink.RelativeFilePath = "TestApp.lnk";
   1027     startupLink.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1028     startupLinkFiles.emplace_back(std::move(startupLink));
   1029     input.CurrentMetadata->InstallerMetadataMap.begin()->second.StartupLinkFiles = std::move(startupLinkFiles);
   1030 
   1031     std::vector<AppInstaller::Repository::ExtractedIconInfo> testIcons;
   1032     AppInstaller::Repository::ExtractedIconInfo iconInfo;
   1033     iconInfo.IconContent = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b700");
   1034     iconInfo.IconSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
   1035     iconInfo.IconFileType = Manifest::IconFileTypeEnum::Ico;
   1036     iconInfo.IconResolution = Manifest::IconResolutionEnum::Custom;
   1037     iconInfo.IconTheme = Manifest::IconThemeEnum::Default;
   1038     testIcons.emplace_back(std::move(iconInfo));
   1039     input.CurrentMetadata->InstallerMetadataMap.begin()->second.Icons = std::move(testIcons);
   1040 
   1041     auto correlationData = std::make_unique<TestARPCorrelationData>();
   1042     auto installedFilesData = std::make_unique<TestInstalledFilesCorrelation>();
   1043 
   1044     Manifest::Manifest manifest;
   1045     manifest.DefaultLocalization.Add<Manifest::Localization::PackageName>("Different Language Name");
   1046     // Same publisher
   1047     manifest.DefaultLocalization.Add<Manifest::Localization::Publisher>(input.CurrentMetadata->InstallerMetadataMap.begin()->second.AppsAndFeaturesEntries[0].Publisher);
   1048     manifest.Version = version;
   1049     manifest.Installers.push_back({});
   1050     manifest.Installers[0].ProductCode = productCode;
   1051 
   1052     IPackageVersion::Metadata metadata;
   1053     metadata[PackageVersionMetadata::InstalledType] = Manifest::InstallerTypeToString(installerType);
   1054 
   1055     correlationData->CorrelateForNewlyInstalledResult.Package = std::make_shared<TestPackageVersion>(manifest, metadata);
   1056 
   1057     Correlation::InstallationMetadata newInstalledFiles;
   1058     newInstalledFiles.InstalledFiles.DefaultInstallLocation = "%TEMP%\\NewTestApp";
   1059     Manifest::InstalledFile newInstalledFile;
   1060     newInstalledFile.RelativeFilePath = "test.exe";
   1061     newInstalledFile.FileSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
   1062     newInstalledFile.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1063     newInstalledFile.InvocationParameter = "invocation";
   1064     newInstalledFile.DisplayName = "name";
   1065     newInstalledFiles.InstalledFiles.Files.emplace_back(std::move(newInstalledFile));
   1066     Correlation::InstalledStartupLinkFile newStartupLink;
   1067     newStartupLink.RelativeFilePath = "NewTestApp.lnk";
   1068     newStartupLink.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1069     newInstalledFiles.StartupLinkFiles.emplace_back(std::move(newStartupLink));
   1070 
   1071     installedFilesData->InstallationMetadata = std::move(newInstalledFiles);
   1072 
   1073     std::vector<AppInstaller::Repository::ExtractedIconInfo> newTestIcons;
   1074     AppInstaller::Repository::ExtractedIconInfo newIconInfo;
   1075     newIconInfo.IconContent = Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6");
   1076     newIconInfo.IconSha256 = Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df8499");
   1077     newIconInfo.IconFileType = Manifest::IconFileTypeEnum::Jpeg;
   1078     newIconInfo.IconResolution = Manifest::IconResolutionEnum::Square16;
   1079     newIconInfo.IconTheme = Manifest::IconThemeEnum::Light;
   1080     newTestIcons.emplace_back(std::move(newIconInfo));
   1081 
   1082     TestHook::SetExtractIconFromArpEntryResult_Override iconsOverride{ newTestIcons };
   1083 
   1084     InstallerMetadataCollectionContext context = CreateTestContext(std::move(correlationData), std::move(installedFilesData), input);
   1085     TestOutput output = GetOutput(context);
   1086 
   1087     REQUIRE(output.IsSuccess());
   1088     output.ValidateFieldPresence();
   1089 
   1090     REQUIRE(output.Metadata->InstallerMetadataMap.size() == 1);
   1091     REQUIRE(output.Metadata->InstallerMetadataMap.count(input.InstallerHash.value()) == 1);
   1092     const auto& entry = output.Metadata->InstallerMetadataMap[input.InstallerHash.value()];
   1093 
   1094     // Conflicting installed files entries get removed.
   1095     REQUIRE(entry.InstalledFiles.has_value());
   1096     REQUIRE_FALSE(entry.InstalledFiles->HasData());
   1097     // Non duplicate startup links get added.
   1098     REQUIRE(entry.StartupLinkFiles.has_value());
   1099     REQUIRE(entry.StartupLinkFiles->size() == 2);
   1100     // New detected icons always take over
   1101     REQUIRE(entry.Icons.size() == 1);
   1102     REQUIRE(entry.Icons[0].IconContent == Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
   1103     REQUIRE(entry.Icons[0].IconSha256 == Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df8499"));
   1104     REQUIRE(entry.Icons[0].IconFileType == Manifest::IconFileTypeEnum::Jpeg);
   1105     REQUIRE(entry.Icons[0].IconResolution == Manifest::IconResolutionEnum::Square16);
   1106     REQUIRE(entry.Icons[0].IconTheme == Manifest::IconThemeEnum::Light);
   1107 }
   1108 
   1109 TEST_CASE("MetadataCollection_Merge_SameInstaller_InstalledFiles", "[metadata_collection]")
   1110 {
   1111     TestMerge mergeData{ MinimalDefaults };
   1112     mergeData.Metadatas->emplace_back(MakeProductMetadata());
   1113 
   1114     Manifest::InstallationMetadataInfo installedFiles;
   1115     installedFiles.DefaultInstallLocation = "%TEMP%\\TestApp";
   1116     Manifest::InstalledFile installedFile;
   1117     installedFile.RelativeFilePath = "test.exe";
   1118     installedFile.FileSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
   1119     installedFile.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1120     installedFile.InvocationParameter = "invocation";
   1121     installedFile.DisplayName = "name";
   1122     installedFiles.Files.emplace_back(std::move(installedFile));
   1123 
   1124     mergeData.Metadatas->at(0).SchemaVersion = { "1.2" };
   1125     mergeData.Metadatas->at(0).InstallerMetadataMap.begin()->second.InstalledFiles = installedFiles;
   1126 
   1127     // Different default install location clears whole data
   1128     Manifest::InstallationMetadataInfo newInstalledFiles = installedFiles;
   1129     newInstalledFiles.DefaultInstallLocation = "%TEMP%\\NewTestApp";
   1130     mergeData.Metadatas->at(1).SchemaVersion = { "1.2" };
   1131 
   1132     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.InstalledFiles = newInstalledFiles;
   1133     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1134     REQUIRE(!mergeResult.empty());
   1135 
   1136     ProductMetadata mergeMetadata;
   1137     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1138 
   1139     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1140     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles.has_value());
   1141     REQUIRE_FALSE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->HasData());
   1142 
   1143     // Different RelativeFilePath clears the file entry
   1144     Manifest::InstallationMetadataInfo newInstalledFiles2 = installedFiles;
   1145     newInstalledFiles2.Files[0].RelativeFilePath = "test2.exe";
   1146     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.InstalledFiles = newInstalledFiles2;
   1147     mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1148     REQUIRE(!mergeResult.empty());
   1149 
   1150     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1151 
   1152     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1153     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles.has_value());
   1154     REQUIRE_FALSE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->DefaultInstallLocation.empty());
   1155     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files.empty());
   1156 
   1157     // Different other fields clears the fields themselves
   1158     Manifest::InstallationMetadataInfo newInstalledFiles3 = installedFiles;
   1159     newInstalledFiles3.Files[0].DisplayName = "name2";
   1160     newInstalledFiles3.Files[0].FileSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b756");
   1161     newInstalledFiles3.Files[0].InvocationParameter = "invocation2";
   1162     newInstalledFiles3.Files[0].FileType = Manifest::InstalledFileTypeEnum::Uninstall;
   1163     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.InstalledFiles = newInstalledFiles3;
   1164     mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1165     REQUIRE(!mergeResult.empty());
   1166 
   1167     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1168 
   1169     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1170     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles.has_value());
   1171     REQUIRE_FALSE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->DefaultInstallLocation.empty());
   1172     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files.size() == 1);
   1173     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files[0].RelativeFilePath == "test.exe");
   1174     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files[0].DisplayName == "");
   1175     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files[0].InvocationParameter == "");
   1176     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files[0].FileType == Manifest::InstalledFileTypeEnum::Unknown);
   1177     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.InstalledFiles->Files[0].FileSha256.empty());
   1178 }
   1179 
   1180 TEST_CASE("MetadataCollection_Merge_SameInstaller_StartupLinkFiles", "[metadata_collection]")
   1181 {
   1182     TestMerge mergeData{ MinimalDefaults };
   1183     mergeData.Metadatas->emplace_back(MakeProductMetadata());
   1184 
   1185     std::vector<InstalledStartupLinkFile> startupLinkFiles;
   1186     Correlation::InstalledStartupLinkFile startupLink;
   1187     startupLink.RelativeFilePath = "TestApp.lnk";
   1188     startupLink.FileType = Manifest::InstalledFileTypeEnum::Launch;
   1189     startupLinkFiles.emplace_back(std::move(startupLink));
   1190 
   1191     mergeData.Metadatas->at(0).SchemaVersion = { "1.2" };
   1192     mergeData.Metadatas->at(0).InstallerMetadataMap.begin()->second.StartupLinkFiles = startupLinkFiles;
   1193 
   1194     // Different relative file path gets added
   1195     std::vector<InstalledStartupLinkFile> newStartupLinkFiles = startupLinkFiles;
   1196     newStartupLinkFiles[0].RelativeFilePath = "TestApp2.lnk";
   1197 
   1198     mergeData.Metadatas->at(1).SchemaVersion = { "1.2" };
   1199     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.StartupLinkFiles = newStartupLinkFiles;
   1200     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1201     REQUIRE(!mergeResult.empty());
   1202 
   1203     ProductMetadata mergeMetadata;
   1204     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1205 
   1206     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1207     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles.has_value());
   1208     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles->size() == 2);
   1209 
   1210     // Different other fields clears the fields themselves
   1211     std::vector<InstalledStartupLinkFile> newStartupLinkFiles2 = startupLinkFiles;
   1212     newStartupLinkFiles2[0].FileType = Manifest::InstalledFileTypeEnum::Uninstall;
   1213     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.StartupLinkFiles = newStartupLinkFiles2;
   1214     mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1215     REQUIRE(!mergeResult.empty());
   1216 
   1217     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1218 
   1219     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1220     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles.has_value());
   1221     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles->size() == 1);
   1222     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles->at(0).RelativeFilePath == "TestApp.lnk");
   1223     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.StartupLinkFiles->at(0).FileType == Manifest::InstalledFileTypeEnum::Unknown);
   1224 }
   1225 
   1226 TEST_CASE("MetadataCollection_Merge_SameInstaller_Icons", "[metadata_collection]")
   1227 {
   1228     TestMerge mergeData{ MinimalDefaults };
   1229     mergeData.Metadatas->emplace_back(MakeProductMetadata());
   1230 
   1231     std::vector<AppInstaller::Repository::ExtractedIconInfo> testIcons;
   1232     AppInstaller::Repository::ExtractedIconInfo iconInfo;
   1233     iconInfo.IconContent = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b700");
   1234     iconInfo.IconSha256 = Utility::SHA256::ConvertToBytes("d2a45116709136462ee7a1c42f0e75f0efa258fe959b1504dc8ea4573451b759");
   1235     iconInfo.IconFileType = Manifest::IconFileTypeEnum::Ico;
   1236     iconInfo.IconResolution = Manifest::IconResolutionEnum::Custom;
   1237     iconInfo.IconTheme = Manifest::IconThemeEnum::Default;
   1238     testIcons.emplace_back(std::move(iconInfo));
   1239 
   1240     mergeData.Metadatas->at(0).SchemaVersion = { "1.2" };
   1241     mergeData.Metadatas->at(0).InstallerMetadataMap.begin()->second.Icons = testIcons;
   1242 
   1243     // Different test icons
   1244     std::vector<AppInstaller::Repository::ExtractedIconInfo> newTestIcons;
   1245     AppInstaller::Repository::ExtractedIconInfo newIconInfo;
   1246     newIconInfo.IconContent = Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6");
   1247     newIconInfo.IconSha256 = Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df8499");
   1248     newIconInfo.IconFileType = Manifest::IconFileTypeEnum::Jpeg;
   1249     newIconInfo.IconResolution = Manifest::IconResolutionEnum::Square16;
   1250     newIconInfo.IconTheme = Manifest::IconThemeEnum::Light;
   1251     newTestIcons.emplace_back(std::move(newIconInfo));
   1252 
   1253     mergeData.Metadatas->at(1).SchemaVersion = { "1.2" };
   1254     mergeData.Metadatas->at(1).InstallerMetadataMap.begin()->second.Icons = newTestIcons;
   1255     std::wstring mergeResult = InstallerMetadataCollectionContext::Merge(mergeData.ToJSON(), 0, {});
   1256     REQUIRE(!mergeResult.empty());
   1257 
   1258     ProductMetadata mergeMetadata;
   1259     mergeMetadata.FromJson(web::json::value::parse(mergeResult));
   1260 
   1261     // New data always take over
   1262     REQUIRE(mergeMetadata.InstallerMetadataMap.size() == 1);
   1263     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons.size() == 1);
   1264     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons[0].IconContent == Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
   1265     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons[0].IconSha256 == Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df8499"));
   1266     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons[0].IconFileType == Manifest::IconFileTypeEnum::Jpeg);
   1267     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons[0].IconResolution == Manifest::IconResolutionEnum::Square16);
   1268     REQUIRE(mergeMetadata.InstallerMetadataMap.begin()->second.Icons[0].IconTheme == Manifest::IconThemeEnum::Light);
   1269 }