winget-cli

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

YamlManifest.cpp (125790B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "TestCommon.h"
      5 #include <AppInstallerSHA256.h>
      6 #include <winget/ManifestYamlParser.h>
      7 #include <winget/ManifestYamlWriter.h>
      8 #include <winget/Yaml.h>
      9 
     10 using namespace TestCommon;
     11 using namespace AppInstaller::Manifest;
     12 using namespace AppInstaller::Manifest::YamlParser;
     13 using namespace AppInstaller::Manifest::YamlWriter;
     14 using namespace AppInstaller::Utility;
     15 using namespace AppInstaller::YAML;
     16 
     17 namespace
     18 {
     19     using MultiValue = std::vector<NormalizedString>;
     20     bool operator==(const MultiValue& a, const MultiValue& b)
     21     {
     22         if (a.size() != b.size())
     23         {
     24             return false;
     25         }
     26 
     27         for (size_t i = 0; i < a.size(); ++i)
     28         {
     29             if (a[i] != b[i])
     30             {
     31                 return false;
     32             }
     33         }
     34 
     35         return true;
     36     }
     37 
     38     void ValidateError(
     39         const ValidationError& error,
     40         ValidationError::Level level,
     41         AppInstaller::StringResource::StringId message,
     42         std::string field,
     43         std::string value)
     44     {
     45         REQUIRE(level == error.ErrorLevel);
     46         REQUIRE(message == error.Message);
     47         REQUIRE(field == error.Context);
     48         REQUIRE(value == error.Value);
     49     }
     50 
     51     void ValidateError(const ValidationError& error, ValidationError::Level level, AppInstaller::StringResource::StringId message)
     52     {
     53         ValidateError(error, level, message, std::string(), std::string());
     54     }
     55 
     56     struct ManifestExceptionMatcher : public Catch::Matchers::MatcherBase<ManifestException>
     57     {
     58         ManifestExceptionMatcher(std::string expectedMessage, bool expectedWarningOnly = false) :
     59             m_expectedMessage(expectedMessage), m_expectedWarningOnly(expectedWarningOnly) {}
     60 
     61         // Performs the test for this matcher
     62         bool match(ManifestException const& e) const override
     63         {
     64             return e.GetManifestErrorMessage().find(m_expectedMessage) != std::string::npos &&
     65                 e.IsWarningOnly() == m_expectedWarningOnly;
     66         }
     67 
     68         virtual std::string describe() const override {
     69             std::ostringstream ss;
     70             ss << std::boolalpha << "Expected exception message: " << m_expectedMessage << " Expected IsWarningOnly: " << m_expectedWarningOnly;
     71             return ss.str();
     72         }
     73 
     74     private:
     75         std::string m_expectedMessage;
     76         bool m_expectedWarningOnly;
     77     };
     78 
     79     ManifestValidateOption GetTestManifestValidateOption(
     80         bool schemaValidationOnly = false,
     81         bool errorOnVerifiedPublisher = false)
     82     {
     83         ManifestValidateOption validateOption;
     84         validateOption.FullValidation = true;
     85         validateOption.ThrowOnWarning = true;
     86         validateOption.SchemaValidationOnly = schemaValidationOnly;
     87         validateOption.ErrorOnVerifiedPublisherFields = errorOnVerifiedPublisher;
     88         return validateOption;
     89     }
     90 
     91     void TestManifest(
     92         const std::filesystem::path& manifestPath,
     93         const std::string& expectedMessage = {},
     94         bool expectedWarningOnly = false,
     95         ManifestValidateOption validateOption = GetTestManifestValidateOption())
     96     {
     97         INFO(manifestPath.u8string());
     98 
     99         if (expectedMessage.empty())
    100         {
    101             CHECK_NOTHROW(YamlParser::CreateFromPath(TestDataFile(manifestPath), validateOption));
    102         }
    103         else
    104         {
    105             CHECK_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile(manifestPath), validateOption), ManifestException, ManifestExceptionMatcher(expectedMessage, expectedWarningOnly));
    106         }
    107     }
    108 
    109     struct ManifestTestCase
    110     {
    111         std::string TestFile;
    112         std::string ExpectedMessage = {};
    113         bool IsWarningOnly = false;
    114         ManifestValidateOption ValidateOption = GetTestManifestValidateOption();
    115     };
    116 
    117     void CopyTestDataFilesToFolder(const std::vector<std::string>& testDataFiles, const std::filesystem::path& dest)
    118     {
    119         for (const auto& fileName : testDataFiles)
    120         {
    121             std::filesystem::copy(TestDataFile(fileName), dest);
    122         }
    123     }
    124 
    125     void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, ManifestVer manifestVer = { s_ManifestVersionV1 }, bool isExported = false)
    126     {
    127         REQUIRE(manifest.Id == "microsoft.msixsdk");
    128         REQUIRE(manifest.Version == "1.7.32");
    129         REQUIRE(manifest.DefaultLocalization.Locale == "en-US");
    130         REQUIRE(manifest.DefaultLocalization.Get<Localization::Publisher>() == "Microsoft");
    131         REQUIRE(manifest.DefaultLocalization.Get<Localization::PublisherUrl>() == "https://www.microsoft.com");
    132         REQUIRE(manifest.DefaultLocalization.Get<Localization::PublisherSupportUrl>() == "https://www.microsoft.com/support");
    133         REQUIRE(manifest.DefaultLocalization.Get<Localization::PrivacyUrl>() == "https://www.microsoft.com/privacy");
    134         REQUIRE(manifest.DefaultLocalization.Get<Localization::Author>() == "Microsoft");
    135         REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == "MSIX SDK");
    136         REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageUrl>() == "https://www.microsoft.com/msixsdk/home");
    137         REQUIRE(manifest.DefaultLocalization.Get<Localization::License>() == "MIT License");
    138         REQUIRE(manifest.DefaultLocalization.Get<Localization::LicenseUrl>() == "https://www.microsoft.com/msixsdk/license");
    139         REQUIRE(manifest.DefaultLocalization.Get<Localization::Copyright>() == "Copyright Microsoft Corporation");
    140         REQUIRE(manifest.DefaultLocalization.Get<Localization::CopyrightUrl>() == "https://www.microsoft.com/msixsdk/copyright");
    141         REQUIRE(manifest.DefaultLocalization.Get<Localization::ShortDescription>() == "This is MSIX SDK");
    142         REQUIRE(manifest.DefaultLocalization.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers");
    143         REQUIRE(manifest.Moniker == "msixsdk");
    144         REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>() == MultiValue{ "appxsdk", "msixsdk" });
    145 
    146         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
    147         {
    148             REQUIRE(manifest.DefaultLocalization.Get<Localization::ReleaseNotes>() == "Default release notes");
    149             REQUIRE(manifest.DefaultLocalization.Get<Localization::ReleaseNotesUrl>() == "https://DefaultReleaseNotes.net");
    150             REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().size() == 1);
    151             REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).Label == "DefaultLabel");
    152             REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).AgreementText == "DefaultText");
    153             REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).AgreementUrl == "https://DefaultAgreementUrl.net");
    154         }
    155 
    156         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 })
    157         {
    158             REQUIRE(manifest.DefaultLocalization.Get<Localization::PurchaseUrl>() == "https://DefaultPurchaseUrl.com");
    159             REQUIRE(manifest.DefaultLocalization.Get<Localization::InstallationNotes>() == "Default installation notes");
    160             REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().size() == 1);
    161             REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().at(0).DocumentLabel == "Default document label");
    162             REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().at(0).DocumentUrl == "https://DefaultDocumentUrl.com");
    163         }
    164 
    165         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_5 })
    166         {
    167             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().size() == 1);
    168             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Url == "https://testIcon-en-US");
    169             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Ico);
    170             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Custom);
    171             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Default);
    172             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"));
    173         }
    174 
    175         if (!isExported)
    176         {
    177             REQUIRE(manifest.DefaultInstallerInfo.Locale == "en-US");
    178             REQUIRE(manifest.DefaultInstallerInfo.Platform == std::vector<PlatformEnum>{ PlatformEnum::Desktop, PlatformEnum::Universal });
    179             REQUIRE(manifest.DefaultInstallerInfo.MinOSVersion == "10.0.0.0");
    180             REQUIRE(manifest.DefaultInstallerInfo.BaseInstallerType == InstallerTypeEnum::Exe);
    181             REQUIRE(manifest.DefaultInstallerInfo.Scope == ScopeEnum::Machine);
    182             REQUIRE(manifest.DefaultInstallerInfo.InstallModes == std::vector<InstallModeEnum>{ InstallModeEnum::Interactive, InstallModeEnum::Silent, InstallModeEnum::SilentWithProgress });
    183 
    184             auto defaultSwitches = manifest.DefaultInstallerInfo.Switches;
    185             REQUIRE(defaultSwitches.at(InstallerSwitchType::Custom) == "/custom");
    186             REQUIRE(defaultSwitches.at(InstallerSwitchType::SilentWithProgress) == "/silentwithprogress");
    187             REQUIRE(defaultSwitches.at(InstallerSwitchType::Silent) == "/silence");
    188             REQUIRE(defaultSwitches.at(InstallerSwitchType::Interactive) == "/interactive");
    189             REQUIRE(defaultSwitches.at(InstallerSwitchType::Log) == "/log=<LOGPATH>");
    190             REQUIRE(defaultSwitches.at(InstallerSwitchType::InstallLocation) == "/dir=<INSTALLPATH>");
    191             REQUIRE(defaultSwitches.at(InstallerSwitchType::Update) == "/upgrade");
    192 
    193             REQUIRE(manifest.DefaultInstallerInfo.InstallerSuccessCodes == std::vector<DWORD>{ 1, static_cast<DWORD>(0x80070005) });
    194             REQUIRE(manifest.DefaultInstallerInfo.UpdateBehavior == UpdateBehaviorEnum::UninstallPrevious);
    195             REQUIRE(manifest.DefaultInstallerInfo.Commands == MultiValue{ "makemsix", "makeappx" });
    196             REQUIRE(manifest.DefaultInstallerInfo.Protocols == MultiValue{ "protocol1", "protocol2" });
    197             REQUIRE(manifest.DefaultInstallerInfo.FileExtensions == MultiValue{ "appx", "msix", "appxbundle", "msixbundle" });
    198 
    199             auto dependencies = manifest.DefaultInstallerInfo.Dependencies;
    200             REQUIRE(dependencies.HasExactDependency(DependencyType::WindowsFeature, "IIS"));
    201             REQUIRE(dependencies.HasExactDependency(DependencyType::WindowsLibrary, "VC Runtime"));
    202             REQUIRE(dependencies.HasExactDependency(DependencyType::Package, "Microsoft.MsixSdkDep", "1.0.0"));
    203             REQUIRE(dependencies.HasExactDependency(DependencyType::External, "Outside dependencies"));
    204             REQUIRE(dependencies.Size() == 4);
    205 
    206             REQUIRE(manifest.DefaultInstallerInfo.Capabilities == MultiValue{ "internetClient" });
    207             REQUIRE(manifest.DefaultInstallerInfo.RestrictedCapabilities == MultiValue{ "runFullTrust" });
    208             REQUIRE(manifest.DefaultInstallerInfo.PackageFamilyName == "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe");
    209             REQUIRE(manifest.DefaultInstallerInfo.ProductCode == "{Foo}");
    210 
    211             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
    212             {
    213                 REQUIRE(manifest.DefaultInstallerInfo.ReleaseDate == "2021-01-01");
    214                 REQUIRE(manifest.DefaultInstallerInfo.InstallerAbortsTerminal);
    215                 REQUIRE(manifest.DefaultInstallerInfo.InstallLocationRequired);
    216                 REQUIRE(manifest.DefaultInstallerInfo.RequireExplicitUpgrade);
    217                 REQUIRE(manifest.DefaultInstallerInfo.ElevationRequirement == ElevationRequirementEnum::ElevatesSelf);
    218                 REQUIRE(manifest.DefaultInstallerInfo.UnsupportedOSArchitectures.size() == 1);
    219                 REQUIRE(manifest.DefaultInstallerInfo.UnsupportedOSArchitectures.at(0) == Architecture::Arm);
    220                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.size() == 1);
    221                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).DisplayName == "DisplayName");
    222                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).DisplayVersion == "DisplayVersion");
    223                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).Publisher == "Publisher");
    224                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).ProductCode == "ProductCode");
    225                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).UpgradeCode == "UpgradeCode");
    226                 REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe);
    227                 REQUIRE(manifest.DefaultInstallerInfo.Markets.AllowedMarkets.size() == 1);
    228                 REQUIRE(manifest.DefaultInstallerInfo.Markets.AllowedMarkets.at(0) == "US");
    229                 REQUIRE(manifest.DefaultInstallerInfo.ExpectedReturnCodes.size() == 1);
    230                 REQUIRE(manifest.DefaultInstallerInfo.ExpectedReturnCodes.at(10).ReturnResponseEnum == ExpectedReturnCodeEnum::PackageInUse);
    231             }
    232 
    233             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 })
    234             {
    235                 REQUIRE(manifest.DefaultInstallerInfo.DisplayInstallWarnings);
    236                 REQUIRE(manifest.DefaultInstallerInfo.UnsupportedArguments.size() == 1);
    237                 REQUIRE(manifest.DefaultInstallerInfo.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Log);
    238             }
    239 
    240             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_4 })
    241             {
    242                 REQUIRE(manifest.DefaultInstallerInfo.NestedInstallerType == InstallerTypeEnum::Msi);
    243                 REQUIRE(manifest.DefaultInstallerInfo.NestedInstallerFiles.size() == 1);
    244                 REQUIRE(manifest.DefaultInstallerInfo.NestedInstallerFiles.at(0).RelativeFilePath == "RelativeFilePath");
    245                 REQUIRE(manifest.DefaultInstallerInfo.NestedInstallerFiles.at(0).PortableCommandAlias == "PortableCommandAlias");
    246                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.DefaultInstallLocation == "%ProgramFiles%\\TestApp");
    247                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.Files.size() == 1);
    248                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.Files.at(0).RelativeFilePath == "main.exe");
    249                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Launch);
    250                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.Files.at(0).FileSha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    251                 REQUIRE(manifest.DefaultInstallerInfo.InstallationMetadata.Files.at(0).InvocationParameter == "/arg");
    252             }
    253 
    254             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_6 })
    255             {
    256                 REQUIRE(manifest.DefaultInstallerInfo.DownloadCommandProhibited);
    257             }
    258 
    259             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_7 })
    260             {
    261                 REQUIRE(defaultSwitches.at(InstallerSwitchType::Repair) == "/repair");
    262                 REQUIRE(manifest.DefaultInstallerInfo.RepairBehavior == RepairBehaviorEnum::Modify);
    263             }
    264 
    265             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_9 })
    266             {
    267                 REQUIRE(manifest.DefaultInstallerInfo.ArchiveBinariesDependOnPath);
    268             }
    269         }
    270 
    271         if (isSingleton || isExported)
    272         {
    273             REQUIRE(manifest.Installers.size() == 1);
    274         }
    275         else
    276         {
    277             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_12 })
    278             {
    279                 REQUIRE(manifest.Installers.size() == 7);
    280             }
    281             else if (manifestVer >= ManifestVer{ s_ManifestVersionV1_7 })
    282             {
    283                 REQUIRE(manifest.Installers.size() == 5);
    284             }
    285             else if (manifestVer >= ManifestVer{ s_ManifestVersionV1_4 })
    286             {
    287                 REQUIRE(manifest.Installers.size() == 4);
    288             }
    289             else if (manifestVer == ManifestVer{ s_ManifestVersionV1_2 })
    290             {
    291                 REQUIRE(manifest.Installers.size() == 3);
    292             }
    293             else
    294             {
    295                 REQUIRE(manifest.Installers.size() == 2);
    296             }
    297         }
    298 
    299         ManifestInstaller installer1 = manifest.Installers.at(0);
    300         REQUIRE(installer1.Arch == Architecture::X86);
    301         REQUIRE(installer1.Locale == "en-GB");
    302         REQUIRE(installer1.Platform == std::vector<PlatformEnum>{ PlatformEnum::Desktop });
    303         REQUIRE(installer1.MinOSVersion == "10.0.1.0");
    304         REQUIRE(installer1.BaseInstallerType == InstallerTypeEnum::Msix);
    305         REQUIRE(installer1.Url == "https://www.microsoft.com/msixsdk/msixsdkx86.msix");
    306         REQUIRE(installer1.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    307         REQUIRE(installer1.SignatureSha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    308         REQUIRE(installer1.Scope == ScopeEnum::User);
    309         REQUIRE(installer1.InstallModes == std::vector<InstallModeEnum>{ InstallModeEnum::Interactive });
    310 
    311         auto installer1Switches = installer1.Switches;
    312         REQUIRE(installer1Switches.at(InstallerSwitchType::Custom) == "/c");
    313         REQUIRE(installer1Switches.at(InstallerSwitchType::SilentWithProgress) == "/sp");
    314         REQUIRE(installer1Switches.at(InstallerSwitchType::Silent) == "/s");
    315         REQUIRE(installer1Switches.at(InstallerSwitchType::Interactive) == "/i");
    316         REQUIRE(installer1Switches.at(InstallerSwitchType::Log) == "/l=<LOGPATH>");
    317         REQUIRE(installer1Switches.at(InstallerSwitchType::InstallLocation) == "/d=<INSTALLPATH>");
    318         REQUIRE(installer1Switches.at(InstallerSwitchType::Update) == "/u");
    319 
    320         REQUIRE(installer1.UpdateBehavior == UpdateBehaviorEnum::Install);
    321         REQUIRE(installer1.Commands == MultiValue{ "makemsixPreview", "makeappxPreview" });
    322         REQUIRE(installer1.Protocols == MultiValue{ "protocol1preview", "protocol2preview" });
    323         REQUIRE(installer1.FileExtensions == MultiValue{ "appxbundle", "msixbundle", "appx", "msix" });
    324 
    325         auto installer1Dependencies = installer1.Dependencies;
    326         REQUIRE(installer1Dependencies.HasExactDependency(DependencyType::WindowsFeature, "PreviewIIS"));
    327         REQUIRE(installer1Dependencies.HasExactDependency(DependencyType::WindowsLibrary, "Preview VC Runtime"));
    328         REQUIRE(installer1Dependencies.HasExactDependency(DependencyType::Package, "Microsoft.MsixSdkDepPreview", "1.0.0"));
    329         REQUIRE(installer1Dependencies.HasExactDependency(DependencyType::External, "Preview Outside dependencies"));
    330         REQUIRE(installer1Dependencies.Size() == 4);
    331 
    332         REQUIRE(installer1.Capabilities == MultiValue{ "internetClientPreview" });
    333         REQUIRE(installer1.RestrictedCapabilities == MultiValue{ "runFullTrustPreview" });
    334         REQUIRE(installer1.PackageFamilyName == "Microsoft.DesktopAppInstallerPreview_8wekyb3d8bbwe");
    335 
    336         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
    337         {
    338             REQUIRE(installer1.ReleaseDate == "2021-02-02");
    339             REQUIRE_FALSE(installer1.InstallerAbortsTerminal);
    340             REQUIRE_FALSE(installer1.InstallLocationRequired);
    341             REQUIRE_FALSE(installer1.RequireExplicitUpgrade);
    342             REQUIRE(installer1.ElevationRequirement == ElevationRequirementEnum::ElevationRequired);
    343             REQUIRE(installer1.UnsupportedOSArchitectures.size() == 1);
    344             REQUIRE(installer1.UnsupportedOSArchitectures.at(0) == Architecture::Arm64);
    345             REQUIRE(installer1.AppsAndFeaturesEntries.size() == 0);
    346             REQUIRE(installer1.Markets.AllowedMarkets.size() == 0);
    347             REQUIRE(installer1.Markets.ExcludedMarkets.size() == 1);
    348             REQUIRE(installer1.Markets.ExcludedMarkets.at(0) == "US");
    349             REQUIRE(installer1.ExpectedReturnCodes.at(2).ReturnResponseEnum == ExpectedReturnCodeEnum::ContactSupport);
    350         }
    351 
    352         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 })
    353         {
    354             REQUIRE_FALSE(installer1.DisplayInstallWarnings);
    355             REQUIRE(installer1.ExpectedReturnCodes.at(3).ReturnResponseEnum == ExpectedReturnCodeEnum::Custom);
    356             REQUIRE(installer1.ExpectedReturnCodes.at(3).ReturnResponseUrl == "https://defaultReturnResponseUrl.com");
    357             REQUIRE(installer1.UnsupportedArguments.size() == 1);
    358             REQUIRE(installer1.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Location);
    359         }
    360 
    361         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_4 })
    362         {
    363             // NestedInstaller metadata should not be populated unless the InstallerType is zip.
    364             REQUIRE(installer1.NestedInstallerType == InstallerTypeEnum::Unknown);
    365             REQUIRE(installer1.NestedInstallerFiles.size() == 0);
    366 
    367             REQUIRE(installer1.InstallationMetadata.DefaultInstallLocation == "%ProgramFiles%\\TestApp");
    368             REQUIRE(installer1.InstallationMetadata.Files.size() == 1);
    369             REQUIRE(installer1.InstallationMetadata.Files.at(0).RelativeFilePath == "main.exe");
    370             REQUIRE(installer1.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Launch);
    371             REQUIRE(installer1.InstallationMetadata.Files.at(0).FileSha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    372             REQUIRE(installer1.InstallationMetadata.Files.at(0).InvocationParameter == "/arg");
    373             REQUIRE(installer1.InstallationMetadata.Files.at(0).DisplayName == "DisplayName");
    374         }
    375 
    376         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_6 })
    377         {
    378             REQUIRE_FALSE(installer1.DownloadCommandProhibited);
    379         }
    380 
    381         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_7 })
    382         {
    383             REQUIRE(installer1.Switches.at(InstallerSwitchType::Repair) == "/r");
    384             REQUIRE(installer1.RepairBehavior == RepairBehaviorEnum::Modify);
    385         }
    386 
    387         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_9 })
    388         {
    389             REQUIRE_FALSE(installer1.ArchiveBinariesDependOnPath);
    390         }
    391 
    392         if (!isSingleton)
    393         {
    394             if (!isExported)
    395             {
    396                 ManifestInstaller installer2 = manifest.Installers.at(1);
    397                 REQUIRE(installer2.BaseInstallerType == InstallerTypeEnum::Exe);
    398                 REQUIRE(installer2.Arch == Architecture::X64);
    399                 REQUIRE(installer2.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe");
    400                 REQUIRE(installer2.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    401                 REQUIRE(installer2.ProductCode == "{Bar}");
    402 
    403                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
    404                 {
    405                     REQUIRE(installer2.ReleaseDate == "2021-01-01");
    406                     REQUIRE(installer2.InstallerAbortsTerminal);
    407                     REQUIRE(installer2.InstallLocationRequired);
    408                     REQUIRE(installer2.RequireExplicitUpgrade);
    409                     REQUIRE(installer2.ElevationRequirement == ElevationRequirementEnum::ElevatesSelf);
    410                     REQUIRE(installer2.UnsupportedOSArchitectures.size() == 1);
    411                     REQUIRE(installer2.UnsupportedOSArchitectures.at(0) == Architecture::Arm);
    412                     REQUIRE(installer2.AppsAndFeaturesEntries.size() == 1);
    413                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).DisplayName == "DisplayName");
    414                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).DisplayVersion == "DisplayVersion");
    415                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).Publisher == "Publisher");
    416                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).ProductCode == "ProductCode");
    417                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).UpgradeCode == "UpgradeCode");
    418                     REQUIRE(installer2.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe);
    419                     REQUIRE(installer2.Markets.AllowedMarkets.size() == 1);
    420                     REQUIRE(installer2.Markets.AllowedMarkets.at(0) == "US");
    421                     REQUIRE(installer2.ExpectedReturnCodes.size() == 1);
    422                     REQUIRE(installer2.ExpectedReturnCodes.at(10).ReturnResponseEnum == ExpectedReturnCodeEnum::PackageInUse);
    423                 }
    424 
    425                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 })
    426                 {
    427                     ManifestInstaller installer3 = manifest.Installers.at(2);
    428                     REQUIRE(installer3.BaseInstallerType == InstallerTypeEnum::Portable);
    429                     REQUIRE(installer3.Arch == Architecture::X86);
    430                     REQUIRE(installer3.Url == "https://www.microsoft.com/msixsdk/msixsdkx86.exe");
    431                     REQUIRE(installer3.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    432                     REQUIRE(installer3.Commands == MultiValue{ "standalone" });
    433                     REQUIRE(installer3.ExpectedReturnCodes.size() == 1);
    434                     REQUIRE(installer3.ExpectedReturnCodes.at(11).ReturnResponseEnum == ExpectedReturnCodeEnum::Custom);
    435                     REQUIRE(installer3.ExpectedReturnCodes.at(11).ReturnResponseUrl == "https://defaultReturnResponseUrl.com");
    436                     REQUIRE_FALSE(installer3.DisplayInstallWarnings);
    437                     REQUIRE(installer3.UnsupportedArguments.size() == 1);
    438                     REQUIRE(installer3.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Log);
    439                 }
    440 
    441                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_4 })
    442                 {
    443                     ManifestInstaller installer4 = manifest.Installers.at(3);
    444                     REQUIRE(installer4.BaseInstallerType == InstallerTypeEnum::Zip);
    445                     REQUIRE(installer4.Arch == Architecture::X64);
    446                     REQUIRE(installer4.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe");
    447                     REQUIRE(installer4.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    448                     REQUIRE(installer4.ProductCode == "{Foo}");
    449                     REQUIRE(installer4.NestedInstallerType == InstallerTypeEnum::Portable);
    450                     REQUIRE(installer4.NestedInstallerFiles.size() == 2);
    451                     REQUIRE(installer4.NestedInstallerFiles.at(0).RelativeFilePath == "relativeFilePath1");
    452                     REQUIRE(installer4.NestedInstallerFiles.at(0).PortableCommandAlias == "portableAlias1");
    453                     REQUIRE(installer4.NestedInstallerFiles.at(1).RelativeFilePath == "relativeFilePath2");
    454                     REQUIRE(installer4.NestedInstallerFiles.at(1).PortableCommandAlias == "portableAlias2");
    455                     REQUIRE(installer4.InstallationMetadata.DefaultInstallLocation == "%ProgramFiles%\\TestApp2");
    456                     REQUIRE(installer4.InstallationMetadata.Files.size() == 1);
    457                     REQUIRE(installer4.InstallationMetadata.Files.at(0).RelativeFilePath == "main2.exe");
    458                     REQUIRE(installer4.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Other);
    459                     REQUIRE(installer4.InstallationMetadata.Files.at(0).FileSha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    460                     REQUIRE(installer4.InstallationMetadata.Files.at(0).InvocationParameter == "/arg2");
    461                     REQUIRE(installer4.InstallationMetadata.Files.at(0).DisplayName == "DisplayName2");
    462                 }
    463 
    464                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_6 })
    465                 {
    466                     REQUIRE(installer2.DownloadCommandProhibited);
    467                     REQUIRE(installer2.UpdateBehavior == UpdateBehaviorEnum::Deny);
    468                 }
    469 
    470                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_7 })
    471                 {
    472                     REQUIRE(installer2.RepairBehavior == RepairBehaviorEnum::Uninstaller);
    473                     REQUIRE(installer2.Switches.at(InstallerSwitchType::Repair) == "/r");
    474 
    475                     ManifestInstaller installer5 = manifest.Installers.at(4);
    476                     REQUIRE(installer5.BaseInstallerType == InstallerTypeEnum::Burn);
    477                     REQUIRE(installer5.Arch == Architecture::X64);
    478                     REQUIRE(installer5.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe");
    479                     REQUIRE(installer5.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    480                     REQUIRE(installer5.ProductCode == "{Bar}");
    481                     REQUIRE(installer5.Switches.at(InstallerSwitchType::Repair) == "/repair");
    482                     REQUIRE(installer5.RepairBehavior == RepairBehaviorEnum::Modify);
    483                 }
    484 
    485                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_9 })
    486                 {
    487                     ManifestInstaller installer4 = manifest.Installers.at(3);
    488                     REQUIRE(installer4.ArchiveBinariesDependOnPath);
    489                 }
    490 
    491                 if (manifestVer >= ManifestVer{ s_ManifestVersionV1_12 })
    492                 {
    493                     ManifestInstaller installer6 = manifest.Installers.at(5);
    494                     REQUIRE(installer6.BaseInstallerType == InstallerTypeEnum::Zip);
    495                     REQUIRE(installer6.Arch == Architecture::Neutral);
    496                     REQUIRE(installer6.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe");
    497                     REQUIRE(installer6.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    498                     REQUIRE(installer6.NestedInstallerType == InstallerTypeEnum::Font);
    499                     REQUIRE(installer6.NestedInstallerFiles.size() == 5);
    500                     REQUIRE(installer6.NestedInstallerFiles.at(0).RelativeFilePath == "relativeFilePath1.otf");
    501                     REQUIRE(installer6.NestedInstallerFiles.at(1).RelativeFilePath == "relativeFilePath2.ttf");
    502                     REQUIRE(installer6.NestedInstallerFiles.at(2).RelativeFilePath == "relativeFilePath3.fnt");
    503                     REQUIRE(installer6.NestedInstallerFiles.at(3).RelativeFilePath == "relativeFilePath4.ttc");
    504                     REQUIRE(installer6.NestedInstallerFiles.at(4).RelativeFilePath == "relativeFilePath5.otc");
    505 
    506                     ManifestInstaller installer7 = manifest.Installers.at(6);
    507                     REQUIRE(installer7.BaseInstallerType == InstallerTypeEnum::Font);
    508                     REQUIRE(installer7.Arch == Architecture::Neutral);
    509                     REQUIRE(installer7.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe");
    510                     REQUIRE(installer7.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    511                 }
    512             }
    513 
    514             // Localization
    515             REQUIRE(manifest.Localizations.size() == 1);
    516             ManifestLocalization localization1 = manifest.Localizations.at(0);
    517             REQUIRE(localization1.Locale == "en-GB");
    518             REQUIRE(localization1.Get<Localization::Publisher>() == "Microsoft UK");
    519             REQUIRE(localization1.Get<Localization::PublisherUrl>() == "https://www.microsoft.com/UK");
    520             REQUIRE(localization1.Get<Localization::PublisherSupportUrl>() == "https://www.microsoft.com/support/UK");
    521             REQUIRE(localization1.Get<Localization::PrivacyUrl>() == "https://www.microsoft.com/privacy/UK");
    522             REQUIRE(localization1.Get<Localization::Author>() == "Microsoft UK");
    523             REQUIRE(localization1.Get<Localization::PackageName>() == "MSIX SDK UK");
    524             REQUIRE(localization1.Get<Localization::PackageUrl>() == "https://www.microsoft.com/msixsdk/home/UK");
    525             REQUIRE(localization1.Get<Localization::License>() == "MIT License UK");
    526             REQUIRE(localization1.Get<Localization::LicenseUrl>() == "https://www.microsoft.com/msixsdk/license/UK");
    527             REQUIRE(localization1.Get<Localization::Copyright>() == "Copyright Microsoft Corporation UK");
    528             REQUIRE(localization1.Get<Localization::CopyrightUrl>() == "https://www.microsoft.com/msixsdk/copyright/UK");
    529             REQUIRE(localization1.Get<Localization::ShortDescription>() == "This is MSIX SDK UK");
    530             REQUIRE(localization1.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers UK");
    531             REQUIRE(localization1.Get<Localization::Tags>() == MultiValue{ "appxsdkUK", "msixsdkUK" });
    532 
    533             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_1 })
    534             {
    535                 REQUIRE(localization1.Get<Localization::ReleaseNotes>() == "Release notes");
    536                 REQUIRE(localization1.Get<Localization::ReleaseNotesUrl>() == "https://ReleaseNotes.net");
    537                 REQUIRE(localization1.Get<Localization::Agreements>().size() == 1);
    538                 REQUIRE(localization1.Get<Localization::Agreements>().at(0).Label == "Label");
    539                 REQUIRE(localization1.Get<Localization::Agreements>().at(0).AgreementText == "Text");
    540                 REQUIRE(localization1.Get<Localization::Agreements>().at(0).AgreementUrl == "https://AgreementUrl.net");
    541             }
    542 
    543             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 })
    544             {
    545                 REQUIRE(localization1.Get<Localization::PurchaseUrl>() == "https://DefaultPurchaseUrl.com");
    546                 REQUIRE(localization1.Get<Localization::InstallationNotes>() == "Default installation notes");
    547                 REQUIRE(localization1.Get<Localization::Documentations>().size() == 1);
    548                 REQUIRE(localization1.Get<Localization::Documentations>().at(0).DocumentLabel == "Default document label");
    549                 REQUIRE(localization1.Get<Localization::Documentations>().at(0).DocumentUrl == "https://DefaultDocumentUrl.com");
    550             }
    551 
    552             if (manifestVer >= ManifestVer{ s_ManifestVersionV1_5 })
    553             {
    554                 REQUIRE(localization1.Get<Localization::Icons>().size() == 1);
    555                 REQUIRE(localization1.Get<Localization::Icons>().at(0).Url == "https://localeTestIcon-en-GB");
    556                 REQUIRE(localization1.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Png);
    557                 REQUIRE(localization1.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Square32);
    558                 REQUIRE(localization1.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Light);
    559                 REQUIRE(localization1.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"));
    560             }
    561         }
    562     }
    563 
    564     struct ManifestShadowTestInfo
    565     {
    566         bool shadowDefaultLocale;
    567         bool shadowEnGbLocale;
    568     };
    569 
    570     void VerifyV1ManifestContentCreatedWithShadow(const Manifest& manifest, ManifestShadowTestInfo shadowInfo, ManifestVer manifestVer = { s_ManifestVersionV1_5 })
    571     {
    572         REQUIRE(manifest.Id == "microsoft.msixsdk");
    573         REQUIRE(manifest.Version == "1.7.32");
    574         REQUIRE(manifest.Installers.size() == 1);
    575 
    576         // Default localization
    577         REQUIRE(manifest.DefaultLocalization.Locale == "en-US");
    578         REQUIRE(manifest.DefaultLocalization.Get<Localization::Publisher>() == "Microsoft");
    579         REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == "MSIX SDK");
    580         REQUIRE(manifest.DefaultLocalization.Get<Localization::License>() == "MIT License");
    581         REQUIRE(manifest.DefaultLocalization.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers");
    582         REQUIRE(manifest.DefaultLocalization.Get<Localization::ShortDescription>() == "This is MSIX SDK");
    583         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_5 })
    584         {
    585             REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().size() == 1);
    586 
    587             if (shadowInfo.shadowDefaultLocale)
    588             {
    589                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Url == "https://shadowIcon-default");
    590                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Ico);
    591                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Custom);
    592                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Default);
    593                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("1111111111111111111111111111111111111111111111111111111111111111"));
    594             }
    595             else
    596             {
    597                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().size() == 1);
    598                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Url == "https://testIcon-en-US");
    599                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Ico);
    600                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Custom);
    601                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Default);
    602                 REQUIRE(manifest.DefaultLocalization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"));
    603             }
    604         }
    605 
    606         // Localization
    607         if (manifestVer >= ManifestVer{ s_ManifestVersionV1_5 })
    608         {
    609             REQUIRE(manifest.Localizations.size() == 3);
    610 
    611             bool foundEnGbLocale = false;
    612             bool foundfrFrLocale = false;
    613             for (auto const& localization : manifest.Localizations)
    614             {
    615                 if (localization.Locale == "en-GB")
    616                 {
    617                     REQUIRE(localization.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers UK");
    618                     if (shadowInfo.shadowEnGbLocale)
    619                     {
    620                         REQUIRE(localization.Get<Localization::Icons>().size() == 1);
    621                         REQUIRE(localization.Get<Localization::Icons>().at(0).Url == "https://shadowIcon-en-GB");
    622                         REQUIRE(localization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Png);
    623                         REQUIRE(localization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Square32);
    624                         REQUIRE(localization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Light);
    625                         REQUIRE(localization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("2222222222222222222222222222222222222222222222222222222222222222"));
    626                     }
    627                     else
    628                     {
    629                         REQUIRE(localization.Get<Localization::Icons>().size() == 1);
    630                         REQUIRE(localization.Get<Localization::Icons>().at(0).Url == "https://localeTestIcon-en-GB");
    631                         REQUIRE(localization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Png);
    632                         REQUIRE(localization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Square32);
    633                         REQUIRE(localization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Light);
    634                         REQUIRE(localization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"));
    635                     }
    636 
    637                     foundEnGbLocale = true;
    638                 }
    639                 else if (localization.Locale == "fr-FR")
    640                 {
    641                     REQUIRE(localization.Get<Localization::Icons>().size() == 1);
    642                     REQUIRE(localization.Get<Localization::Icons>().at(0).Url == "https://shadowIcon-fr-FR");
    643                     REQUIRE(localization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Jpeg);
    644                     REQUIRE(localization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Square20);
    645                     REQUIRE(localization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Dark);
    646                     REQUIRE(localization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("3333333333333333333333333333333333333333333333333333333333333333"));
    647                     foundfrFrLocale = true;
    648                 }
    649                 else
    650                 {
    651                     REQUIRE(localization.Locale == "es-MX");
    652                     REQUIRE(localization.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers MX");
    653                     REQUIRE(localization.Get<Localization::Icons>().size() == 1);
    654                     REQUIRE(localization.Get<Localization::Icons>().at(0).Url == "https://localeTestIcon-es-MX");
    655                     REQUIRE(localization.Get<Localization::Icons>().at(0).FileType == IconFileTypeEnum::Png);
    656                     REQUIRE(localization.Get<Localization::Icons>().at(0).Resolution == IconResolutionEnum::Square32);
    657                     REQUIRE(localization.Get<Localization::Icons>().at(0).Theme == IconThemeEnum::Light);
    658                     REQUIRE(localization.Get<Localization::Icons>().at(0).Sha256 == SHA256::ConvertToBytes("4444444444444444444444444444444444444444444444444444444444444444"));
    659                 }
    660             }
    661 
    662             REQUIRE(foundEnGbLocale);
    663             REQUIRE(foundfrFrLocale);
    664         }
    665     }
    666 }
    667 
    668 TEST_CASE("ReadPreviewGoodManifestAndVerifyContents", "[ManifestValidation]")
    669 {
    670     auto manifestFile = TestDataFile("Manifest-Good.yaml");
    671     Manifest manifest = YamlParser::CreateFromPath(manifestFile);
    672 
    673     REQUIRE(manifest.Id == "microsoft.msixsdk");
    674     REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == "MSIX SDK");
    675     REQUIRE(manifest.Moniker == "msixsdk");
    676     REQUIRE(manifest.Version == "1.7.32");
    677     REQUIRE(manifest.DefaultLocalization.Get<Localization::Publisher>() == "Microsoft");
    678     REQUIRE(manifest.Channel == "release");
    679     REQUIRE(manifest.DefaultLocalization.Get<Localization::Author>() == "Microsoft");
    680     REQUIRE(manifest.DefaultLocalization.Get<Localization::License>() == "MIT License");
    681     REQUIRE(manifest.DefaultLocalization.Get<Localization::LicenseUrl>() == "https://github.com/microsoft/msix-packaging/blob/master/LICENSE");
    682     REQUIRE(manifest.DefaultInstallerInfo.MinOSVersion == "0.0.0.0");
    683     REQUIRE(manifest.DefaultLocalization.Get<Localization::Description>() == "The MSIX SDK project is an effort to enable developers");
    684     REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageUrl>() == "https://github.com/microsoft/msix-packaging");
    685     REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>() == MultiValue{ "msix", "appx" });
    686     REQUIRE(manifest.DefaultInstallerInfo.Commands == MultiValue{ "makemsix", "makeappx" });
    687     REQUIRE(manifest.DefaultInstallerInfo.Protocols == MultiValue{ "protocol1", "protocol2" });
    688     REQUIRE(manifest.DefaultInstallerInfo.FileExtensions == MultiValue{ "appx", "appxbundle", "msix", "msixbundle" });
    689     REQUIRE(manifest.DefaultInstallerInfo.BaseInstallerType == InstallerTypeEnum::Exe);
    690     REQUIRE(manifest.DefaultInstallerInfo.PackageFamilyName == "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe");
    691     REQUIRE(manifest.DefaultInstallerInfo.ProductCode == "{Foo}");
    692     REQUIRE(manifest.DefaultInstallerInfo.UpdateBehavior == UpdateBehaviorEnum::UninstallPrevious);
    693 
    694     // default switches
    695     auto switches = manifest.DefaultInstallerInfo.Switches;
    696     REQUIRE(switches.at(InstallerSwitchType::Custom) == "/custom");
    697     REQUIRE(switches.at(InstallerSwitchType::SilentWithProgress) == "/silentwithprogress");
    698     REQUIRE(switches.at(InstallerSwitchType::Silent) == "/silence");
    699     REQUIRE(switches.at(InstallerSwitchType::Interactive) == "/interactive");
    700     REQUIRE(switches.at(InstallerSwitchType::Language) == "/en-us");
    701     REQUIRE(switches.at(InstallerSwitchType::Log) == "/log=<LOGPATH>");
    702     REQUIRE(switches.at(InstallerSwitchType::InstallLocation) == "/dir=<INSTALLPATH>");
    703     REQUIRE(switches.at(InstallerSwitchType::Update) == "/update");
    704 
    705     // installers
    706     REQUIRE(manifest.Installers.size() == 2);
    707     ManifestInstaller installer1 = manifest.Installers.at(0);
    708     REQUIRE(installer1.Arch == Architecture::X86);
    709     REQUIRE(installer1.Url == "https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx86.zip");
    710     REQUIRE(installer1.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82"));
    711     REQUIRE(installer1.Locale == "en-US");
    712     REQUIRE(installer1.BaseInstallerType == InstallerTypeEnum::Exe);
    713     REQUIRE(installer1.Scope == ScopeEnum::User);
    714     REQUIRE(installer1.PackageFamilyName == "");
    715     REQUIRE(installer1.ProductCode == "{Foo}");
    716     REQUIRE(installer1.UpdateBehavior == UpdateBehaviorEnum::Install);
    717 
    718     auto installer1Switches = installer1.Switches;
    719     REQUIRE(installer1Switches.at(InstallerSwitchType::Custom) == "/c");
    720     REQUIRE(installer1Switches.at(InstallerSwitchType::SilentWithProgress) == "/sp");
    721     REQUIRE(installer1Switches.at(InstallerSwitchType::Silent) == "/s");
    722     REQUIRE(installer1Switches.at(InstallerSwitchType::Interactive) == "/i");
    723     REQUIRE(installer1Switches.at(InstallerSwitchType::Language) == "/en");
    724     REQUIRE(installer1Switches.at(InstallerSwitchType::Log) == "/l=<LOGPATH>");
    725     REQUIRE(installer1Switches.at(InstallerSwitchType::InstallLocation) == "/d=<INSTALLPATH>");
    726     REQUIRE(installer1Switches.at(InstallerSwitchType::Update) == "/u");
    727 
    728     ManifestInstaller installer2 = manifest.Installers.at(1);
    729     REQUIRE(installer2.Arch == Architecture::X64);
    730     REQUIRE(installer2.Url == "https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx64.zip");
    731     REQUIRE(installer2.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF0000"));
    732     REQUIRE(installer2.Locale == "en-US");
    733     REQUIRE(installer2.BaseInstallerType == InstallerTypeEnum::Exe);
    734     REQUIRE(installer2.Scope == ScopeEnum::User);
    735     REQUIRE(installer2.PackageFamilyName == "");
    736     REQUIRE(installer2.ProductCode == "{Foo}");
    737     REQUIRE(installer2.UpdateBehavior == UpdateBehaviorEnum::UninstallPrevious);
    738 
    739     // Installer2 does not declare switches, it inherits switches from package default.
    740     auto installer2Switches = installer2.Switches;
    741     REQUIRE(installer2Switches.at(InstallerSwitchType::Custom) == "/custom");
    742     REQUIRE(installer2Switches.at(InstallerSwitchType::SilentWithProgress) == "/silentwithprogress");
    743     REQUIRE(installer2Switches.at(InstallerSwitchType::Silent) == "/silence");
    744     REQUIRE(installer2Switches.at(InstallerSwitchType::Interactive) == "/interactive");
    745     REQUIRE(installer2Switches.at(InstallerSwitchType::Language) == "/en-us");
    746     REQUIRE(installer2Switches.at(InstallerSwitchType::Log) == "/log=<LOGPATH>");
    747     REQUIRE(installer2Switches.at(InstallerSwitchType::InstallLocation) == "/dir=<INSTALLPATH>");
    748     REQUIRE(installer2Switches.at(InstallerSwitchType::Update) == "/update");
    749 
    750     // Localization
    751     REQUIRE(manifest.Localizations.size() == 1);
    752     ManifestLocalization localization1 = manifest.Localizations.at(0);
    753     REQUIRE(localization1.Locale == "es-MX");
    754     REQUIRE(localization1.Get<Localization::Description>() == "El proyecto MSIX SDK es habilita desarrolladores de diferentes");
    755     REQUIRE(localization1.Get<Localization::PackageUrl>() == "https://github.com/microsoft/msix-packaging/es-MX");
    756     REQUIRE(localization1.Get<Localization::LicenseUrl>() == "https://github.com/microsoft/msix-packaging/blob/master/LICENSE-es-MX");
    757 
    758     // Stream hash
    759     std::ifstream stream(manifestFile.GetPath(), std::ios_base::in | std::ios_base::binary);
    760     REQUIRE(!stream.fail());
    761     auto manifestHash = SHA256::ComputeHash(stream);
    762     REQUIRE(manifestHash.size() == manifest.StreamSha256.size());
    763     REQUIRE(std::equal(manifestHash.begin(), manifestHash.end(), manifest.StreamSha256.begin()));
    764 }
    765 
    766 TEST_CASE("ReadGoodManifestWithSpaces", "[ManifestValidation]")
    767 {
    768     Manifest manifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-Spaces.yaml"));
    769 
    770     REQUIRE(manifest.Id == "microsoft.msixsdk");
    771     REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == "MSIX SDK");
    772     REQUIRE(manifest.Moniker == "msixsdk");
    773     REQUIRE(manifest.Version == "1.7.32");
    774     REQUIRE(manifest.Channel == "release");
    775     REQUIRE(manifest.DefaultInstallerInfo.MinOSVersion == "0.0.0.0");
    776     REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>() == MultiValue{ "msix", "appx" });
    777     REQUIRE(manifest.DefaultInstallerInfo.Commands == MultiValue{ "makemsix", "makeappx" });
    778     REQUIRE(manifest.DefaultInstallerInfo.Protocols == MultiValue{ "protocol1", "protocol2" });
    779     REQUIRE(manifest.DefaultInstallerInfo.FileExtensions == MultiValue{ "appx", "appxbundle", "msix", "msixbundle" });
    780 }
    781 
    782 TEST_CASE("ReadGoodManifests", "[ManifestValidation]")
    783 {
    784     ManifestTestCase TestCases[] =
    785     {
    786         { "Manifest-Good-InstallerTypeExeRoot-Silent.yaml" },
    787         { "Manifest-Good-InstallerTypeExeRoot-SilentRoot.yaml" },
    788         { "Manifest-Good-InstallerTypeExe-Silent.yaml" },
    789         { "Manifest-Good-InstallerTypeExe-SilentRoot.yaml" },
    790         { "Manifest-Good-InstallerUniqueness-DefaultLang.yaml" },
    791         { "Manifest-Good-InstallerUniqueness-DiffLangs.yaml" },
    792         { "Manifest-Good-InstallerUniqueness-DiffScope.yaml" },
    793         { "Manifest-Good-Minimum.yaml" },
    794         { "Manifest-Good-Minimum-InstallerType.yaml" },
    795         { "Manifest-Good-Switches.yaml" },
    796         { "Manifest-Good-DefaultExpectedReturnCodeInInstallerSuccessCodes.yaml" },
    797         { "Manifest-Good-InstallerTypeZip-PortableExe.yaml" },
    798     };
    799 
    800     for (auto const& testCase : TestCases)
    801     {
    802         TestManifest(testCase.TestFile);
    803     }
    804 }
    805 
    806 TEST_CASE("ReadBadManifests", "[ManifestValidation]")
    807 {
    808     ManifestTestCase TestCases[] =
    809     {
    810         { "Manifest-Bad-ArchInvalid.yaml", "Invalid field value. [Architecture]" },
    811         { "Manifest-Bad-ArchMissing.yaml", "Missing required property 'Arch'" },
    812         { "Manifest-Bad-Channel-NotSupported.yaml", "Field is not supported. [Channel]" },
    813         { "Manifest-Bad-DifferentCase-camelCase.yaml", "All field names should be PascalCased. [installerType]" },
    814         { "Manifest-Bad-DifferentCase-lower.yaml", "All field names should be PascalCased. [installertype]" },
    815         { "Manifest-Bad-DifferentCase-UPPER.yaml", "All field names should be PascalCased. [INSTALLERTYPE]" },
    816         { "Manifest-Bad-DuplicateKey.yaml", "Duplicate field found in the manifest." },
    817         { "Manifest-Bad-DuplicateKey-DifferentCase.yaml", "Duplicate field found in the manifest." },
    818         { "Manifest-Bad-DuplicateKey-DifferentCase-lower.yaml", "Duplicate field found in the manifest." },
    819         { "Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml", "Duplicate installer return code found." },
    820         { "Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml", "Duplicate installer return code found." },
    821         { "Manifest-Bad-DuplicateSha256.yaml", "Multiple Installer URLs found with the same InstallerSha256. Please ensure the accuracy of the URLs.", true },
    822         { "Manifest-Bad-IdInvalid.yaml", "Failed to validate against schema associated with property name 'Id'" },
    823         { "Manifest-Bad-IdMissing.yaml", "Missing required property 'Id'" },
    824         { "Manifest-Bad-InconsistentSha256.yaml", "The values of InstallerSha256 do not match for all instances of the same InstallerUrl." },
    825         { "Manifest-Bad-InstallersMissing.yaml", "Missing required property 'Installers'" },
    826         { "Manifest-Bad-InstallerTypeExe-NoSilent.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
    827         { "Manifest-Bad-InstallerTypeExe-NoSilentRoot.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
    828         { "Manifest-Bad-InstallerTypeExeRoot-NoSilent.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
    829         { "Manifest-Bad-InstallerTypeExeRoot-NoSilentRoot.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
    830         { "Manifest-Bad-InstallerTypeInvalid.yaml", "Invalid field value. [InstallerType]" },
    831         { "Manifest-Bad-InstallerTypeMissing.yaml", "Invalid field value. [InstallerType]" },
    832         { "Manifest-Bad-InstallerTypePortable-InvalidAppsAndFeatures.yaml", "Only zero or one entry for Apps and Features may be specified for InstallerType portable." },
    833         { "Manifest-Bad-InstallerTypePortable-InvalidCommands.yaml", "Only zero or one value for Commands may be specified for InstallerType portable." },
    834         { "Manifest-Bad-InstallerTypePortable-InvalidScope.yaml", "Scope is not supported for InstallerType portable." },
    835         { "Manifest-Bad-InstallerTypeZip-DuplicateCommandAlias.yaml", "Duplicate portable command alias found." },
    836         { "Manifest-Bad-InstallerTypeZip-DuplicateRelativeFilePath.yaml", "Duplicate relative file path found." },
    837         { "Manifest-Bad-InstallerTypeZip-InvalidRelativeFilePath.yaml", "Relative file path must not point to a location outside of archive directory" },
    838         { "Manifest-Bad-InstallerTypeZip-MissingRelativeFilePath.yaml", "Required field missing. [RelativeFilePath]" },
    839         { "Manifest-Bad-InstallerTypeZip-MultipleNestedInstallers.yaml", "Only one entry for NestedInstallerFiles can be specified for non-portable InstallerTypes." },
    840         { "Manifest-Bad-InstallerTypeZip-NoNestedInstallerFile.yaml", "Required field missing. [NestedInstallerFiles]" },
    841         { "Manifest-Bad-InstallerTypeZip-NoNestedInstallerType.yaml", "Required field missing. [NestedInstallerType]" },
    842         { "Manifest-Bad-InstallerUniqueness.yaml", "Duplicate installer entry found." },
    843         { "Manifest-Bad-InstallerUniqueness-DefaultScope.yaml", "Duplicate installer entry found." },
    844         { "Manifest-Bad-InstallerUniqueness-DefaultValues.yaml", "Duplicate installer entry found." },
    845         { "Manifest-Bad-InstallerUniqueness-SameLang.yaml", "Duplicate installer entry found." },
    846         { "Manifest-Bad-LicenseMissing.yaml", "Missing required property 'License'" },
    847         { "Manifest-Bad-NameMissing.yaml", "Missing required property 'Name'" },
    848         { "Manifest-Bad-PublisherMissing.yaml", "Missing required property 'Publisher'" },
    849         { "Manifest-Bad-Sha256Invalid.yaml", "Failed to validate against schema associated with property name 'Sha256'" },
    850         { "Manifest-Bad-Sha256Missing.yaml", "Required field missing. [InstallerSha256]" },
    851         { "Manifest-Bad-SwitchInvalid.yaml", "Unknown field. [NotASwitch]", true },
    852         { "Manifest-Bad-UnknownProperty.yaml", "Unknown field. [Fake]", true },
    853         { "Manifest-Bad-UnsupportedVersion.yaml", "Unsupported ManifestVersion" },
    854         { "Manifest-Bad-UrlInvalid.yaml", "Invalid field value. [InstallerUrl]" },
    855         { "Manifest-Bad-UrlMissing.yaml", "Required field missing. [InstallerUrl]" },
    856         { "Manifest-Bad-VersionInvalid.yaml", "Failed to validate against schema associated with property name 'Version'" },
    857         { "Manifest-Bad-VersionMissing.yaml", "Missing required property 'Version'" },
    858         { "Manifest-Bad-InvalidManifestVersionValue.yaml", "Failed to validate against schema associated with property name 'ManifestVersion'" },
    859         { "InstallFlowTest_MSStore.yaml", "Field value is not supported. [InstallerType] Value: msstore" },
    860         { "Manifest-Bad-PackageFamilyNameOnMSI.yaml", "The specified installer type does not support PackageFamilyName. [InstallerType] Value: msi", true },
    861         { "Manifest-Bad-ProductCodeOnMSIX.yaml", "The specified installer type does not support ProductCode. [InstallerType] Value: msix" },
    862         { "Manifest-Bad-InvalidUpdateBehavior.yaml", "Invalid field value. [UpgradeBehavior]" },
    863         { "Manifest-Bad-InvalidLocale.yaml", "The locale value is not a well formed bcp47 language tag." },
    864         { "Manifest-Bad-AppsAndFeaturesEntriesOnMSIX.yaml", "The specified installer type does not write to Apps and Features entry." },
    865         { "InstallFlowTest_LicenseAgreement.yaml", "Field usage requires verified publishers. [Agreement]", true },
    866         { "InstallFlowTest_LicenseAgreement.yaml", "Field usage requires verified publishers. [Agreement]", false, GetTestManifestValidateOption(false, true) },
    867         { "Manifest-Bad-ApproximateVersionInPackageVersion.yaml", "Approximate version not allowed. [PackageVersion]" },
    868         { "Manifest-Bad-ApproximateVersionInArpVersion.yaml", "Approximate version not allowed. [DisplayVersion]" },
    869         { "Manifest-Bad-InstallerTypeZip-PortableNotExe.yaml", "The file type of the referenced file is not allowed. [RelativeFilePath] Value: ScriptedApplication.bat" },
    870         { "Manifest-Bad-InstallerTypeZip-PortableNotExe_Root.yaml", "The file type of the referenced file is not allowed. [RelativeFilePath] Value: ScriptedApplication.bat" },
    871     };
    872 
    873     for (auto const& testCase : TestCases)
    874     {
    875         TestManifest(testCase.TestFile, testCase.ExpectedMessage, testCase.IsWarningOnly, testCase.ValidateOption);
    876     }
    877 }
    878 
    879 TEST_CASE("ManifestEncoding", "[ManifestValidation]")
    880 {
    881     ManifestTestCase TestCases[] =
    882     {
    883         { "Manifest-Encoding-ANSI.yaml" },
    884         { "Manifest-Encoding-UTF8.yaml" },
    885         { "Manifest-Encoding-UTF8-BOM.yaml" },
    886         { "Manifest-Encoding-UTF16BE.yaml" },
    887         { "Manifest-Encoding-UTF16BE-BOM.yaml" },
    888         { "Manifest-Encoding-UTF16LE.yaml" },
    889         { "Manifest-Encoding-UTF16LE-BOM.yaml" },
    890     };
    891 
    892     for (auto const& testCase : TestCases)
    893     {
    894         INFO(testCase.TestFile);
    895         Manifest manifest = YamlParser::CreateFromPath(TestDataFile(testCase.TestFile), GetTestManifestValidateOption());
    896         REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == u8"MSIX SDK\xA9");
    897     }
    898 }
    899 
    900 TEST_CASE("ComplexSystemReference", "[ManifestValidation]")
    901 {
    902     Manifest manifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-SystemReferenceComplex.yaml"));
    903 
    904     REQUIRE(manifest.Installers.size() == 4);
    905 
    906     // MSIX installer does inherit
    907     auto& installer = manifest.Installers[0];
    908     REQUIRE(installer.BaseInstallerType == InstallerTypeEnum::Msix);
    909     REQUIRE(installer.Arch == Architecture::X86);
    910     REQUIRE(installer.PackageFamilyName == "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe");
    911     REQUIRE(installer.ProductCode == "");
    912 
    913     // MSI installer does inherit
    914     auto& installer1 = manifest.Installers[1];
    915     REQUIRE(installer1.BaseInstallerType == InstallerTypeEnum::Msi);
    916     REQUIRE(installer1.Arch == Architecture::X86);
    917     REQUIRE(installer1.PackageFamilyName == "");
    918     REQUIRE(installer1.ProductCode == "{Foo}");
    919 
    920     // MSIX installer with override
    921     auto& installer2 = manifest.Installers[2];
    922     REQUIRE(installer2.BaseInstallerType == InstallerTypeEnum::Msix);
    923     REQUIRE(installer2.Arch == Architecture::X64);
    924     REQUIRE(installer2.PackageFamilyName == "Override_8wekyb3d8bbwe");
    925     REQUIRE(installer2.ProductCode == "");
    926 
    927     // MSI installer with override
    928     auto& installer3 = manifest.Installers[3];
    929     REQUIRE(installer3.BaseInstallerType == InstallerTypeEnum::Msi);
    930     REQUIRE(installer3.Arch == Architecture::X64);
    931     REQUIRE(installer3.PackageFamilyName == "");
    932     REQUIRE(installer3.ProductCode == "Override");
    933 }
    934 
    935 TEST_CASE("ManifestVersionExtensions", "[ManifestValidation]")
    936 {
    937     REQUIRE(!ManifestVer("1.0.0"sv).HasExtension("msstore"));
    938     REQUIRE(!ManifestVer("1.0.0-other"sv).HasExtension("msstore"));
    939     REQUIRE(!ManifestVer("1.0.0-other-other2"sv).HasExtension("msstore"));
    940 
    941     REQUIRE(ManifestVer("1.0.0-msstore"sv).HasExtension("msstore"));
    942     REQUIRE(ManifestVer("1.0.0-msstore.2"sv).HasExtension("msstore"));
    943     REQUIRE(ManifestVer("1.0.0-other-msstore.2"sv).HasExtension("msstore"));
    944     REQUIRE(ManifestVer("1.0.0-msstore.2-other"sv).HasExtension("msstore"));
    945 }
    946 
    947 TEST_CASE("ValidateV1GoodManifestAndVerifyContents", "[ManifestValidation]")
    948 {
    949     ManifestValidateOption validateOption;
    950     validateOption.FullValidation = true;
    951     TempDirectory singletonDirectory{ "SingletonManifest" };
    952     CopyTestDataFilesToFolder({ "ManifestV1-Singleton.yaml" }, singletonDirectory);
    953     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
    954     VerifyV1ManifestContent(singletonManifest, true);
    955 
    956     TempDirectory multiFileDirectory{ "MultiFileManifest" };
    957     CopyTestDataFilesToFolder({
    958         "ManifestV1-MultiFile-Version.yaml",
    959         "ManifestV1-MultiFile-Installer.yaml",
    960         "ManifestV1-MultiFile-DefaultLocale.yaml",
    961         "ManifestV1-MultiFile-Locale.yaml" }, multiFileDirectory);
    962 
    963     TempFile mergedManifestFile{ "merged.yaml" };
    964     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
    965     VerifyV1ManifestContent(multiFileManifest, false);
    966 
    967     // Read from merged manifest should have the same content as multi file manifest
    968     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
    969     VerifyV1ManifestContent(mergedManifest, false);
    970 }
    971 
    972 TEST_CASE("ValidateV1_1GoodManifestAndVerifyContents", "[ManifestValidation]")
    973 {
    974     ManifestValidateOption validateOption;
    975     validateOption.FullValidation = true;
    976     TempDirectory singletonDirectory{ "SingletonManifest" };
    977     CopyTestDataFilesToFolder({ "ManifestV1_1-Singleton.yaml" }, singletonDirectory);
    978     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
    979     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_1 });
    980 
    981     TempDirectory multiFileDirectory{ "MultiFileManifest" };
    982     CopyTestDataFilesToFolder({
    983         "ManifestV1_1-MultiFile-Version.yaml",
    984         "ManifestV1_1-MultiFile-Installer.yaml",
    985         "ManifestV1_1-MultiFile-DefaultLocale.yaml",
    986         "ManifestV1_1-MultiFile-Locale.yaml" }, multiFileDirectory);
    987 
    988     TempFile mergedManifestFile{ "merged.yaml" };
    989     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
    990     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_1 });
    991 
    992     // Read from merged manifest should have the same content as multi file manifest
    993     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
    994     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_1 });
    995 }
    996 
    997 TEST_CASE("ValidateV1_2GoodManifestAndVerifyContents", "[ManifestValidation]")
    998 {
    999     ManifestValidateOption validateOption;
   1000     validateOption.FullValidation = true;
   1001     TempDirectory singletonDirectory{ "SingletonManifest" };
   1002     CopyTestDataFilesToFolder({ "ManifestV1_2-Singleton.yaml" }, singletonDirectory);
   1003     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1004     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_2 });
   1005 
   1006     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1007     CopyTestDataFilesToFolder({
   1008         "ManifestV1_2-MultiFile-Version.yaml",
   1009         "ManifestV1_2-MultiFile-Installer.yaml",
   1010         "ManifestV1_2-MultiFile-DefaultLocale.yaml",
   1011         "ManifestV1_2-MultiFile-Locale.yaml" }, multiFileDirectory);
   1012 
   1013     TempFile mergedManifestFile{ "merged.yaml" };
   1014     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1015     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_2 });
   1016 
   1017     // Read from merged manifest should have the same content as multi file manifest
   1018     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1019     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_2 });
   1020 }
   1021 
   1022 TEST_CASE("ValidateV1_4GoodManifestAndVerifyContents", "[ManifestValidation]")
   1023 {
   1024     ManifestValidateOption validateOption;
   1025     validateOption.FullValidation = true;
   1026     TempDirectory singletonDirectory{ "SingletonManifest" };
   1027     CopyTestDataFilesToFolder({ "ManifestV1_4-Singleton.yaml" }, singletonDirectory);
   1028     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1029     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_4 });
   1030 
   1031     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1032     CopyTestDataFilesToFolder({
   1033         "ManifestV1_4-MultiFile-Version.yaml",
   1034         "ManifestV1_4-MultiFile-Installer.yaml",
   1035         "ManifestV1_4-MultiFile-DefaultLocale.yaml",
   1036         "ManifestV1_4-MultiFile-Locale.yaml" }, multiFileDirectory);
   1037 
   1038     TempFile mergedManifestFile{ "merged.yaml" };
   1039     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1040     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_4 });
   1041 
   1042     // Read from merged manifest should have the same content as multi file manifest
   1043     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1044     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_4 });
   1045 }
   1046 
   1047 TEST_CASE("ValidateV1_5GoodManifestAndVerifyContents", "[ManifestValidation]")
   1048 {
   1049     ManifestValidateOption validateOption;
   1050     validateOption.FullValidation = true;
   1051     TempDirectory singletonDirectory{ "SingletonManifest" };
   1052     CopyTestDataFilesToFolder({ "ManifestV1_5-Singleton.yaml" }, singletonDirectory);
   1053     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1054     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_5 });
   1055 
   1056     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1057     CopyTestDataFilesToFolder({
   1058         "ManifestV1_5-MultiFile-Version.yaml",
   1059         "ManifestV1_5-MultiFile-Installer.yaml",
   1060         "ManifestV1_5-MultiFile-DefaultLocale.yaml",
   1061         "ManifestV1_5-MultiFile-Locale.yaml" }, multiFileDirectory);
   1062 
   1063     TempFile mergedManifestFile{ "merged.yaml" };
   1064     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1065     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_5 });
   1066 
   1067     // Read from merged manifest should have the same content as multi file manifest
   1068     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1069     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_5 });
   1070 }
   1071 
   1072 TEST_CASE("ValidateV1_6GoodManifestAndVerifyContents", "[ManifestValidation]")
   1073 {
   1074     ManifestValidateOption validateOption;
   1075     validateOption.FullValidation = true;
   1076     TempDirectory singletonDirectory{ "SingletonManifest" };
   1077     CopyTestDataFilesToFolder({ "ManifestV1_6-Singleton.yaml" }, singletonDirectory);
   1078     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1079     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_6 });
   1080 
   1081     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1082     CopyTestDataFilesToFolder({
   1083         "ManifestV1_6-MultiFile-Version.yaml",
   1084         "ManifestV1_6-MultiFile-Installer.yaml",
   1085         "ManifestV1_6-MultiFile-DefaultLocale.yaml",
   1086         "ManifestV1_6-MultiFile-Locale.yaml" }, multiFileDirectory);
   1087 
   1088     TempFile mergedManifestFile{ "merged.yaml" };
   1089     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1090     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_6 });
   1091 
   1092     // Read from merged manifest should have the same content as multi file manifest
   1093     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1094     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_6 });
   1095 }
   1096 
   1097 TEST_CASE("ValidateV1_7GoodManifestAndVerifyContents", "[ManifestValidation]")
   1098 {
   1099     ManifestValidateOption validateOption;
   1100     validateOption.FullValidation = true;
   1101     TempDirectory singletonDirectory{ "SingletonManifest" };
   1102     CopyTestDataFilesToFolder({ "ManifestV1_7-Singleton.yaml" }, singletonDirectory);
   1103     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1104     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_7 });
   1105 
   1106     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1107     CopyTestDataFilesToFolder({
   1108         "ManifestV1_7-MultiFile-Version.yaml",
   1109         "ManifestV1_7-MultiFile-Installer.yaml",
   1110         "ManifestV1_7-MultiFile-DefaultLocale.yaml",
   1111         "ManifestV1_7-MultiFile-Locale.yaml" }, multiFileDirectory);
   1112 
   1113     TempFile mergedManifestFile{ "merged.yaml" };
   1114     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1115     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_7 });
   1116 
   1117     // Read from merged manifest should have the same content as multi file manifest
   1118     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1119     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_7 });
   1120 }
   1121 
   1122 TEST_CASE("ValidateV1_9GoodManifestAndVerifyContents", "[ManifestValidation]")
   1123 {
   1124     ManifestValidateOption validateOption;
   1125     validateOption.FullValidation = true;
   1126     TempDirectory singletonDirectory{ "SingletonManifest" };
   1127     CopyTestDataFilesToFolder({ "ManifestV1_9-Singleton.yaml" }, singletonDirectory);
   1128     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1129     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_9 });
   1130 
   1131     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1132     CopyTestDataFilesToFolder({
   1133         "ManifestV1_9-MultiFile-Version.yaml",
   1134         "ManifestV1_9-MultiFile-Installer.yaml",
   1135         "ManifestV1_9-MultiFile-DefaultLocale.yaml",
   1136         "ManifestV1_9-MultiFile-Locale.yaml" }, multiFileDirectory);
   1137 
   1138     TempFile mergedManifestFile{ "merged.yaml" };
   1139     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1140     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_9 });
   1141 
   1142     // Read from merged manifest should have the same content as multi file manifest
   1143     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1144     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_9 });
   1145 }
   1146 
   1147 TEST_CASE("ValidateV1_10GoodManifestAndVerifyContents", "[ManifestValidation]")
   1148 {
   1149     ManifestValidateOption validateOption;
   1150     validateOption.FullValidation = true;
   1151     TempDirectory singletonDirectory{ "SingletonManifest" };
   1152     CopyTestDataFilesToFolder({ "ManifestV1_10-Singleton.yaml" }, singletonDirectory);
   1153     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1154     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_10 });
   1155 
   1156     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1157     CopyTestDataFilesToFolder({
   1158         "ManifestV1_10-MultiFile-Version.yaml",
   1159         "ManifestV1_10-MultiFile-Installer.yaml",
   1160         "ManifestV1_10-MultiFile-DefaultLocale.yaml",
   1161         "ManifestV1_10-MultiFile-Locale.yaml" }, multiFileDirectory);
   1162 
   1163     TempFile mergedManifestFile{ "merged.yaml" };
   1164     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1165     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_10 });
   1166 
   1167     // Read from merged manifest should have the same content as multi file manifest
   1168     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1169     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_10 });
   1170 }
   1171 
   1172 TEST_CASE("ValidateV1_12GoodManifestAndVerifyContents", "[ManifestValidation]")
   1173 {
   1174     ManifestValidateOption validateOption;
   1175     validateOption.FullValidation = true;
   1176     TempDirectory singletonDirectory{ "SingletonManifest" };
   1177     CopyTestDataFilesToFolder({ "ManifestV1_12-Singleton.yaml" }, singletonDirectory);
   1178     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory, validateOption);
   1179     VerifyV1ManifestContent(singletonManifest, true, ManifestVer{ s_ManifestVersionV1_12 });
   1180 
   1181     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1182     CopyTestDataFilesToFolder({
   1183         "ManifestV1_12-MultiFile-Version.yaml",
   1184         "ManifestV1_12-MultiFile-Installer.yaml",
   1185         "ManifestV1_12-MultiFile-DefaultLocale.yaml",
   1186         "ManifestV1_12-MultiFile-Locale.yaml" }, multiFileDirectory);
   1187 
   1188     TempFile mergedManifestFile{ "merged.yaml" };
   1189     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1190     VerifyV1ManifestContent(multiFileManifest, false, ManifestVer{ s_ManifestVersionV1_12 });
   1191 
   1192     // Read from merged manifest should have the same content as multi file manifest
   1193     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1194     VerifyV1ManifestContent(mergedManifest, false, ManifestVer{ s_ManifestVersionV1_12 });
   1195 }
   1196 
   1197 TEST_CASE("WriteV1SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1198 {
   1199     TempDirectory singletonDirectory{ "SingletonManifest" };
   1200     CopyTestDataFilesToFolder({ "ManifestV1_1-Singleton.yaml" }, singletonDirectory);
   1201     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1202 
   1203     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1204     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1205     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1206 
   1207     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1208     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1209     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1 }, true);
   1210 
   1211     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1212     CopyTestDataFilesToFolder({
   1213         "ManifestV1-MultiFile-Version.yaml",
   1214         "ManifestV1-MultiFile-Installer.yaml",
   1215         "ManifestV1-MultiFile-DefaultLocale.yaml",
   1216         "ManifestV1-MultiFile-Locale.yaml" }, multiFileDirectory);
   1217 
   1218     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1219     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1220     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1221     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1222 
   1223     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1224     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1225     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1 }, true);
   1226 }
   1227 
   1228 TEST_CASE("WriteV1_1SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1229 {
   1230     TempDirectory singletonDirectory{ "SingletonManifest" };
   1231     CopyTestDataFilesToFolder({ "ManifestV1_1-Singleton.yaml" }, singletonDirectory);
   1232     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1233 
   1234     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1235     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1236     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1237 
   1238     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1239     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1240     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_1 }, true);
   1241 
   1242     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1243     CopyTestDataFilesToFolder({
   1244         "ManifestV1_1-MultiFile-Version.yaml",
   1245         "ManifestV1_1-MultiFile-Installer.yaml",
   1246         "ManifestV1_1-MultiFile-DefaultLocale.yaml",
   1247         "ManifestV1_1-MultiFile-Locale.yaml" }, multiFileDirectory);
   1248 
   1249     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1250     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1251     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1252     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1253 
   1254     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1255     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1256     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_1 }, true);
   1257 }
   1258 
   1259 TEST_CASE("WriteV1_2SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1260 {
   1261     TempDirectory singletonDirectory{ "SingletonManifest" };
   1262     CopyTestDataFilesToFolder({ "ManifestV1_2-Singleton.yaml" }, singletonDirectory);
   1263     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1264 
   1265     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1266     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1267     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1268 
   1269     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1270     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1271     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_2 }, true);
   1272 
   1273     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1274     CopyTestDataFilesToFolder({
   1275         "ManifestV1_2-MultiFile-Version.yaml",
   1276         "ManifestV1_2-MultiFile-Installer.yaml",
   1277         "ManifestV1_2-MultiFile-DefaultLocale.yaml",
   1278         "ManifestV1_2-MultiFile-Locale.yaml" }, multiFileDirectory);
   1279 
   1280     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1281     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1282     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1283     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1284 
   1285     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1286     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1287     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_2 }, true);
   1288 }
   1289 
   1290 TEST_CASE("WriteV1_4SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1291 {
   1292     TempDirectory singletonDirectory{ "SingletonManifest" };
   1293     CopyTestDataFilesToFolder({ "ManifestV1_4-Singleton.yaml" }, singletonDirectory);
   1294     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1295 
   1296     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1297     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1298     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1299 
   1300     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1301     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1302     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_4 }, true);
   1303 
   1304     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1305     CopyTestDataFilesToFolder({
   1306         "ManifestV1_4-MultiFile-Version.yaml",
   1307         "ManifestV1_4-MultiFile-Installer.yaml",
   1308         "ManifestV1_4-MultiFile-DefaultLocale.yaml",
   1309         "ManifestV1_4-MultiFile-Locale.yaml" }, multiFileDirectory);
   1310 
   1311     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1312     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1313     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1314     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1315 
   1316     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1317     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1318     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_4 }, true);
   1319 }
   1320 
   1321 TEST_CASE("WriteV1_5SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1322 {
   1323     TempDirectory singletonDirectory{ "SingletonManifest" };
   1324     CopyTestDataFilesToFolder({ "ManifestV1_5-Singleton.yaml" }, singletonDirectory);
   1325     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1326 
   1327     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1328     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1329     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1330 
   1331     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1332     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1333     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_5 }, true);
   1334 
   1335     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1336     CopyTestDataFilesToFolder({
   1337         "ManifestV1_5-MultiFile-Version.yaml",
   1338         "ManifestV1_5-MultiFile-Installer.yaml",
   1339         "ManifestV1_5-MultiFile-DefaultLocale.yaml",
   1340         "ManifestV1_5-MultiFile-Locale.yaml" }, multiFileDirectory);
   1341 
   1342     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1343     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1344     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1345     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1346 
   1347     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1348     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1349     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_5 }, true);
   1350 }
   1351 
   1352 TEST_CASE("WriteV1_6SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1353 {
   1354     TempDirectory singletonDirectory{ "SingletonManifest" };
   1355     CopyTestDataFilesToFolder({ "ManifestV1_6-Singleton.yaml" }, singletonDirectory);
   1356     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1357 
   1358     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1359     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1360     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1361 
   1362     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1363     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1364     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_6 }, true);
   1365 
   1366     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1367     CopyTestDataFilesToFolder({
   1368         "ManifestV1_6-MultiFile-Version.yaml",
   1369         "ManifestV1_6-MultiFile-Installer.yaml",
   1370         "ManifestV1_6-MultiFile-DefaultLocale.yaml",
   1371         "ManifestV1_6-MultiFile-Locale.yaml" }, multiFileDirectory);
   1372 
   1373     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1374     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1375     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1376     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1377 
   1378     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1379     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1380     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_6 }, true);
   1381 }
   1382 
   1383 TEST_CASE("WriteV1_7SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1384 {
   1385     TempDirectory singletonDirectory{ "SingletonManifest" };
   1386     CopyTestDataFilesToFolder({ "ManifestV1_7-Singleton.yaml" }, singletonDirectory);
   1387     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1388 
   1389     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1390     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1391     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1392 
   1393     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1394     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1395     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_7 }, true);
   1396 
   1397     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1398     CopyTestDataFilesToFolder({
   1399         "ManifestV1_7-MultiFile-Version.yaml",
   1400         "ManifestV1_7-MultiFile-Installer.yaml",
   1401         "ManifestV1_7-MultiFile-DefaultLocale.yaml",
   1402         "ManifestV1_7-MultiFile-Locale.yaml" }, multiFileDirectory);
   1403 
   1404     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1405     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1406     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1407     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1408 
   1409     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1410     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1411     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_7 }, true);
   1412 }
   1413 
   1414 TEST_CASE("WriteV1_9SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1415 {
   1416     TempDirectory singletonDirectory{ "SingletonManifest" };
   1417     CopyTestDataFilesToFolder({ "ManifestV1_9-Singleton.yaml" }, singletonDirectory);
   1418     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1419 
   1420     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1421     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1422     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1423 
   1424     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1425     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1426     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_9 }, true);
   1427 
   1428     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1429     CopyTestDataFilesToFolder({
   1430         "ManifestV1_9-MultiFile-Version.yaml",
   1431         "ManifestV1_9-MultiFile-Installer.yaml",
   1432         "ManifestV1_9-MultiFile-DefaultLocale.yaml",
   1433         "ManifestV1_9-MultiFile-Locale.yaml" }, multiFileDirectory);
   1434 
   1435     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1436     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1437     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1438     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1439 
   1440     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1441     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1442     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_9 }, true);
   1443 }
   1444 
   1445 TEST_CASE("WriteV1_10SingletonManifestAndVerifyContents", "[ManifestCreation]")
   1446 {
   1447     TempDirectory singletonDirectory{ "SingletonManifest" };
   1448     CopyTestDataFilesToFolder({ "ManifestV1_10-Singleton.yaml" }, singletonDirectory);
   1449     Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);
   1450 
   1451     TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
   1452     std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
   1453     YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);
   1454 
   1455     REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
   1456     Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
   1457     VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_10 }, true);
   1458 
   1459     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1460     CopyTestDataFilesToFolder({
   1461         "ManifestV1_10-MultiFile-Version.yaml",
   1462         "ManifestV1_10-MultiFile-Installer.yaml",
   1463         "ManifestV1_10-MultiFile-DefaultLocale.yaml",
   1464         "ManifestV1_10-MultiFile-Locale.yaml" }, multiFileDirectory);
   1465 
   1466     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
   1467     TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
   1468     std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
   1469     YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);
   1470 
   1471     REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
   1472     Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
   1473     VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_10 }, true);
   1474 }
   1475 
   1476 // Since Authentication is not supported in community repo and will cause manifest validation failure,
   1477 // we are not adding Authentication in v1_10 manifests. Instead a separate test is created for Authentication.
   1478 TEST_CASE("ReadWriteValidateV1_10ManifestWithInstallerAuthentication", "[ManifestValidation]")
   1479 {
   1480     // Read manifest
   1481     TempDirectory testDirectory{ "TestManifest" };
   1482     CopyTestDataFilesToFolder({ "ManifestV1_10-InstallerAuthentication.yaml" }, testDirectory);
   1483     Manifest testManifest = YamlParser::CreateFromPath(testDirectory);
   1484 
   1485     // Verify content
   1486     REQUIRE(testManifest.ManifestVersion == AppInstaller::Manifest::ManifestVer{ s_ManifestVersionV1_10 });
   1487     REQUIRE(testManifest.DefaultInstallerInfo.AuthInfo.Type == AppInstaller::Authentication::AuthenticationType::MicrosoftEntraId);
   1488     REQUIRE(testManifest.DefaultInstallerInfo.AuthInfo.MicrosoftEntraIdInfo);
   1489     REQUIRE(testManifest.DefaultInstallerInfo.AuthInfo.MicrosoftEntraIdInfo->Resource == "TestResource");
   1490     REQUIRE(testManifest.DefaultInstallerInfo.AuthInfo.MicrosoftEntraIdInfo->Scope == "TestScope");
   1491     REQUIRE(testManifest.Installers.size() == 1);
   1492     REQUIRE(testManifest.Installers[0].AuthInfo.Type == AppInstaller::Authentication::AuthenticationType::MicrosoftEntraIdForAzureBlobStorage);
   1493     REQUIRE(testManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo);
   1494     REQUIRE(testManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo->Resource == "https://storage.azure.com/");
   1495     REQUIRE(testManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo->Scope.empty());
   1496 
   1497     // Manifest Validation. Only error is "Authentication not supported".
   1498     auto errors = ValidateManifest(testManifest, true);
   1499     REQUIRE(errors.size() == 1);
   1500     REQUIRE(errors[0].GetErrorMessage() == "Field is not supported.");
   1501     REQUIRE(errors[0].Context == "Authentication");
   1502 
   1503     // Write manifest
   1504     TempDirectory exportedDirectory{ "ExportedManifest" };
   1505     std::filesystem::path exportedManifestPath = exportedDirectory.GetPath() / "ExportedManifest.yaml";
   1506     YamlWriter::OutputYamlFile(testManifest, testManifest.Installers[0], exportedManifestPath);
   1507 
   1508     // Read back and validate content
   1509     REQUIRE(std::filesystem::exists(exportedManifestPath));
   1510     Manifest exportedManifest = YamlParser::CreateFromPath(exportedDirectory);
   1511     REQUIRE(testManifest.ManifestVersion == AppInstaller::Manifest::ManifestVer{ s_ManifestVersionV1_10 });
   1512     REQUIRE(exportedManifest.Installers.size() == 1);
   1513     REQUIRE(exportedManifest.Installers[0].AuthInfo.Type == AppInstaller::Authentication::AuthenticationType::MicrosoftEntraIdForAzureBlobStorage);
   1514     REQUIRE(exportedManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo);
   1515     REQUIRE(exportedManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo->Resource == "https://storage.azure.com/");
   1516     REQUIRE(exportedManifest.Installers[0].AuthInfo.MicrosoftEntraIdInfo->Scope.empty());
   1517 }
   1518 
   1519 TEST_CASE("WriteManifestWithMultipleLocale", "[ManifestCreation]")
   1520 {
   1521     Manifest multiLocaleManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-MultiLocale.yaml"));
   1522     TempDirectory exportedDirectory{ "exported" };
   1523     std::filesystem::path generatedManifestPath = exportedDirectory.GetPath() / "testManifestWithMultipleLocale.yaml";
   1524     YamlWriter::OutputYamlFile(multiLocaleManifest, multiLocaleManifest.Installers[0], generatedManifestPath);
   1525 
   1526     REQUIRE(std::filesystem::exists(generatedManifestPath));
   1527     Manifest generatedManifest = YamlParser::CreateFromPath(generatedManifestPath);
   1528     REQUIRE(generatedManifest.Localizations.size() == 2);
   1529 }
   1530 
   1531 TEST_CASE("WriteManifestWithMSStoreInstaller", "[ManifestCreation]")
   1532 {
   1533     Manifest msstoreManifest = YamlParser::CreateFromPath(TestDataFile("DownloadFlowTest_MSStore.yaml"));
   1534     TempDirectory exportedDirectory{ "exported" };
   1535     std::filesystem::path generatedManifestPath = exportedDirectory.GetPath() / "testManifestWithMultipleLocale.yaml";
   1536     msstoreManifest.ManifestVersion = ManifestVer{ "1.1.0" };
   1537     YamlWriter::OutputYamlFile(msstoreManifest, msstoreManifest.Installers[0], generatedManifestPath);
   1538 
   1539     REQUIRE(std::filesystem::exists(generatedManifestPath));
   1540     Manifest generatedManifest = YamlParser::CreateFromPath(generatedManifestPath);
   1541     REQUIRE(generatedManifest.Installers[0].BaseInstallerType == InstallerTypeEnum::MSStore);
   1542     REQUIRE(!generatedManifest.Installers[0].ProductId.empty());
   1543 }
   1544 
   1545 YamlManifestInfo CreateYamlManifestInfo(std::string testDataFile)
   1546 {
   1547     YamlManifestInfo result;
   1548     result.Root = AppInstaller::YAML::Load(TestDataFile(testDataFile));
   1549     result.FileName = testDataFile;
   1550     return result;
   1551 }
   1552 
   1553 TEST_CASE("MultifileManifestInputValidation", "[ManifestValidation]")
   1554 {
   1555     auto previewManifest = CreateYamlManifestInfo("Manifest-Good.yaml");
   1556     auto v1SingletonManifest = CreateYamlManifestInfo("ManifestV1-Singleton.yaml");
   1557     auto v1VersionManifest = CreateYamlManifestInfo("ManifestV1-MultiFile-Version.yaml");
   1558     auto v1InstallerManifest = CreateYamlManifestInfo("ManifestV1-MultiFile-Installer.yaml");
   1559     auto v1DefaultLocaleManifest = CreateYamlManifestInfo("ManifestV1-MultiFile-DefaultLocale.yaml");
   1560     auto v1LocaleManifest = CreateYamlManifestInfo("ManifestV1-MultiFile-Locale.yaml");
   1561 
   1562     {
   1563         // Preview and multi file manifest together
   1564         std::vector<YamlManifestInfo> input = { previewManifest, v1VersionManifest, v1InstallerManifest, v1DefaultLocaleManifest };
   1565         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("Preview manifest does not support multi file manifest format"));
   1566     }
   1567 
   1568     {
   1569         // Singleton and multi file manifest together
   1570         std::vector<YamlManifestInfo> input = { v1SingletonManifest, v1VersionManifest, v1InstallerManifest, v1DefaultLocaleManifest };
   1571         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest should not contain file with the particular ManifestType. [ManifestType] Value: singleton"));
   1572     }
   1573 
   1574     {
   1575         // More than 1 version manifest
   1576         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1VersionManifest, v1InstallerManifest, v1DefaultLocaleManifest };
   1577         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest should contain only one file with the particular ManifestType. [ManifestType] Value: version"));
   1578     }
   1579 
   1580     {
   1581         // More than 1 installer manifest
   1582         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1InstallerManifest, v1InstallerManifest, v1DefaultLocaleManifest };
   1583         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest should contain only one file with the particular ManifestType. [ManifestType] Value: installer"));
   1584     }
   1585 
   1586     {
   1587         // More than 1 default locale manifest
   1588         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1InstallerManifest, v1DefaultLocaleManifest, v1DefaultLocaleManifest };
   1589         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest should contain only one file with the particular ManifestType. [ManifestType] Value: defaultLocale"));
   1590     }
   1591 
   1592     {
   1593         // Duplicate locales
   1594         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1InstallerManifest, v1DefaultLocaleManifest, v1LocaleManifest, v1LocaleManifest };
   1595         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest contains duplicate PackageLocale. [PackageLocale] Value: en-GB"));
   1596     }
   1597 
   1598     {
   1599         // default locale not match
   1600         auto defaultLocaleManifestCopy = v1DefaultLocaleManifest;
   1601         defaultLocaleManifestCopy.Root["PackageLocale"].SetScalar("fr-fr");
   1602         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1InstallerManifest, defaultLocaleManifestCopy, v1LocaleManifest };
   1603         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("DefaultLocale value in version manifest does not match PackageLocale value in defaultLocale manifest"));
   1604     }
   1605 
   1606     {
   1607         // Package Id does not match
   1608         auto installerManifestCopy = v1InstallerManifest;
   1609         installerManifestCopy.Root["PackageIdentifier"].SetScalar("Another.Identifier");
   1610         std::vector<YamlManifestInfo> input = { v1VersionManifest, installerManifestCopy, v1DefaultLocaleManifest, v1LocaleManifest };
   1611         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest has inconsistent field values. [PackageIdentifier] Value: Another.Identifier"));
   1612     }
   1613 
   1614     {
   1615         // Package Version does not match
   1616         auto installerManifestCopy = v1InstallerManifest;
   1617         installerManifestCopy.Root["PackageVersion"].SetScalar("Another.Version");
   1618         std::vector<YamlManifestInfo> input = { v1VersionManifest, installerManifestCopy, v1DefaultLocaleManifest, v1LocaleManifest };
   1619         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest has inconsistent field values. [PackageVersion] Value: Another.Version"));
   1620     }
   1621 
   1622     {
   1623         // Incomplete multi file manifest, missing installer
   1624         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1DefaultLocaleManifest };
   1625         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest is incomplete"));
   1626     }
   1627 
   1628     {
   1629         // Incomplete multi file manifest, missing default locale
   1630         std::vector<YamlManifestInfo> input = { v1VersionManifest, v1InstallerManifest };
   1631         REQUIRE_THROWS_MATCHES(YamlParser::ParseManifest(input), ManifestException, ManifestExceptionMatcher("The multi file manifest is incomplete"));
   1632     }
   1633 }
   1634 
   1635 TEST_CASE("ManifestApplyLocale", "[ManifestValidation]")
   1636 {
   1637     Manifest manifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-MultiLocale.yaml"));
   1638 
   1639     // No better alternative locale, default is used.
   1640     manifest.ApplyLocale("zh-CN");
   1641     REQUIRE(manifest.CurrentLocalization.Locale == "es-MX");
   1642     REQUIRE(manifest.CurrentLocalization.Get<Localization::PackageName>() == "es-MX package name");
   1643     REQUIRE(manifest.CurrentLocalization.Get<Localization::Publisher>() == "es-MX publisher");
   1644 
   1645     // en-US results in en-GB, which is better than default.
   1646     manifest.ApplyLocale("en-US");
   1647     REQUIRE(manifest.CurrentLocalization.Locale == "en-GB");
   1648     REQUIRE(manifest.CurrentLocalization.Get<Localization::PackageName>() == "en-GB package name");
   1649     REQUIRE(manifest.CurrentLocalization.Get<Localization::Publisher>() == "en-GB publisher");
   1650 
   1651     // fr-FR results in fr-FR, but only package name is localized.
   1652     manifest.ApplyLocale("fr-FR");
   1653     REQUIRE(manifest.CurrentLocalization.Locale == "fr-FR");
   1654     REQUIRE(manifest.CurrentLocalization.Get<Localization::PackageName>() == "fr-FR package name");
   1655     REQUIRE(manifest.CurrentLocalization.Get<Localization::Publisher>() == "es-MX publisher");
   1656 }
   1657 
   1658 TEST_CASE("ManifestLocalizationValidation", "[ManifestValidation]")
   1659 {
   1660     Manifest manifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-MultiLocale.yaml"));
   1661 
   1662     // Set 1 locale to bad value
   1663     manifest.Localizations.at(0).Locale = "Invalid";
   1664 
   1665     // Full validation should detect as error
   1666     auto errors = ValidateManifest(manifest, true);
   1667     REQUIRE(errors.size() == 1);
   1668     REQUIRE(errors.at(0).ErrorLevel == ValidationError::Level::Error);
   1669 
   1670     // Not full validation should detect as warning
   1671     errors = ValidateManifest(manifest, false);
   1672     REQUIRE(errors.size() == 1);
   1673     REQUIRE(errors.at(0).ErrorLevel == ValidationError::Level::Warning);
   1674 }
   1675 
   1676 TEST_CASE("PortableFileTypeValidation", "[ManifestValidation]")
   1677 {
   1678     Manifest installerManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Bad-InstallerTypeZip-PortableNotExe.yaml"));
   1679     Manifest rootManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Bad-InstallerTypeZip-PortableNotExe_Root.yaml"));
   1680 
   1681     // Regular validation should detect as error
   1682     auto errors = ValidateManifest(installerManifest, true);
   1683     REQUIRE(errors.size() == 1);
   1684     REQUIRE(errors.at(0).ErrorLevel == ValidationError::Level::Error);
   1685 
   1686     errors = ValidateManifest(rootManifest, true);
   1687     REQUIRE(errors.size() == 1);
   1688     REQUIRE(errors.at(0).ErrorLevel == ValidationError::Level::Error);
   1689 
   1690     // Should not error when full validation is set to false
   1691     errors = ValidateManifest(installerManifest, false);
   1692     REQUIRE(errors.size() == 0);
   1693 
   1694     errors = ValidateManifest(rootManifest, false);
   1695     REQUIRE(errors.size() == 0);
   1696 }
   1697 
   1698 TEST_CASE("ReadManifestAndValidateMsixInstallers_Success", "[ManifestValidation]")
   1699 {
   1700     TestDataFile testFile("Manifest-Good-MsixInstaller.yaml");
   1701     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1702 
   1703     // Update the installer path for testing
   1704     REQUIRE(1 == manifest.Installers.size());
   1705     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1706     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1707 
   1708     auto errors = ValidateManifestInstallers(manifest);
   1709     REQUIRE(0 == errors.size());
   1710 }
   1711 
   1712 TEST_CASE("ReadManifestAndValidateMsixInstallers_InconsistentFields", "[ManifestValidation]")
   1713 {
   1714     TestDataFile testFile("Manifest-Bad-InconsistentMsixInstallerFields.yaml");
   1715     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1716 
   1717     // Update the installer path for testing
   1718     REQUIRE(1 == manifest.Installers.size());
   1719     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1720     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1721 
   1722     auto errors = ValidateManifestInstallers(manifest);
   1723     REQUIRE(4 == errors.size());
   1724 
   1725     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::MsixSignatureHashFailed);
   1726     ValidateError(errors[1], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1727     ValidateError(errors[2], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1728     ValidateError(errors[3], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.0.0");
   1729 }
   1730 
   1731 TEST_CASE("ReadManifestAndValidateMsixInstallers_NoSupportedPlatforms", "[ManifestValidation]")
   1732 {
   1733     auto testFileName = "Manifest-Bad-NoSupportedPlatforms.yaml";
   1734     TestDataFile testFile(testFileName);
   1735     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1736 
   1737     // Update the installer path for testing
   1738     REQUIRE(1 == manifest.Installers.size());
   1739     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1740     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1741 
   1742     auto errors = ValidateManifestInstallers(manifest);
   1743     REQUIRE(1 == errors.size());
   1744 
   1745     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::NoSupportedPlatforms, "InstallerUrl", manifest.Installers.front().Url);
   1746 }
   1747 
   1748 TEST_CASE("ReadManifestAndValidateMsixInstallers_PackageVersionNotUINT64", "[ManifestValidation]")
   1749 {
   1750     Manifest manifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Bad-MsixInstaller-PackageVersion.yaml"));
   1751 
   1752     // Update the installer path for testing
   1753     REQUIRE(1 == manifest.Installers.size());
   1754     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1755     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1756 
   1757     auto errors = ValidateManifestInstallers(manifest);
   1758     REQUIRE(1 == errors.size());
   1759 
   1760     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1761 }
   1762 
   1763 TEST_CASE("ReadManifestAndValidateMsixInstallers_MissingFields", "[ManifestValidation]")
   1764 {
   1765     TestDataFile testFile("Manifest-Bad-MissingMsixInstallerFields.yaml");
   1766     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1767 
   1768     // Update the installer path for testing
   1769     REQUIRE(1 == manifest.Installers.size());
   1770     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1771     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1772 
   1773     for (bool treatErrorAsWarning : { false, true })
   1774     {
   1775         auto errors = ValidateManifestInstallers(manifest, treatErrorAsWarning);
   1776         auto expectedLevel = treatErrorAsWarning ? ValidationError::Level::Warning : ValidationError::Level::Error;
   1777         REQUIRE(2 == errors.size());
   1778 
   1779         ValidateError(errors[0], expectedLevel, ManifestError::OptionalFieldMissing, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1780         ValidateError(errors[1], expectedLevel, ManifestError::OptionalFieldMissing, "MinimumOSVersion", "10.0.0.0");
   1781     }
   1782 }
   1783 
   1784 TEST_CASE("ReadManifestAndValidateMsixInstallers_Signed_Success", "[ManifestValidation]")
   1785 {
   1786     TestDataFile testFile("Manifest-Good-SignedMsixInstaller.yaml");
   1787     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1788 
   1789     // Update the installer path for testing
   1790     REQUIRE(1 == manifest.Installers.size());
   1791     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1792     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1793 
   1794     auto errors = ValidateManifestInstallers(manifest);
   1795     REQUIRE(0 == errors.size());
   1796 }
   1797 
   1798 TEST_CASE("ReadManifestAndValidateMsixInstallers_Signed_InconsistentFields", "[ManifestValidation]")
   1799 {
   1800     TestDataFile testFile("Manifest-Bad-InconsistentSignedMsixInstallerFields.yaml");
   1801     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1802 
   1803     // Update the installer path for testing
   1804     REQUIRE(1 == manifest.Installers.size());
   1805     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1806     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1807 
   1808     auto errors = ValidateManifestInstallers(manifest);
   1809     REQUIRE(4 == errors.size());
   1810 
   1811     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "SignatureSha256", "50562001202c8dad456474d3f20903138d0a15c44ee497c3d4f82e85edbf2f97");
   1812     ValidateError(errors[1], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1813     ValidateError(errors[2], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1814     ValidateError(errors[3], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.0.0");
   1815 }
   1816 
   1817 TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_Success", "[ManifestValidation]")
   1818 {
   1819     TestDataFile testFile("Manifest-Good-MsixBundleInstaller.yaml");
   1820     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1821 
   1822     // Update the installer path for testing
   1823     REQUIRE(1 == manifest.Installers.size());
   1824     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1825     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1826 
   1827     auto errors = ValidateManifestInstallers(manifest);
   1828     REQUIRE(0 == errors.size());
   1829 }
   1830 
   1831 TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_WithStub_Success", "[ManifestValidation]")
   1832 {
   1833     TestDataFile testFile("Manifest-Good-MsixBundleInstaller-WithStub.yaml");
   1834     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1835 
   1836     // Update the installer path for testing
   1837     REQUIRE(1 == manifest.Installers.size());
   1838     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1839     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1840 
   1841     auto errors = ValidateManifestInstallers(manifest);
   1842     REQUIRE(0 == errors.size());
   1843 }
   1844 
   1845 TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_InconsistentFields", "[ManifestValidation]")
   1846 {
   1847     TestDataFile testFile("Manifest-Bad-InconsistentMsixBundleInstallerFields.yaml");
   1848     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1849 
   1850     // Update the installer path for testing
   1851     REQUIRE(1 == manifest.Installers.size());
   1852     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1853     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1854 
   1855     auto errors = ValidateManifestInstallers(manifest);
   1856     REQUIRE(7 == errors.size());
   1857 
   1858     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::MsixSignatureHashFailed);
   1859 
   1860     // Validate errors for the first msix package in the msix bundle
   1861     ValidateError(errors[1], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1862     ValidateError(errors[2], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1863     ValidateError(errors[3], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.16299.0");
   1864 
   1865     // Validate errors for the second msix package in the msix bundle
   1866     ValidateError(errors[4], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1867     ValidateError(errors[5], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1868     ValidateError(errors[6], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.16299.0");
   1869 }
   1870 
   1871 TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_Signed_Success", "[ManifestValidation]")
   1872 {
   1873     TestDataFile testFile("Manifest-Good-SignedMsixBundleInstaller.yaml");
   1874     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1875 
   1876     // Update the installer path for testing
   1877     REQUIRE(1 == manifest.Installers.size());
   1878     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1879     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1880 
   1881     auto errors = ValidateManifestInstallers(manifest);
   1882     REQUIRE(0 == errors.size());
   1883 }
   1884 
   1885 TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_Signed_InconsistentFields", "[ManifestValidation]")
   1886 {
   1887     TestDataFile testFile("Manifest-Bad-InconsistentSignedMsixBundleInstallerFields.yaml");
   1888     Manifest manifest = YamlParser::CreateFromPath(testFile);
   1889 
   1890     // Update the installer path for testing
   1891     REQUIRE(1 == manifest.Installers.size());
   1892     TestDataFile msixFile(manifest.Installers[0].Url.c_str());
   1893     manifest.Installers[0].Url = msixFile.GetPath().u8string();
   1894 
   1895     auto errors = ValidateManifestInstallers(manifest);
   1896     REQUIRE(7 == errors.size());
   1897 
   1898     ValidateError(errors[0], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "SignatureSha256", "d70bd623f87b6ce4ddba4506c6000cf43ef3af4ab1207f5579ec43400de1623f");
   1899 
   1900     // Validate errors for the first msix package in the msix bundle
   1901     ValidateError(errors[1], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1902     ValidateError(errors[2], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1903     ValidateError(errors[3], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.16299.0");
   1904 
   1905     // Validate errors for the second msix package in the msix bundle
   1906     ValidateError(errors[4], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageFamilyName", "FakeInstallerForTesting_125rzkzqaqjwj");
   1907     ValidateError(errors[5], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "PackageVersion", "43690.48059.52428.56797");
   1908     ValidateError(errors[6], ValidationError::Level::Error, ManifestError::InstallerMsixInconsistencies, "MinimumOSVersion", "10.0.16299.0");
   1909 }
   1910 
   1911 TEST_CASE("ManifestArpVersionRange", "[ManifestValidation]")
   1912 {
   1913     Manifest manifestNoArp = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-NoArpVersionDeclared.yaml"));
   1914     REQUIRE(manifestNoArp.GetArpVersionRange().IsEmpty());
   1915 
   1916     Manifest manifestSingleArp = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-SingleArpVersionDeclared.yaml"));
   1917     auto arpRangeSingleArp = manifestSingleArp.GetArpVersionRange();
   1918     REQUIRE(arpRangeSingleArp.GetMinVersion().ToString() == "11.0");
   1919     REQUIRE(arpRangeSingleArp.GetMaxVersion().ToString() == "11.0");
   1920 
   1921     Manifest manifestMultiArp = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-MultipleArpVersionDeclared.yaml"));
   1922     auto arpRangeMultiArp = manifestMultiArp.GetArpVersionRange();
   1923     REQUIRE(arpRangeMultiArp.GetMinVersion().ToString() == "12.0");
   1924     REQUIRE(arpRangeMultiArp.GetMaxVersion().ToString() == "13.0");
   1925 }
   1926 
   1927 TEST_CASE("ManifestV1_10_SchemaHeaderValidations", "[ManifestValidation]")
   1928 {
   1929     ManifestValidateOption validateOption;
   1930     validateOption.FullValidation = true;
   1931 
   1932     // Schema header not found
   1933     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile("ManifestV1_10-Bad-SchemaHeaderNotFound.yaml"),validateOption), ManifestException, ManifestExceptionMatcher("Schema header not found"));
   1934 
   1935     // Schema header not valid
   1936     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile("ManifestV1_10-Bad-SchemaHeaderInvalid.yaml"), validateOption), ManifestException, ManifestExceptionMatcher("The schema header is invalid. Please verify that the schema header is present and formatted correctly."));
   1937 
   1938     // Schema header URL does not match the expected schema URL
   1939     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile("ManifestV1_10-Bad-SchemaHeaderURLPatternMismatch.yaml"), validateOption), ManifestException, ManifestExceptionMatcher("The schema header URL does not match the expected pattern."));
   1940 
   1941     // Schema header ManifestType does not match the expected value
   1942     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile("ManifestV1_10-Bad-SchemaHeaderManifestTypeMismatch.yaml"), validateOption), ManifestException, ManifestExceptionMatcher("The manifest type in the schema header does not match the ManifestType property value in the manifest."));
   1943 
   1944     // Schema header version does not match the expected version
   1945     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(TestDataFile("ManifestV1_10-Bad-SchemaHeaderManifestVersionMismatch.yaml"), validateOption), ManifestException, ManifestExceptionMatcher("The manifest version in the schema header does not match the ManifestVersion property value in the manifest."));
   1946 }
   1947 
   1948 TEST_CASE("ShadowManifest", "[ShadowManifest]")
   1949 {
   1950     ManifestValidateOption validateOption;
   1951     validateOption.FullValidation = true;
   1952     validateOption.AllowShadowManifest = true;
   1953 
   1954     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1955     CopyTestDataFilesToFolder({
   1956         "ManifestV1_5-MultiFile-Version.yaml",
   1957         "ManifestV1_5-Shadow-Installer.yaml",
   1958         "ManifestV1_5-Shadow-DefaultLocale.yaml",
   1959         "ManifestV1_5-Shadow-Locale.yaml",
   1960         "ManifestV1_5-Shadow-Locale2.yaml",
   1961         "ManifestV1_5-Shadow-Shadow.yaml" }, multiFileDirectory);
   1962 
   1963     auto shadowInfo = ManifestShadowTestInfo{};
   1964     shadowInfo.shadowDefaultLocale = true;
   1965     shadowInfo.shadowEnGbLocale = true;
   1966 
   1967     TempFile mergedManifestFile{ "merged.yaml" };
   1968     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1969     VerifyV1ManifestContentCreatedWithShadow(multiFileManifest, shadowInfo);
   1970 
   1971     // Read from merged manifest should have the same content as multi file manifest
   1972     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   1973     VerifyV1ManifestContentCreatedWithShadow(mergedManifest, shadowInfo);
   1974 }
   1975 
   1976 TEST_CASE("ShadowManifest_SkipShadowDefaultLocale", "[ShadowManifest]")
   1977 {
   1978     ManifestValidateOption validateOption;
   1979     validateOption.FullValidation = true;
   1980     validateOption.AllowShadowManifest = true;
   1981 
   1982     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   1983     CopyTestDataFilesToFolder({
   1984         "ManifestV1_5-MultiFile-Version.yaml",
   1985         "ManifestV1_5-Shadow-Installer.yaml",
   1986         "ManifestV1_5-MultiFile-DefaultLocale.yaml",
   1987         "ManifestV1_5-Shadow-Locale.yaml",
   1988         "ManifestV1_5-Shadow-Locale2.yaml",
   1989         "ManifestV1_5-Shadow-Shadow.yaml" }, multiFileDirectory);
   1990 
   1991     auto shadowInfo = ManifestShadowTestInfo{};
   1992     shadowInfo.shadowDefaultLocale = false;
   1993     shadowInfo.shadowEnGbLocale = true;
   1994 
   1995     TempFile mergedManifestFile{ "merged.yaml" };
   1996     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   1997     VerifyV1ManifestContentCreatedWithShadow(multiFileManifest, shadowInfo);
   1998 
   1999     // Read from merged manifest should have the same content as multi file manifest
   2000     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   2001     VerifyV1ManifestContentCreatedWithShadow(mergedManifest, shadowInfo);
   2002 }
   2003 
   2004 TEST_CASE("ShadowManifest_SkipShadowLocalizationLocale", "[ShadowManifest]")
   2005 {
   2006     ManifestValidateOption validateOption;
   2007     validateOption.FullValidation = true;
   2008     validateOption.AllowShadowManifest = true;
   2009 
   2010     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   2011     CopyTestDataFilesToFolder({
   2012         "ManifestV1_5-MultiFile-Version.yaml",
   2013         "ManifestV1_5-Shadow-Installer.yaml",
   2014         "ManifestV1_5-Shadow-DefaultLocale.yaml",
   2015         "ManifestV1_5-MultiFile-Locale.yaml",
   2016         "ManifestV1_5-Shadow-Locale2.yaml",
   2017         "ManifestV1_5-Shadow-Shadow.yaml" }, multiFileDirectory);
   2018 
   2019     auto shadowInfo = ManifestShadowTestInfo{};
   2020     shadowInfo.shadowDefaultLocale = true;
   2021     shadowInfo.shadowEnGbLocale = false;
   2022 
   2023     TempFile mergedManifestFile{ "merged.yaml" };
   2024     Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile);
   2025     VerifyV1ManifestContentCreatedWithShadow(multiFileManifest, shadowInfo);
   2026 
   2027     // Read from merged manifest should have the same content as multi file manifest
   2028     Manifest mergedManifest = YamlParser::CreateFromPath(mergedManifestFile);
   2029     VerifyV1ManifestContentCreatedWithShadow(mergedManifest, shadowInfo);
   2030 }
   2031 
   2032 TEST_CASE("ShadowManifest_ShadowNotAllowed", "[ShadowManifest]")
   2033 {
   2034     ManifestValidateOption validateOption;
   2035     validateOption.FullValidation = true;
   2036     validateOption.AllowShadowManifest = false;
   2037 
   2038     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   2039     CopyTestDataFilesToFolder({
   2040         "ManifestV1_5-MultiFile-Version.yaml",
   2041         "ManifestV1_5-Shadow-Installer.yaml",
   2042         "ManifestV1_5-Shadow-DefaultLocale.yaml",
   2043         "ManifestV1_5-Shadow-Locale.yaml",
   2044         "ManifestV1_5-Shadow-Locale2.yaml",
   2045         "ManifestV1_5-Shadow-Shadow.yaml" }, multiFileDirectory);
   2046 
   2047     TempFile mergedManifestFile{ "merged.yaml" };
   2048     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile), ManifestException, ManifestExceptionMatcher("Shadow manifest is not allowed. [ManifestType] Value: shadow File: ManifestV1_5-Shadow-Shadow.yaml"));
   2049 }
   2050 
   2051 TEST_CASE("ShadowManifest_TwoShadowFiles", "[ShadowManifest]")
   2052 {
   2053     ManifestValidateOption validateOption;
   2054     validateOption.FullValidation = true;
   2055     validateOption.AllowShadowManifest = true;
   2056 
   2057     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   2058     CopyTestDataFilesToFolder({
   2059         "ManifestV1_5-MultiFile-Version.yaml",
   2060         "ManifestV1_5-Shadow-Installer.yaml",
   2061         "ManifestV1_5-Shadow-DefaultLocale.yaml",
   2062         "ManifestV1_5-Shadow-Shadow.yaml",
   2063         "ManifestV1_5-Shadow-Shadow2.yaml" }, multiFileDirectory);
   2064 
   2065     TempFile mergedManifestFile{ "merged.yaml" };
   2066     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile), ManifestException, ManifestExceptionMatcher("The multi file manifest should contain only one file with the particular ManifestType. [ManifestType] Value: shadow File: ManifestV1_5-Shadow-Shadow2.yaml"));
   2067 }
   2068 
   2069 TEST_CASE("ShadowManifest_NotVerifiedPublisher", "[ShadowManifest]")
   2070 {
   2071     ManifestValidateOption validateOption;
   2072     validateOption.FullValidation = true;
   2073     validateOption.AllowShadowManifest = true;
   2074     validateOption.ErrorOnVerifiedPublisherFields = true;
   2075 
   2076     TempDirectory multiFileDirectory{ "MultiFileManifest" };
   2077     CopyTestDataFilesToFolder({
   2078         "ManifestV1_5-MultiFile-Version.yaml",
   2079         "ManifestV1_5-Shadow-Installer.yaml",
   2080         "ManifestV1_5-Shadow-DefaultLocale.yaml",
   2081         "ManifestV1_5-Shadow-Locale.yaml",
   2082         "ManifestV1_5-Shadow-Locale2.yaml",
   2083         "ManifestV1_5-Shadow-Shadow.yaml" }, multiFileDirectory);
   2084 
   2085     TempFile mergedManifestFile{ "merged.yaml" };
   2086     REQUIRE_THROWS_MATCHES(YamlParser::CreateFromPath(multiFileDirectory, validateOption, mergedManifestFile), ManifestException, ManifestExceptionMatcher("Field usage requires verified publishers. [Icons]"));
   2087 }