RestInterface_1_4.cpp (24601B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "TestCommon.h" 5 #include "TestRestRequestHandler.h" 6 #include <Rest/Schema/1_4/Interface.h> 7 #include <Rest/Schema/IRestClient.h> 8 #include <AppInstallerVersions.h> 9 #include <AppInstallerErrors.h> 10 11 using namespace TestCommon; 12 using namespace AppInstaller::Http; 13 using namespace AppInstaller::Utility; 14 using namespace AppInstaller::Manifest; 15 using namespace AppInstaller::Repository; 16 using namespace AppInstaller::Repository::Rest; 17 using namespace AppInstaller::Repository::Rest::Schema; 18 using namespace AppInstaller::Repository::Rest::Schema::V1_4; 19 20 namespace 21 { 22 const std::string TestRestUriString = "http://restsource.com/api"; 23 24 IRestClient::Information GetTestSourceInformation() 25 { 26 IRestClient::Information result; 27 28 result.RequiredPackageMatchFields.emplace_back("Market"); 29 result.RequiredQueryParameters.emplace_back("Market"); 30 result.UnsupportedPackageMatchFields.emplace_back("Moniker"); 31 result.UnsupportedQueryParameters.emplace_back("Channel"); 32 33 return result; 34 } 35 36 struct GoodManifest_AllFields 37 { 38 utility::string_t GetSampleManifest_AllFields() 39 { 40 return _XPLATSTR( 41 R"delimiter( 42 { 43 "Data": { 44 "PackageIdentifier": "Foo.Bar", 45 "Versions": [ 46 { 47 "PackageVersion": "3.0.0abc", 48 "DefaultLocale": { 49 "PackageLocale": "en-US", 50 "Publisher": "Foo", 51 "PublisherUrl": "http://publisher.net", 52 "PublisherSupportUrl": "http://publisherSupport.net", 53 "PrivacyUrl": "http://packagePrivacyUrl.net", 54 "Author": "FooBar", 55 "PackageName": "Bar", 56 "PackageUrl": "http://packageUrl.net", 57 "License": "Foo Bar License", 58 "LicenseUrl": "http://licenseUrl.net", 59 "Copyright": "Foo Bar Copyright", 60 "CopyrightUrl": "http://copyrightUrl.net", 61 "ShortDescription": "Foo bar is a foo bar.", 62 "Description": "Foo bar is a placeholder.", 63 "Tags": [ 64 "FooBar", 65 "Foo", 66 "Bar" 67 ], 68 "Moniker": "FooBarMoniker", 69 "ReleaseNotes": "Default release notes", 70 "ReleaseNotesUrl": "https://DefaultReleaseNotes.net", 71 "Agreements": [{ 72 "AgreementLabel": "DefaultLabel", 73 "Agreement": "DefaultText", 74 "AgreementUrl": "https://DefaultAgreementUrl.net" 75 }], 76 "PurchaseUrl": "http://DefaultPurchaseUrl.net", 77 "InstallationNotes": "Default Installation Notes", 78 "Documentations": [{ 79 "DocumentLabel": "Default Document Label", 80 "DocumentUrl": "http://DefaultDocumentUrl.net" 81 }] 82 }, 83 "Channel": "", 84 "Locales": [ 85 { 86 "PackageLocale": "fr-Fr", 87 "Publisher": "Foo French", 88 "PublisherUrl": "http://publisher-fr.net", 89 "PublisherSupportUrl": "http://publisherSupport-fr.net", 90 "PrivacyUrl": "http://packagePrivacyUrl-fr.net", 91 "Author": "FooBar French", 92 "PackageName": "Bar", 93 "PackageUrl": "http://packageUrl-fr.net", 94 "License": "Foo Bar License", 95 "LicenseUrl": "http://licenseUrl-fr.net", 96 "Copyright": "Foo Bar Copyright", 97 "CopyrightUrl": "http://copyrightUrl-fr.net", 98 "ShortDescription": "Foo bar is a foo bar French.", 99 "Description": "Foo bar is a placeholder French.", 100 "Tags": [ 101 "FooBarFr", 102 "FooFr", 103 "BarFr" 104 ], 105 "ReleaseNotes": "Release notes", 106 "ReleaseNotesUrl": "https://ReleaseNotes.net", 107 "Agreements": [{ 108 "AgreementLabel": "Label", 109 "Agreement": "Text", 110 "AgreementUrl": "https://AgreementUrl.net" 111 }], 112 "PurchaseUrl": "http://purchaseUrl.net", 113 "InstallationNotes": "Installation Notes", 114 "Documentations": [{ 115 "DocumentLabel": "Document Label", 116 "DocumentUrl": "http://documentUrl.net" 117 }] 118 } 119 ], 120 "Installers": [ 121 { 122 "InstallerSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6", 123 "InstallerUrl": "http://foobar.zip", 124 "Architecture": "x86", 125 "InstallerLocale": "en-US", 126 "Platform": [ 127 "Windows.Desktop" 128 ], 129 "MinimumOSVersion": "1078", 130 "InstallerType": "zip", 131 "Scope": "user", 132 "InstallModes": [ 133 "interactive" 134 ], 135 "InstallerSwitches": { 136 "Silent": "/s", 137 "SilentWithProgress": "/s", 138 "Interactive": "/i", 139 "InstallLocation": "C:\\Users\\User1", 140 "Log": "/l", 141 "Upgrade": "/u", 142 "Custom": "/custom" 143 }, 144 "InstallerSuccessCodes": [ 145 0 146 ], 147 "UpgradeBehavior": "install", 148 "Commands": [ 149 "command1" 150 ], 151 "Protocols": [ 152 "protocol1" 153 ], 154 "FileExtensions": [ 155 ".file-extension" 156 ], 157 "Dependencies": { 158 "WindowsFeatures": [ 159 "feature1" 160 ], 161 "WindowsLibraries": [ 162 "library1" 163 ], 164 "PackageDependencies": [ 165 { 166 "PackageIdentifier": "Foo.Baz", 167 "MinimumVersion": "2.0.0" 168 } 169 ], 170 "ExternalDependencies": [ 171 "FooBarBaz" 172 ] 173 }, 174 "ProductCode": "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d", 175 "ReleaseDate": "2021-01-01", 176 "InstallerAbortsTerminal": true, 177 "InstallLocationRequired": true, 178 "RequireExplicitUpgrade": true, 179 "UnsupportedOSArchitectures": [ "arm" ], 180 "ElevationRequirement": "elevatesSelf", 181 "AppsAndFeaturesEntries": [{ 182 "DisplayName": "DisplayName", 183 "DisplayVersion": "DisplayVersion", 184 "Publisher": "Publisher", 185 "ProductCode": "ProductCode", 186 "UpgradeCode": "UpgradeCode", 187 "InstallerType": "exe" 188 }], 189 "Markets" : { 190 "AllowedMarkets": [ "US" ] 191 }, 192 "ExpectedReturnCodes": [{ 193 "InstallerReturnCode": 3, 194 "ReturnResponse": "custom", 195 "ReturnResponseUrl": "http://returnResponseUrl.net" 196 }], 197 "NestedInstallerType": "portable", 198 "DisplayInstallWarnings": true, 199 "UnsupportedArguments": [ "log" ], 200 "NestedInstallerFiles": [{ 201 "RelativeFilePath": "test\\app.exe", 202 "PortableCommandAlias": "test.exe" 203 }], 204 "InstallationMetadata": { 205 "DefaultInstallLocation": "%TEMP%\\DefaultInstallLocation", 206 "Files": [{ 207 "RelativeFilePath": "test\\app.exe", 208 "FileSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6", 209 "FileType": "launch", 210 "InvocationParameter": "/parameter", 211 "DisplayName": "test" 212 }] 213 } 214 } 215 ] 216 } 217 ] 218 }, 219 "ContinuationToken": "abcd" 220 })delimiter"); 221 } 222 223 void VerifyLocalizations_AllFields(const Manifest& manifest) 224 { 225 REQUIRE(manifest.DefaultLocalization.Locale == "en-US"); 226 REQUIRE(manifest.DefaultLocalization.Get<Localization::Publisher>() == "Foo"); 227 REQUIRE(manifest.DefaultLocalization.Get<Localization::PublisherUrl>() == "http://publisher.net"); 228 REQUIRE(manifest.DefaultLocalization.Get<Localization::PublisherSupportUrl>() == "http://publisherSupport.net"); 229 REQUIRE(manifest.DefaultLocalization.Get<Localization::PrivacyUrl>() == "http://packagePrivacyUrl.net"); 230 REQUIRE(manifest.DefaultLocalization.Get<Localization::Author>() == "FooBar"); 231 REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageName>() == "Bar"); 232 REQUIRE(manifest.DefaultLocalization.Get<Localization::PackageUrl>() == "http://packageUrl.net"); 233 REQUIRE(manifest.DefaultLocalization.Get<Localization::License>() == "Foo Bar License"); 234 REQUIRE(manifest.DefaultLocalization.Get<Localization::LicenseUrl>() == "http://licenseUrl.net"); 235 REQUIRE(manifest.DefaultLocalization.Get<Localization::Copyright>() == "Foo Bar Copyright"); 236 REQUIRE(manifest.DefaultLocalization.Get<Localization::CopyrightUrl>() == "http://copyrightUrl.net"); 237 REQUIRE(manifest.DefaultLocalization.Get<Localization::ShortDescription>() == "Foo bar is a foo bar."); 238 REQUIRE(manifest.DefaultLocalization.Get<Localization::Description>() == "Foo bar is a placeholder."); 239 REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>().size() == 3); 240 REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>().at(0) == "FooBar"); 241 REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>().at(1) == "Foo"); 242 REQUIRE(manifest.DefaultLocalization.Get<Localization::Tags>().at(2) == "Bar"); 243 REQUIRE(manifest.DefaultLocalization.Get<Localization::ReleaseNotes>() == "Default release notes"); 244 REQUIRE(manifest.DefaultLocalization.Get<Localization::ReleaseNotesUrl>() == "https://DefaultReleaseNotes.net"); 245 REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().size() == 1); 246 REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).Label == "DefaultLabel"); 247 REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).AgreementText == "DefaultText"); 248 REQUIRE(manifest.DefaultLocalization.Get<Localization::Agreements>().at(0).AgreementUrl == "https://DefaultAgreementUrl.net"); 249 REQUIRE(manifest.DefaultLocalization.Get<Localization::PurchaseUrl>() == "http://DefaultPurchaseUrl.net"); 250 REQUIRE(manifest.DefaultLocalization.Get<Localization::InstallationNotes>() == "Default Installation Notes"); 251 REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().size() == 1); 252 REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().at(0).DocumentLabel == "Default Document Label"); 253 REQUIRE(manifest.DefaultLocalization.Get<Localization::Documentations>().at(0).DocumentUrl == "http://DefaultDocumentUrl.net"); 254 255 REQUIRE(manifest.Localizations.size() == 1); 256 ManifestLocalization frenchLocalization = manifest.Localizations.at(0); 257 REQUIRE(frenchLocalization.Locale == "fr-Fr"); 258 REQUIRE(frenchLocalization.Get<Localization::Publisher>() == "Foo French"); 259 REQUIRE(frenchLocalization.Get<Localization::PublisherUrl>() == "http://publisher-fr.net"); 260 REQUIRE(frenchLocalization.Get<Localization::PublisherSupportUrl>() == "http://publisherSupport-fr.net"); 261 REQUIRE(frenchLocalization.Get<Localization::PrivacyUrl>() == "http://packagePrivacyUrl-fr.net"); 262 REQUIRE(frenchLocalization.Get<Localization::Author>() == "FooBar French"); 263 REQUIRE(frenchLocalization.Get<Localization::PackageName>() == "Bar"); 264 REQUIRE(frenchLocalization.Get<Localization::PackageUrl>() == "http://packageUrl-fr.net"); 265 REQUIRE(frenchLocalization.Get<Localization::License>() == "Foo Bar License"); 266 REQUIRE(frenchLocalization.Get<Localization::LicenseUrl>() == "http://licenseUrl-fr.net"); 267 REQUIRE(frenchLocalization.Get<Localization::Copyright>() == "Foo Bar Copyright"); 268 REQUIRE(frenchLocalization.Get<Localization::CopyrightUrl>() == "http://copyrightUrl-fr.net"); 269 REQUIRE(frenchLocalization.Get<Localization::ShortDescription>() == "Foo bar is a foo bar French."); 270 REQUIRE(frenchLocalization.Get<Localization::Description>() == "Foo bar is a placeholder French."); 271 REQUIRE(frenchLocalization.Get<Localization::Tags>().size() == 3); 272 REQUIRE(frenchLocalization.Get<Localization::Tags>().at(0) == "FooBarFr"); 273 REQUIRE(frenchLocalization.Get<Localization::Tags>().at(1) == "FooFr"); 274 REQUIRE(frenchLocalization.Get<Localization::Tags>().at(2) == "BarFr"); 275 REQUIRE(frenchLocalization.Get<Localization::ReleaseNotes>() == "Release notes"); 276 REQUIRE(frenchLocalization.Get<Localization::ReleaseNotesUrl>() == "https://ReleaseNotes.net"); 277 REQUIRE(frenchLocalization.Get<Localization::Agreements>().size() == 1); 278 REQUIRE(frenchLocalization.Get<Localization::Agreements>().at(0).Label == "Label"); 279 REQUIRE(frenchLocalization.Get<Localization::Agreements>().at(0).AgreementText == "Text"); 280 REQUIRE(frenchLocalization.Get<Localization::Agreements>().at(0).AgreementUrl == "https://AgreementUrl.net"); 281 REQUIRE(frenchLocalization.Get<Localization::PurchaseUrl>() == "http://purchaseUrl.net"); 282 REQUIRE(frenchLocalization.Get<Localization::InstallationNotes>() == "Installation Notes"); 283 REQUIRE(frenchLocalization.Get<Localization::Documentations>().size() == 1); 284 REQUIRE(frenchLocalization.Get<Localization::Documentations>().at(0).DocumentLabel == "Document Label"); 285 REQUIRE(frenchLocalization.Get<Localization::Documentations>().at(0).DocumentUrl == "http://documentUrl.net"); 286 } 287 288 void VerifyInstallers_AllFields(const Manifest& manifest) 289 { 290 REQUIRE(manifest.Installers.size() == 1); 291 292 ManifestInstaller actualInstaller = manifest.Installers.at(0); 293 REQUIRE(actualInstaller.Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6")); 294 REQUIRE(actualInstaller.Url == "http://foobar.zip"); 295 REQUIRE(actualInstaller.Arch == Architecture::X86); 296 REQUIRE(actualInstaller.Locale == "en-US"); 297 REQUIRE(actualInstaller.Platform.size() == 1); 298 REQUIRE(actualInstaller.Platform[0] == PlatformEnum::Desktop); 299 REQUIRE(actualInstaller.MinOSVersion == "1078"); 300 REQUIRE(actualInstaller.BaseInstallerType == InstallerTypeEnum::Zip); 301 REQUIRE(actualInstaller.Scope == ScopeEnum::User); 302 REQUIRE(actualInstaller.InstallModes.size() == 1); 303 REQUIRE(actualInstaller.InstallModes.at(0) == InstallModeEnum::Interactive); 304 REQUIRE(actualInstaller.Switches.size() == 7); 305 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Silent) == "/s"); 306 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::SilentWithProgress) == "/s"); 307 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Interactive) == "/i"); 308 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::InstallLocation) == "C:\\Users\\User1"); 309 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Log) == "/l"); 310 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Update) == "/u"); 311 REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Custom) == "/custom"); 312 REQUIRE(actualInstaller.InstallerSuccessCodes.size() == 1); 313 REQUIRE(actualInstaller.InstallerSuccessCodes.at(0) == 0); 314 REQUIRE(actualInstaller.UpdateBehavior == UpdateBehaviorEnum::Install); 315 REQUIRE(actualInstaller.Commands.at(0) == "command1"); 316 REQUIRE(actualInstaller.Protocols.at(0) == "protocol1"); 317 REQUIRE(actualInstaller.FileExtensions.at(0) == ".file-extension"); 318 REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsFeature, "feature1")); 319 REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsLibrary, "library1")); 320 REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::Package, "Foo.Baz", "2.0.0")); 321 REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::External, "FooBarBaz")); 322 REQUIRE(actualInstaller.PackageFamilyName == ""); 323 REQUIRE(actualInstaller.ProductCode == "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d"); 324 REQUIRE(actualInstaller.ReleaseDate == "2021-01-01"); 325 REQUIRE(actualInstaller.InstallerAbortsTerminal); 326 REQUIRE(actualInstaller.InstallLocationRequired); 327 REQUIRE(actualInstaller.RequireExplicitUpgrade); 328 REQUIRE(actualInstaller.ElevationRequirement == ElevationRequirementEnum::ElevatesSelf); 329 REQUIRE(actualInstaller.UnsupportedOSArchitectures.size() == 1); 330 REQUIRE(actualInstaller.UnsupportedOSArchitectures.at(0) == Architecture::Arm); 331 REQUIRE(actualInstaller.AppsAndFeaturesEntries.size() == 1); 332 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayName == "DisplayName"); 333 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayVersion == "DisplayVersion"); 334 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).Publisher == "Publisher"); 335 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).ProductCode == "ProductCode"); 336 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).UpgradeCode == "UpgradeCode"); 337 REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe); 338 REQUIRE(actualInstaller.Markets.AllowedMarkets.size() == 1); 339 REQUIRE(actualInstaller.Markets.AllowedMarkets.at(0) == "US"); 340 REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseEnum == ExpectedReturnCodeEnum::Custom); 341 REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseUrl == "http://returnResponseUrl.net"); 342 REQUIRE(actualInstaller.NestedInstallerType == InstallerTypeEnum::Portable); 343 REQUIRE(actualInstaller.DisplayInstallWarnings); 344 REQUIRE(actualInstaller.UnsupportedArguments.size() == 1); 345 REQUIRE(actualInstaller.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Log); 346 REQUIRE(actualInstaller.NestedInstallerFiles.size() == 1); 347 REQUIRE(actualInstaller.NestedInstallerFiles.at(0).RelativeFilePath == "test\\app.exe"); 348 REQUIRE(actualInstaller.NestedInstallerFiles.at(0).PortableCommandAlias == "test.exe"); 349 REQUIRE(actualInstaller.InstallationMetadata.DefaultInstallLocation == "%TEMP%\\DefaultInstallLocation"); 350 REQUIRE(actualInstaller.InstallationMetadata.Files.size() == 1); 351 REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).RelativeFilePath == "test\\app.exe"); 352 REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Launch); 353 REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileSha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6")); 354 REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).InvocationParameter == "/parameter"); 355 REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).DisplayName == "test"); 356 } 357 }; 358 } 359 360 TEST_CASE("GetManifests_GoodResponse_V1_4", "[RestSource][Interface_1_4]") 361 { 362 GoodManifest_AllFields sampleManifest; 363 utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); 364 HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; 365 Interface v1_4{ TestRestUriString, std::move(helper), {} }; 366 std::vector<Manifest> manifests = v1_4.GetManifests("Foo.Bar"); 367 REQUIRE(manifests.size() == 1); 368 369 // Verify manifest is populated 370 Manifest& manifest = manifests[0]; 371 REQUIRE(manifest.Id == "Foo.Bar"); 372 REQUIRE(manifest.Version == "3.0.0abc"); 373 REQUIRE(manifest.Moniker == "FooBarMoniker"); 374 REQUIRE(manifest.Channel == ""); 375 REQUIRE(manifest.ManifestVersion == AppInstaller::Manifest::ManifestVer{ "1.4.0" }); 376 sampleManifest.VerifyLocalizations_AllFields(manifest); 377 sampleManifest.VerifyInstallers_AllFields(manifest); 378 } 379 380 TEST_CASE("Search_GoodResponse_V1_4", "[RestSource][Interface_1_4]") 381 { 382 utility::string_t sample = _XPLATSTR( 383 R"delimiter({ 384 "Data" : [{ 385 "PackageIdentifier": "git.package", 386 "PackageName": "package", 387 "Publisher": "git", 388 "Versions": [{ 389 "PackageVersion": "1.0.0", 390 "PackageFamilyNames": [ 391 "pfn1" 392 ], 393 "ProductCodes": [ 394 "pc1" 395 ], 396 "UpgradeCodes": [ 397 "upgradeCode" 398 ], 399 "AppsAndFeaturesEntryVersions": [ 400 "2.0", 401 "1.0" 402 ] 403 }] 404 }] 405 })delimiter"); 406 407 HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; 408 Interface v1_4{ TestRestUriString, std::move(helper), {} }; 409 Schema::IRestClient::SearchResult searchResponse = v1_4.Search({}); 410 REQUIRE(searchResponse.Matches.size() == 1); 411 Schema::IRestClient::Package package = searchResponse.Matches.at(0); 412 REQUIRE(package.PackageInformation.PackageIdentifier.compare("git.package") == 0); 413 REQUIRE(package.PackageInformation.Publisher.compare("git") == 0); 414 REQUIRE(package.PackageInformation.PackageName.compare("package") == 0); 415 REQUIRE(package.Versions.size() == 1); 416 REQUIRE(package.Versions.at(0).VersionAndChannel.GetVersion().ToString().compare("1.0.0") == 0); 417 REQUIRE(package.Versions.at(0).PackageFamilyNames.size() == 1); 418 REQUIRE(package.Versions.at(0).PackageFamilyNames.at(0) == "pfn1"); 419 REQUIRE(package.Versions.at(0).ProductCodes.size() == 1); 420 REQUIRE(package.Versions.at(0).ProductCodes.at(0) == "pc1"); 421 REQUIRE(package.Versions.at(0).UpgradeCodes.size() == 1); 422 REQUIRE(package.Versions.at(0).UpgradeCodes.at(0) == "upgradeCode"); 423 REQUIRE(package.Versions.at(0).ArpVersions.size() == 2); 424 REQUIRE(package.Versions.at(0).ArpVersions.at(0).ToString() == "1.0"); 425 REQUIRE(package.Versions.at(0).ArpVersions.at(1).ToString() == "2.0"); 426 }