diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
index 9b0e2e2853..043eab3f5a 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -322,6 +322,7 @@
+
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
index 2bbcd74516..a24784a802 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -365,6 +365,9 @@
Source Files\CLI
+
+ Source Files\Repository
+
diff --git a/src/AppInstallerCLITests/RestClient.cpp b/src/AppInstallerCLITests/RestClient.cpp
index a45a9e2eba..a864454f76 100644
--- a/src/AppInstallerCLITests/RestClient.cpp
+++ b/src/AppInstallerCLITests/RestClient.cpp
@@ -51,7 +51,7 @@ TEST_CASE("GetSupportedInterface", "[RestSource]")
REQUIRE(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, version, {})->GetVersion() == version);
// Update this test to next version so that we don't forget to add to supported versions before rest e2e tests are available.
- Version invalid{ "1.8.0" };
+ Version invalid{ "1.10.0" };
REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, invalid, {}), APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION);
Authentication::AuthenticationArguments authArgs;
diff --git a/src/AppInstallerCLITests/RestInterface_1_9.cpp b/src/AppInstallerCLITests/RestInterface_1_9.cpp
new file mode 100644
index 0000000000..e33480dd19
--- /dev/null
+++ b/src/AppInstallerCLITests/RestInterface_1_9.cpp
@@ -0,0 +1,400 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "TestCommon.h"
+#include "TestRestRequestHandler.h"
+#include
+#include
+#include
+#include
+
+using namespace TestCommon;
+using namespace AppInstaller::Http;
+using namespace AppInstaller::Utility;
+using namespace AppInstaller::Manifest;
+using namespace AppInstaller::Repository;
+using namespace AppInstaller::Repository::Rest;
+using namespace AppInstaller::Repository::Rest::Schema;
+using namespace AppInstaller::Repository::Rest::Schema::V1_9;
+
+namespace
+{
+ const std::string TestRestUriString = "http://restsource.com/api";
+
+ struct GoodManifest_AllFields
+ {
+ utility::string_t GetSampleManifest_AllFields()
+ {
+ return _XPLATSTR(
+ R"delimiter(
+ {
+ "Data": {
+ "PackageIdentifier": "Foo.Bar",
+ "Versions": [
+ {
+ "PackageVersion": "3.0.0abc",
+ "DefaultLocale": {
+ "PackageLocale": "en-US",
+ "Publisher": "Foo",
+ "PublisherUrl": "http://publisher.net",
+ "PublisherSupportUrl": "http://publisherSupport.net",
+ "PrivacyUrl": "http://packagePrivacyUrl.net",
+ "Author": "FooBar",
+ "PackageName": "Bar",
+ "PackageUrl": "http://packageUrl.net",
+ "License": "Foo Bar License",
+ "LicenseUrl": "http://licenseUrl.net",
+ "Copyright": "Foo Bar Copyright",
+ "CopyrightUrl": "http://copyrightUrl.net",
+ "ShortDescription": "Foo bar is a foo bar.",
+ "Description": "Foo bar is a placeholder.",
+ "Tags": [
+ "FooBar",
+ "Foo",
+ "Bar"
+ ],
+ "Moniker": "FooBarMoniker",
+ "ReleaseNotes": "Default release notes",
+ "ReleaseNotesUrl": "https://DefaultReleaseNotes.net",
+ "Agreements": [{
+ "AgreementLabel": "DefaultLabel",
+ "Agreement": "DefaultText",
+ "AgreementUrl": "https://DefaultAgreementUrl.net"
+ }],
+ "PurchaseUrl": "http://DefaultPurchaseUrl.net",
+ "InstallationNotes": "Default Installation Notes",
+ "Documentations": [{
+ "DocumentLabel": "Default Document Label",
+ "DocumentUrl": "http://DefaultDocumentUrl.net"
+ }],
+ "Icons": [{
+ "IconUrl": "https://DefaultTestIcon",
+ "IconFileType": "ico",
+ "IconResolution": "custom",
+ "IconTheme": "default",
+ "IconSha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"
+ }]
+ },
+ "Channel": "",
+ "Locales": [
+ {
+ "PackageLocale": "fr-Fr",
+ "Publisher": "Foo French",
+ "PublisherUrl": "http://publisher-fr.net",
+ "PublisherSupportUrl": "http://publisherSupport-fr.net",
+ "PrivacyUrl": "http://packagePrivacyUrl-fr.net",
+ "Author": "FooBar French",
+ "PackageName": "Bar",
+ "PackageUrl": "http://packageUrl-fr.net",
+ "License": "Foo Bar License",
+ "LicenseUrl": "http://licenseUrl-fr.net",
+ "Copyright": "Foo Bar Copyright",
+ "CopyrightUrl": "http://copyrightUrl-fr.net",
+ "ShortDescription": "Foo bar is a foo bar French.",
+ "Description": "Foo bar is a placeholder French.",
+ "Tags": [
+ "FooBarFr",
+ "FooFr",
+ "BarFr"
+ ],
+ "ReleaseNotes": "Release notes",
+ "ReleaseNotesUrl": "https://ReleaseNotes.net",
+ "Agreements": [{
+ "AgreementLabel": "Label",
+ "Agreement": "Text",
+ "AgreementUrl": "https://AgreementUrl.net"
+ }],
+ "PurchaseUrl": "http://purchaseUrl.net",
+ "InstallationNotes": "Installation Notes",
+ "Documentations": [{
+ "DocumentLabel": "Document Label",
+ "DocumentUrl": "http://documentUrl.net"
+ }],
+ "Icons": [{
+ "IconUrl": "https://testIcon",
+ "IconFileType": "png",
+ "IconResolution": "32x32",
+ "IconTheme": "light",
+ "IconSha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"
+ }]
+ }
+ ],)delimiter") _XPLATSTR(R"delimiter(
+ "Installers": [
+ {
+ "InstallerSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6",
+ "InstallerUrl": "http://foobar.zip",
+ "Architecture": "x86",
+ "InstallerLocale": "en-US",
+ "Platform": [
+ "Windows.Desktop"
+ ],
+ "MinimumOSVersion": "1078",
+ "InstallerType": "zip",
+ "Scope": "user",
+ "InstallModes": [
+ "interactive"
+ ],
+ "InstallerSwitches": {
+ "Silent": "/s",
+ "SilentWithProgress": "/s",
+ "Interactive": "/i",
+ "InstallLocation": "C:\\Users\\User1",
+ "Log": "/l",
+ "Upgrade": "/u",
+ "Custom": "/custom",
+ "Repair": "/repair"
+ },
+ "InstallerSuccessCodes": [
+ 0
+ ],
+ "UpgradeBehavior": "deny",
+ "Commands": [
+ "command1"
+ ],
+ "Protocols": [
+ "protocol1"
+ ],
+ "FileExtensions": [
+ ".file-extension"
+ ],
+ "Dependencies": {
+ "WindowsFeatures": [
+ "feature1"
+ ],
+ "WindowsLibraries": [
+ "library1"
+ ],
+ "PackageDependencies": [
+ {
+ "PackageIdentifier": "Foo.Baz",
+ "MinimumVersion": "2.0.0"
+ }
+ ],
+ "ExternalDependencies": [
+ "FooBarBaz"
+ ]
+ },
+ "ProductCode": "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d",
+ "ReleaseDate": "2021-01-01",
+ "InstallerAbortsTerminal": true,
+ "InstallLocationRequired": true,
+ "RequireExplicitUpgrade": true,
+ "UnsupportedOSArchitectures": [ "arm" ],
+ "ElevationRequirement": "elevatesSelf",
+ "AppsAndFeaturesEntries": [{
+ "DisplayName": "DisplayName",
+ "DisplayVersion": "DisplayVersion",
+ "Publisher": "Publisher",
+ "ProductCode": "ProductCode",
+ "UpgradeCode": "UpgradeCode",
+ "InstallerType": "exe"
+ }],
+ "Markets" : {
+ "AllowedMarkets": [ "US" ]
+ },
+ "ExpectedReturnCodes": [{
+ "InstallerReturnCode": 3,
+ "ReturnResponse": "custom",
+ "ReturnResponseUrl": "http://returnResponseUrl.net"
+ }],
+ "NestedInstallerType": "portable",
+ "DisplayInstallWarnings": true,
+ "UnsupportedArguments": [ "log" ],
+ "NestedInstallerFiles": [{
+ "RelativeFilePath": "test\\app.exe",
+ "PortableCommandAlias": "test.exe"
+ }],
+ "InstallationMetadata": {
+ "DefaultInstallLocation": "%TEMP%\\DefaultInstallLocation",
+ "Files": [{
+ "RelativeFilePath": "test\\app.exe",
+ "FileSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6",
+ "FileType": "launch",
+ "InvocationParameter": "/parameter",
+ "DisplayName": "test"
+ }]
+ },
+ "DownloadCommandProhibited": true,
+ "RepairBehavior": "uninstaller",
+ "ArchiveBinariesDependOnPath": true
+ }
+ ]
+ }
+ ]
+ },
+ "ContinuationToken": "abcd"
+ })delimiter");
+ }
+
+ void VerifyLocalizations_AllFields(const AppInstaller::Manifest::Manifest& manifest)
+ {
+ REQUIRE(manifest.DefaultLocalization.Locale == "en-US");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://publisher.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://publisherSupport.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://packagePrivacyUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "FooBar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Bar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://packageUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo Bar License");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://licenseUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo Bar Copyright");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://copyrightUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo bar is a foo bar.");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo bar is a placeholder.");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 3);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0) == "FooBar");
+ REQUIRE(manifest.DefaultLocalization.Get().at(1) == "Foo");
+ REQUIRE(manifest.DefaultLocalization.Get().at(2) == "Bar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Default release notes");
+ REQUIRE(manifest.DefaultLocalization.Get() == "https://DefaultReleaseNotes.net");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Label == "DefaultLabel");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).AgreementText == "DefaultText");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).AgreementUrl == "https://DefaultAgreementUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://DefaultPurchaseUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Default Installation Notes");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).DocumentLabel == "Default Document Label");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).DocumentUrl == "http://DefaultDocumentUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Url == "https://DefaultTestIcon");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).FileType == IconFileTypeEnum::Ico);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Resolution == IconResolutionEnum::Custom);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Theme == IconThemeEnum::Default);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"));
+
+ REQUIRE(manifest.Localizations.size() == 1);
+ ManifestLocalization frenchLocalization = manifest.Localizations.at(0);
+ REQUIRE(frenchLocalization.Locale == "fr-Fr");
+ REQUIRE(frenchLocalization.Get() == "Foo French");
+ REQUIRE(frenchLocalization.Get() == "http://publisher-fr.net");
+ REQUIRE(frenchLocalization.Get() == "http://publisherSupport-fr.net");
+ REQUIRE(frenchLocalization.Get() == "http://packagePrivacyUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "FooBar French");
+ REQUIRE(frenchLocalization.Get() == "Bar");
+ REQUIRE(frenchLocalization.Get() == "http://packageUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo Bar License");
+ REQUIRE(frenchLocalization.Get() == "http://licenseUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo Bar Copyright");
+ REQUIRE(frenchLocalization.Get() == "http://copyrightUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo bar is a foo bar French.");
+ REQUIRE(frenchLocalization.Get() == "Foo bar is a placeholder French.");
+ REQUIRE(frenchLocalization.Get().size() == 3);
+ REQUIRE(frenchLocalization.Get().at(0) == "FooBarFr");
+ REQUIRE(frenchLocalization.Get().at(1) == "FooFr");
+ REQUIRE(frenchLocalization.Get().at(2) == "BarFr");
+ REQUIRE(frenchLocalization.Get() == "Release notes");
+ REQUIRE(frenchLocalization.Get() == "https://ReleaseNotes.net");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).Label == "Label");
+ REQUIRE(frenchLocalization.Get().at(0).AgreementText == "Text");
+ REQUIRE(frenchLocalization.Get().at(0).AgreementUrl == "https://AgreementUrl.net");
+ REQUIRE(frenchLocalization.Get() == "http://purchaseUrl.net");
+ REQUIRE(frenchLocalization.Get() == "Installation Notes");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).DocumentLabel == "Document Label");
+ REQUIRE(frenchLocalization.Get().at(0).DocumentUrl == "http://documentUrl.net");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).Url == "https://testIcon");
+ REQUIRE(frenchLocalization.Get().at(0).FileType == IconFileTypeEnum::Png);
+ REQUIRE(frenchLocalization.Get().at(0).Resolution == IconResolutionEnum::Square32);
+ REQUIRE(frenchLocalization.Get().at(0).Theme == IconThemeEnum::Light);
+ REQUIRE(frenchLocalization.Get().at(0).Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"));
+ }
+
+ void VerifyInstallers_AllFields(const AppInstaller::Manifest::Manifest& manifest)
+ {
+ REQUIRE(manifest.Installers.size() == 1);
+
+ ManifestInstaller actualInstaller = manifest.Installers.at(0);
+ REQUIRE(actualInstaller.Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
+ REQUIRE(actualInstaller.Url == "http://foobar.zip");
+ REQUIRE(actualInstaller.Arch == Architecture::X86);
+ REQUIRE(actualInstaller.Locale == "en-US");
+ REQUIRE(actualInstaller.Platform.size() == 1);
+ REQUIRE(actualInstaller.Platform[0] == PlatformEnum::Desktop);
+ REQUIRE(actualInstaller.MinOSVersion == "1078");
+ REQUIRE(actualInstaller.BaseInstallerType == InstallerTypeEnum::Zip);
+ REQUIRE(actualInstaller.Scope == ScopeEnum::User);
+ REQUIRE(actualInstaller.InstallModes.size() == 1);
+ REQUIRE(actualInstaller.InstallModes.at(0) == InstallModeEnum::Interactive);
+ REQUIRE(actualInstaller.Switches.size() == 8);
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Silent) == "/s");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::SilentWithProgress) == "/s");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Interactive) == "/i");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::InstallLocation) == "C:\\Users\\User1");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Log) == "/l");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Update) == "/u");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Custom) == "/custom");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Repair) == "/repair");
+ REQUIRE(actualInstaller.InstallerSuccessCodes.size() == 1);
+ REQUIRE(actualInstaller.InstallerSuccessCodes.at(0) == 0);
+ REQUIRE(actualInstaller.UpdateBehavior == UpdateBehaviorEnum::Deny);
+ REQUIRE(actualInstaller.Commands.at(0) == "command1");
+ REQUIRE(actualInstaller.Protocols.at(0) == "protocol1");
+ REQUIRE(actualInstaller.FileExtensions.at(0) == ".file-extension");
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsFeature, "feature1"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsLibrary, "library1"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::Package, "Foo.Baz", "2.0.0"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::External, "FooBarBaz"));
+ REQUIRE(actualInstaller.PackageFamilyName == "");
+ REQUIRE(actualInstaller.ProductCode == "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d");
+ REQUIRE(actualInstaller.ReleaseDate == "2021-01-01");
+ REQUIRE(actualInstaller.InstallerAbortsTerminal);
+ REQUIRE(actualInstaller.InstallLocationRequired);
+ REQUIRE(actualInstaller.RequireExplicitUpgrade);
+ REQUIRE(actualInstaller.ElevationRequirement == ElevationRequirementEnum::ElevatesSelf);
+ REQUIRE(actualInstaller.UnsupportedOSArchitectures.size() == 1);
+ REQUIRE(actualInstaller.UnsupportedOSArchitectures.at(0) == Architecture::Arm);
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.size() == 1);
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayName == "DisplayName");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayVersion == "DisplayVersion");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).Publisher == "Publisher");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).ProductCode == "ProductCode");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).UpgradeCode == "UpgradeCode");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe);
+ REQUIRE(actualInstaller.Markets.AllowedMarkets.size() == 1);
+ REQUIRE(actualInstaller.Markets.AllowedMarkets.at(0) == "US");
+ REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseEnum == ExpectedReturnCodeEnum::Custom);
+ REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseUrl == "http://returnResponseUrl.net");
+ REQUIRE(actualInstaller.NestedInstallerType == InstallerTypeEnum::Portable);
+ REQUIRE(actualInstaller.DisplayInstallWarnings);
+ REQUIRE(actualInstaller.UnsupportedArguments.size() == 1);
+ REQUIRE(actualInstaller.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Log);
+ REQUIRE(actualInstaller.NestedInstallerFiles.size() == 1);
+ REQUIRE(actualInstaller.NestedInstallerFiles.at(0).RelativeFilePath == "test\\app.exe");
+ REQUIRE(actualInstaller.NestedInstallerFiles.at(0).PortableCommandAlias == "test.exe");
+ REQUIRE(actualInstaller.InstallationMetadata.DefaultInstallLocation == "%TEMP%\\DefaultInstallLocation");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.size() == 1);
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).RelativeFilePath == "test\\app.exe");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Launch);
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileSha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).InvocationParameter == "/parameter");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).DisplayName == "test");
+ REQUIRE(actualInstaller.DownloadCommandProhibited);
+ REQUIRE(actualInstaller.RepairBehavior == RepairBehaviorEnum::Uninstaller);
+ REQUIRE(actualInstaller.ArchiveBinariesDependOnPath);
+ }
+ };
+}
+
+TEST_CASE("GetManifests_GoodResponse_V1_9", "[RestSource][Interface_1_9]")
+{
+ GoodManifest_AllFields sampleManifest;
+ utility::string_t sample = sampleManifest.GetSampleManifest_AllFields();
+ HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) };
+ Interface v1_9{ TestRestUriString, std::move(helper), {} };
+ std::vector manifests = v1_9.GetManifests("Foo.Bar");
+ REQUIRE(manifests.size() == 1);
+
+ // Verify manifest is populated
+ Manifest& manifest = manifests[0];
+ REQUIRE(manifest.Id == "Foo.Bar");
+ REQUIRE(manifest.Version == "3.0.0abc");
+ REQUIRE(manifest.Moniker == "FooBarMoniker");
+ REQUIRE(manifest.Channel == "");
+ REQUIRE(manifest.ManifestVersion == AppInstaller::Manifest::ManifestVer{ "1.9.0" });
+ sampleManifest.VerifyLocalizations_AllFields(manifest);
+ sampleManifest.VerifyInstallers_AllFields(manifest);
+}
diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
index f1dc17c57f..d70fb30e56 100644
--- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
+++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
@@ -451,6 +451,8 @@
+
+
@@ -544,6 +546,8 @@
+
+
diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
index 5abac094cf..1b91d82bcf 100644
--- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
+++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
@@ -103,6 +103,12 @@
{34442899-29e5-4183-96ba-a1e8740146be}
+
+ {8edd7018-8836-4b15-84c1-998391e19038}
+
+
+ {7464e3ff-7a60-4bb6-8806-70562382043b}
+
@@ -462,6 +468,12 @@
Microsoft
+
+ Rest\Schema\1_9\Json
+
+
+ Rest\Schema\1_9
+
@@ -722,6 +734,12 @@
Microsoft
+
+ Rest\Schema\1_9\Json
+
+
+ Rest\Schema\1_9
+
diff --git a/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp b/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
index 79877c0edc..d30a871cdf 100644
--- a/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
+++ b/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
@@ -8,6 +8,7 @@
#include "Rest/Schema/1_5/Json/ManifestDeserializer.h"
#include "Rest/Schema/1_6/Json/ManifestDeserializer.h"
#include "Rest/Schema/1_7/Json/ManifestDeserializer.h"
+#include "Rest/Schema/1_9/Json/ManifestDeserializer.h"
namespace AppInstaller::Repository::JSON
{
@@ -46,10 +47,14 @@ namespace AppInstaller::Repository::JSON
{
m_pImpl->m_deserializer = std::make_unique();
}
- else
+ else if (parts.size() > 1 && parts[1].Integer < 9)
{
m_pImpl->m_deserializer = std::make_unique();
}
+ else
+ {
+ m_pImpl->m_deserializer = std::make_unique();
+ }
}
else
{
diff --git a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
index 602d1fbfeb..c7e796bb16 100644
--- a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
+++ b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
@@ -8,6 +8,7 @@
#include "Rest/Schema/1_5/Interface.h"
#include "Rest/Schema/1_6/Interface.h"
#include "Rest/Schema/1_7/Interface.h"
+#include "Rest/Schema/1_9/Interface.h"
#include "Rest/Schema/InformationResponseDeserializer.h"
#include "Rest/Schema/CommonRestConstants.h"
#include
@@ -22,7 +23,7 @@ using namespace AppInstaller::Http;
namespace AppInstaller::Repository::Rest
{
// Supported versions
- std::set WingetSupportedContracts = { Version_1_0_0, Version_1_1_0, Version_1_4_0, Version_1_5_0, Version_1_6_0, Version_1_7_0 };
+ std::set WingetSupportedContracts = { Version_1_0_0, Version_1_1_0, Version_1_4_0, Version_1_5_0, Version_1_6_0, Version_1_7_0, Version_1_9_0 };
constexpr std::string_view WindowsPackageManagerHeader = "Windows-Package-Manager"sv;
constexpr size_t WindowsPackageManagerHeaderMaxLength = 1024;
@@ -176,6 +177,10 @@ namespace AppInstaller::Repository::Rest
{
return std::make_unique(api, helper, information, additionalHeaders, authArgs);
}
+ else if (version == Version_1_9_0)
+ {
+ return std::make_unique(api, helper, information, additionalHeaders, authArgs);
+ }
THROW_HR(APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION);
}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
new file mode 100644
index 0000000000..d9fb755c45
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "Rest/Schema/1_7/Interface.h"
+
+namespace AppInstaller::Repository::Rest::Schema::V1_9
+{
+ // Interface to this schema version exposed through IRestClient.
+ struct Interface : public V1_7::Interface
+ {
+ Interface(const std::string& restApi, const Http::HttpClientHelper& helper, IRestClient::Information information, const Http::HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, Authentication::AuthenticationArguments authArgs = {});
+
+ Interface(const Interface&) = delete;
+ Interface& operator=(const Interface&) = delete;
+
+ Interface(Interface&&) = default;
+ Interface& operator=(Interface&&) = default;
+
+ Utility::Version GetVersion() const override;
+ };
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h
new file mode 100644
index 0000000000..09dd1da76d
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "Rest/Schema/1_7/Json/ManifestDeserializer.h"
+
+namespace AppInstaller::Repository::Rest::Schema::V1_9::Json
+{
+ // Manifest Deserializer.
+ struct ManifestDeserializer : public V1_7::Json::ManifestDeserializer
+ {
+ protected:
+
+ std::optional DeserializeInstaller(const web::json::value& installerJsonObject) const override;
+
+ Manifest::ManifestVer GetManifestVersion() const override;
+ };
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp
new file mode 100644
index 0000000000..714d3fe048
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "ManifestDeserializer.h"
+#include
+
+using namespace AppInstaller::Manifest;
+
+namespace AppInstaller::Repository::Rest::Schema::V1_9::Json
+{
+ namespace
+ {
+ // Installer
+ constexpr std::string_view ArchiveBinariesDependOnPath = "ArchiveBinariesDependOnPath"sv;
+ }
+
+ std::optional ManifestDeserializer::DeserializeInstaller(const web::json::value& installerJsonObject) const
+ {
+ auto result = V1_7::Json::ManifestDeserializer::DeserializeInstaller(installerJsonObject);
+
+ if (result)
+ {
+ auto& installer = result.value();
+
+ installer.ArchiveBinariesDependOnPath = JSON::GetRawBoolValueFromJsonNode(installerJsonObject, JSON::GetUtilityString(ArchiveBinariesDependOnPath)).value_or(false);
+ }
+
+ return result;
+ }
+
+ Manifest::ManifestVer ManifestDeserializer::GetManifestVersion() const
+ {
+ return Manifest::s_ManifestVersionV1_9;
+ }
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp
new file mode 100644
index 0000000000..b741b96530
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "Rest/Schema/1_9/Interface.h"
+#include "Rest/Schema/CommonRestConstants.h"
+#include "Rest/Schema/IRestClient.h"
+#include
+#include
+
+namespace AppInstaller::Repository::Rest::Schema::V1_9
+{
+ Interface::Interface(
+ const std::string& restApi,
+ const Http::HttpClientHelper& httpClientHelper,
+ IRestClient::Information information,
+ const Http::HttpClientHelper::HttpRequestHeaders& additionalHeaders,
+ Authentication::AuthenticationArguments authArgs) : V1_7::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders, std::move(authArgs))
+ {
+ m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_9_0.ToString());
+ }
+
+ Utility::Version Interface::GetVersion() const
+ {
+ return Version_1_9_0;
+ }
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h b/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
index ab3ab2002e..6ee979b7aa 100644
--- a/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
@@ -12,6 +12,7 @@ namespace AppInstaller::Repository::Rest::Schema
const Utility::Version Version_1_5_0{ "1.5.0" };
const Utility::Version Version_1_6_0{ "1.6.0" };
const Utility::Version Version_1_7_0{ "1.7.0" };
+ const Utility::Version Version_1_9_0{ "1.9.0" };
// General API response constants
constexpr std::string_view Data = "Data"sv;
diff --git a/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj b/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
index b3fd2c5990..618c708bc4 100644
--- a/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
+++ b/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
@@ -94,6 +94,9 @@
Always
+
+ Always
+
PreserveNewest