From 9fd1078397f05b527eea8f496f3c6f9832d81503 Mon Sep 17 00:00:00 2001 From: Muhammad Danish Date: Thu, 14 Dec 2023 03:58:13 +0500 Subject: [PATCH] Retain non-null installer fields when copying over root values (#491) --- src/WingetCreateCLI/Commands/BaseCommand.cs | 10 +- src/WingetCreateCLI/Commands/UpdateCommand.cs | 7 - ...ublisher.OverwriteNullInstallerFields.yaml | 88 +++++++++++ ... TestPublisher.RetainInstallerFields.yaml} | 87 ++--------- .../UnitTests/UpdateCommandTests.cs | 142 +++++++++++++++++- .../WingetCreateTests.csproj | 5 +- 6 files changed, 252 insertions(+), 87 deletions(-) create mode 100644 src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverwriteNullInstallerFields.yaml rename src/WingetCreateTests/WingetCreateTests/Resources/{TestPublisher.OverrideInstallerFields.yaml => TestPublisher.RetainInstallerFields.yaml} (60%) diff --git a/src/WingetCreateCLI/Commands/BaseCommand.cs b/src/WingetCreateCLI/Commands/BaseCommand.cs index 3c4ed842..737b59bc 100644 --- a/src/WingetCreateCLI/Commands/BaseCommand.cs +++ b/src/WingetCreateCLI/Commands/BaseCommand.cs @@ -422,6 +422,7 @@ protected static void RemoveEmptyStringFieldsInManifests(Manifests manifests) /// /// Shifts common installer fields from manifest root to installer level. + /// If value is already defined at the installer level, then it should not be overwritten. /// /// Wrapper object containing the installer manifest object models. protected static void ShiftRootFieldsToInstallerLevel(InstallerManifest installerManifest) @@ -439,8 +440,13 @@ protected static void ShiftRootFieldsToInstallerLevel(InstallerManifest installe { foreach (var installer in installerManifest.Installers) { - // Copy the value to installer level - installer.GetType().GetProperty(property.Name).SetValue(installer, rootValue); + var installerProperty = installer.GetType().GetProperty(property.Name); + + // Only set the value if it is null at the installer level + if (installerProperty.GetValue(installer) == null) + { + installerProperty.SetValue(installer, rootValue); + } } // Set root value to null diff --git a/src/WingetCreateCLI/Commands/UpdateCommand.cs b/src/WingetCreateCLI/Commands/UpdateCommand.cs index 391b340e..afd6b902 100644 --- a/src/WingetCreateCLI/Commands/UpdateCommand.cs +++ b/src/WingetCreateCLI/Commands/UpdateCommand.cs @@ -460,13 +460,6 @@ public Manifests DeserializeManifestContentAndApplyInitialUpdate(List la UpdatePropertyForLocaleManifests(nameof(LocaleManifest.PackageVersion), this.Version, localeManifests); } - // TODO: Move relevant metadata from root node to installer node. - if (installerManifest.InstallerType != null) - { - installerManifest.Installers.ForEach(i => i.InstallerType = installerManifest.InstallerType); - installerManifest.InstallerType = null; - } - return manifests; } diff --git a/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverwriteNullInstallerFields.yaml b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverwriteNullInstallerFields.yaml new file mode 100644 index 00000000..eb089e0e --- /dev/null +++ b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverwriteNullInstallerFields.yaml @@ -0,0 +1,88 @@ +PackageIdentifier: TestPublisher.OverwriteNullInstallerFields +PackageVersion: 0.1.2 +PackageName: Overwrite installer level fields by root fields +Publisher: Test publisher +License: MIT +ShortDescription: A manifest that verifies that installer level fields are overwritten by root fields. +Description: |- + Expected flow: + + 1) Installer level fields are overwritten by root fields at the start of the update. + 2) The update flow modifies the installer level fields if needed. (e.g. ProductCode in case of MSI upgrade) + 3) At the end of the update, the common installer fields are moved to the root level. +InstallerLocale: en-US +InstallerType: zip +NestedInstallerType: exe +NestedInstallerFiles: +- RelativeFilePath: WingetCreateTestExeInstaller.exe + PortableCommandAlias: PortableCommandAlias1 +AppsAndFeaturesEntries: +- DisplayName: TestDisplayName1 + Publisher: TestPublisher1 + DisplayVersion: 1.0.1 + ProductCode: TestProductCode1 + UpgradeCode: TestUpgradeCode1 + InstallerType: msi +InstallerSwitches: + Silent: /silent1 + SilentWithProgress: /silentwithprogress1 +Dependencies: + PackageDependencies: + - PackageIdentifier: TestPackageDependency1 + MinimumVersion: 1.0.1 + WindowsFeatures: + - TestWindowsFeature1 + ExternalDependencies: + - TestExternalDependency1 + WindowsLibraries: + - TestWindowsLibrary1 +ExpectedReturnCodes: + - InstallerReturnCode: 1001 + ReturnResponse: installInProgress +MinimumOSVersion: 10.0.22000.0 +PackageFamilyName: TestPackageFamilyName1 +Platform: +- Windows.Desktop +Scope: machine +UpgradeBehavior: install +ElevationRequirement: elevationRequired +Commands: + - fakeCommand1 +Protocols: + - fakeProtocol1 +FileExtensions: + - .exe +# Uncomment when installer model gets updated to support these fields +#Markets: +# AllowedMarkets: +# - fakeAllowedMarket +# ExcludedMarkets: +# - fakeExcludedMarket +InstallerAbortsTerminal: true +InstallLocationRequired: true +RequireExplicitUpgrade: true +UnsupportedOSArchitectures: + - arm64 +DisplayInstallWarnings: true +InstallerSuccessCodes: + - 1 +UnsupportedArguments: + - log + - location +InstallationMetadata: + DefaultInstallLocation: "%ProgramFiles%\\TestApp1" + Files: + - RelativeFilePath: "main1.exe" + FileSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82 + FileType: launch + InvocationParameter: "/arg1" +Installers: + - Architecture: x64 + InstallerUrl: https://fakedomain.com/WingetCreateTestZipInstaller.zip + InstallerSha256: 8A052767127A6E2058BAAE03B551A807777BB1B726650E2C7E92C3E92C8DF80D + - Architecture: x86 + InstallerUrl: https://fakedomain.com/WingetCreateTestZipInstaller.zip + InstallerSha256: 8A052767127A6E2058BAAE03B551A807777BB1B726650E2C7E92C3E92C8DF80D +PackageLocale: en-US +ManifestType: singleton +ManifestVersion: 1.4.0 \ No newline at end of file diff --git a/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverrideInstallerFields.yaml b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.RetainInstallerFields.yaml similarity index 60% rename from src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverrideInstallerFields.yaml rename to src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.RetainInstallerFields.yaml index 062adbf1..ce0587b3 100644 --- a/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.OverrideInstallerFields.yaml +++ b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.RetainInstallerFields.yaml @@ -1,21 +1,24 @@ -PackageIdentifier: TestPublisher.OverrideInstallerFields +PackageIdentifier: TestPublisher.RetainInstallerFields PackageVersion: 0.1.2 -PackageName: Override installer level fields by root fields +PackageName: Retain installer level fields when copying over root values Publisher: Test publisher License: MIT -ShortDescription: A manifest that verifies that installer level fields are overridden by root fields. +ShortDescription: A manifest that verifies that non-null installer level fields are not overwritten by root fields. Description: |- Expected flow: - 1) Installer level fields are overridden by root fields at the start of the update. - 2) The update flow modifies the installer level fields if needed. (e.g. ProductCode in case of MSI upgrade) - 3) At the end of the update, the common installer fields are moved to the root level. + 1) For the first installer, all root level fields are copied over and root fields are set to null. + 2) For the second installer, installer level fields are preserved since they are not null. + 3) InstallerType and NestedInstallerType are common across both installers, so they are moved to the root level at the end of the update. + + TODO: Use different NestedInstallerType and RelativeFilePath for each installer once logic for handling multiple nested installers is improved. + Reference: https://github.com/microsoft/winget-create/issues/392 InstallerLocale: en-US InstallerType: zip NestedInstallerType: exe NestedInstallerFiles: - RelativeFilePath: WingetCreateTestExeInstaller.exe - PortableCommandAlias: PortableCommandAlias1 + PortableCommandAlias: TestAlias AppsAndFeaturesEntries: - DisplayName: TestDisplayName1 Publisher: TestPublisher1 @@ -78,80 +81,16 @@ InstallationMetadata: InvocationParameter: "/arg1" Installers: - Architecture: x64 - InstallerType: zip InstallerUrl: https://fakedomain.com/WingetCreateTestZipInstaller.zip InstallerSha256: 8A052767127A6E2058BAAE03B551A807777BB1B726650E2C7E92C3E92C8DF80D - NestedInstallerType: msi - NestedInstallerFiles: - - RelativeFilePath: WingetCreateTestExeInstaller.exe - PortableCommandAlias: PortableCommandAlias2 - AppsAndFeaturesEntries: - - DisplayName: TestDisplayName2 - Publisher: TestPublisher2 - DisplayVersion: 1.0.2 - ProductCode: TestProductCode2 - UpgradeCode: TestUpgradeCode2 - InstallerType: exe - InstallerSwitches: - Silent: /silent2 - SilentWithProgress: /silentwithprogress2 - Dependencies: - PackageDependencies: - - PackageIdentifier: TestPackageDependency2 - MinimumVersion: 1.0.2 - WindowsFeatures: - - TestWindowsFeature2 - ExternalDependencies: - - TestExternalDependency2 - WindowsLibraries: - - TestWindowsLibrary2 - ExpectedReturnCodes: - - InstallerReturnCode: 1002 - ReturnResponse: installInProgress - MinimumOSVersion: 10.0.17763.0 - PackageFamilyName: TestPackageFamilyName2 - Platform: - - Windows.Universal - Scope: user - UpgradeBehavior: uninstallPrevious - ElevationRequirement: elevatesSelf - Commands: - - fakeCommand2 - Protocols: - - fakeProtocol2 - FileExtensions: - - .msi - # Uncomment when installer model gets updated to support these fields - #Markets: - # AllowedMarkets: - # - fakeAllowedMarket - # ExcludedMarkets: - # - fakeExcludedMarket - InstallerAbortsTerminal: false - InstallLocationRequired: false - RequireExplicitUpgrade: false - UnsupportedOSArchitectures: - - arm - DisplayInstallWarnings: false - InstallerSuccessCodes: - - 2 - UnsupportedArguments: - - log - InstallationMetadata: - DefaultInstallLocation: "%ProgramFiles%\\TestApp2" - Files: - - RelativeFilePath: "main2.exe" - FileSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82 - FileType: launch - InvocationParameter: "/arg2" - Architecture: x86 InstallerType: zip InstallerUrl: https://fakedomain.com/WingetCreateTestZipInstaller.zip InstallerSha256: 8A052767127A6E2058BAAE03B551A807777BB1B726650E2C7E92C3E92C8DF80D - NestedInstallerType: msi + NestedInstallerType: exe NestedInstallerFiles: - RelativeFilePath: WingetCreateTestExeInstaller.exe - PortableCommandAlias: PortableCommandAlias2 + PortableCommandAlias: TestAlias AppsAndFeaturesEntries: - DisplayName: TestDisplayName2 Publisher: TestPublisher2 @@ -188,7 +127,7 @@ Installers: - fakeProtocol2 FileExtensions: - .msi - # Uncomment when installer model gets updated to support these fields + # TODO: Uncomment when installer model gets updated to support these fields #Markets: # AllowedMarkets: # - fakeAllowedMarket diff --git a/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs b/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs index 7610ffeb..cdf92714 100644 --- a/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs +++ b/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs @@ -1076,15 +1076,19 @@ public async Task DontMoveInstallerFieldsToRoot() } /// - /// Verifies that installer fields are overridden by root fields in update scenario. + /// Verifies that null installer fields are overwritten by root fields in update scenario. + /// Expected flow: + /// 1) Null installer level fields are overwritten by root fields at the start of the update. + /// 2) The update flow modifies the installer level fields if needed. (e.g. ProductCode in case of MSI upgrade) + /// 3) At the end of the update, the common installer fields are moved to the root level. /// /// A representing the result of the asynchronous operation. [Test] - public async Task UpdateOverridesInstallerFields() + public async Task UpdateOverwritesNullInstallerFields() { TestUtils.InitializeMockDownloads(TestConstants.TestZipInstaller); string installerUrl = $"https://fakedomain.com/{TestConstants.TestZipInstaller}"; - (UpdateCommand command, var initialManifestContent) = GetUpdateCommandAndManifestData("TestPublisher.OverrideInstallerFields", null, this.tempPath, new[] { $"{installerUrl}|x64", $"{installerUrl}|x86" }); + (UpdateCommand command, var initialManifestContent) = GetUpdateCommandAndManifestData("TestPublisher.OverwriteNullInstallerFields", null, this.tempPath, new[] { $"{installerUrl}|x64", $"{installerUrl}|x86" }); var updatedManifests = await RunUpdateCommand(command, initialManifestContent); Assert.IsNotNull(updatedManifests, "Command should have succeeded"); @@ -1162,6 +1166,138 @@ public async Task UpdateOverridesInstallerFields() } } + /// + /// Verifies that non-null installer fields are preserved when overwriting with root fields at the start of the update. + /// Expected flow: + /// 1) For the first installer, all root level fields are copied over and root fields are set to null. + /// 2) For the second installer, installer level fields are preserved since they are not null. + /// 3) InstallerType, NestedInstallerType and NestedInstallerFiles are common across both installers, so they are moved to the root level at the end of the update. + /// TODO: Use different NestedInstallerType and RelativeFilePath for each installer once logic for handling multiple nested installers is improved. + /// Reference: https://github.com/microsoft/winget-create/issues/392. + /// + /// A representing the result of the asynchronous operation. + [Test] + public async Task UpdateRetainsNonNullInstallerFields() + { + TestUtils.InitializeMockDownloads(TestConstants.TestZipInstaller); + string installerUrl = $"https://fakedomain.com/{TestConstants.TestZipInstaller}"; + (UpdateCommand command, var initialManifestContent) = GetUpdateCommandAndManifestData("TestPublisher.RetainInstallerFields", null, this.tempPath, new[] { $"{installerUrl}|x64", $"{installerUrl}|x86" }); + var updatedManifests = await RunUpdateCommand(command, initialManifestContent); + Assert.IsNotNull(updatedManifests, "Command should have succeeded"); + + InstallerManifest updatedInstallerManifest = updatedManifests.InstallerManifest; + Installer firstInstaller = updatedInstallerManifest.Installers[0]; + Installer secondInstaller = updatedInstallerManifest.Installers[1]; + + // Fields for first installer should be copied over from root + Assert.IsTrue(firstInstaller.Scope == Scope.Machine, "Scope for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.MinimumOSVersion == "10.0.22000.0", "MinimumOSVersion for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.PackageFamilyName == "TestPackageFamilyName1", "PackageFamilyName for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.UpgradeBehavior == UpgradeBehavior.Install, "UpgradeBehavior for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.ElevationRequirement == ElevationRequirement.ElevationRequired, "ElevationRequirement for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.InstallerAbortsTerminal == true, "InstallerAbortsTerminal for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.InstallLocationRequired == true, "InstallLocation for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.RequireExplicitUpgrade == true, "RequireExplicitUpgrade for the first installer should be copied over from root"); + Assert.IsTrue(firstInstaller.DisplayInstallWarnings == true, "DisplayInstallWarnings for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.InstallerSwitches, "InstallerSwitches for the first installer should not be null"); + Assert.IsTrue(firstInstaller.InstallerSwitches.Silent == "/silent1", "Silent installer switch for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.Dependencies, "Dependencies for the first installer should not be null"); + Assert.IsTrue(firstInstaller.Dependencies.PackageDependencies[0].PackageIdentifier == "TestPackageDependency1", "PackageDependencies PackageIdentifier for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.AppsAndFeaturesEntries, "AppsAndFeaturesEntries for the first installer should not be null"); + Assert.IsTrue(firstInstaller.AppsAndFeaturesEntries[0].ProductCode == "TestProductCode1", "AppsAndFeaturesEntries ProductCode for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.Platform, "Platform for the first installer should not be null"); + Assert.IsTrue(firstInstaller.Platform[0] == Platform.Windows_Desktop, "Platform for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.ExpectedReturnCodes, "ExpectedReturnCodes afor the first installer should not be null"); + Assert.IsTrue(firstInstaller.ExpectedReturnCodes[0].InstallerReturnCode == 1001, "ExpectedReturnCodes InstallerReturnCode for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.Commands, "Commands for the first installer should not be null"); + Assert.IsTrue(firstInstaller.Commands[0] == "fakeCommand1", "Commands for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.Protocols, "Protocols for the first installer should not be null"); + Assert.IsTrue(firstInstaller.Protocols[0] == "fakeProtocol1", "Protocols for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.FileExtensions, "FileExtensions for the first installer should not be null"); + Assert.IsTrue(firstInstaller.FileExtensions[0] == ".exe", "FileExtensions for the first installer should be copied over from root"); + + // TODO: Uncomment when installer model gets updated to support markets field. + // Assert.IsNotNull(firstInstaller.Markets, "Markets for the first installer should not be null"); + Assert.IsNotNull(firstInstaller.UnsupportedOSArchitectures, "UnsupportedOSArchitectures for the first installer should not be null"); + Assert.IsTrue(firstInstaller.UnsupportedOSArchitectures[0] == UnsupportedOSArchitecture.Arm64, "UnsupportedOSArchitectures for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.InstallerSuccessCodes, "InstallerSuccessCodes for the first installer should not be null"); + Assert.IsTrue(firstInstaller.InstallerSuccessCodes[0] == 1, "InstallerSuccessCodes for the first installer should contain be copied over from root"); + Assert.IsNotNull(firstInstaller.UnsupportedArguments, "UnsupportedArguments for the first installer should not be null"); + Assert.IsTrue(firstInstaller.UnsupportedArguments[1] == UnsupportedArgument.Location, "UnsupportedArguments for the first installer should be copied over from root"); + Assert.IsNotNull(firstInstaller.InstallationMetadata, "InstallationMetadata for the first installer should not be null"); + Assert.IsTrue(firstInstaller.InstallationMetadata.DefaultInstallLocation == "%ProgramFiles%\\TestApp1", "DefaultInstallLocation for the first installer should be copied over from root"); + + // Fields for second installer should be preserved + Assert.IsTrue(secondInstaller.Scope == Scope.User, "Scope for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.MinimumOSVersion == "10.0.17763.0", "MinimumOSVersion for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.PackageFamilyName == "TestPackageFamilyName2", "PackageFamilyName for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.UpgradeBehavior == UpgradeBehavior.UninstallPrevious, "UpgradeBehavior for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.ElevationRequirement == ElevationRequirement.ElevatesSelf, "ElevationRequirement for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.InstallerAbortsTerminal == false, "InstallerAbortsTerminal for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.InstallLocationRequired == false, "InstallLocation for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.RequireExplicitUpgrade == false, "RequireExplicitUpgrade for the second installer should be preserved"); + Assert.IsTrue(secondInstaller.DisplayInstallWarnings == false, "DisplayInstallWarnings for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.InstallerSwitches, "InstallerSwitches for the second installer should not be null"); + Assert.IsTrue(secondInstaller.InstallerSwitches.Silent == "/silent2", "Silent installer switch for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.Dependencies, "Dependencies for the second installer should not be null"); + Assert.IsTrue(secondInstaller.Dependencies.PackageDependencies[0].PackageIdentifier == "TestPackageDependency2", "PackageDependencies PackageIdentifier for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.AppsAndFeaturesEntries, "AppsAndFeaturesEntries for the second installer should not be null"); + Assert.IsTrue(secondInstaller.AppsAndFeaturesEntries[0].ProductCode == "TestProductCode2", "AppsAndFeaturesEntries ProductCode for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.Platform, "Platform for the second installer should not be null"); + Assert.IsTrue(secondInstaller.Platform[0] == Platform.Windows_Universal, "Platform for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.ExpectedReturnCodes, "ExpectedReturnCodes for the second installer should not be null"); + Assert.IsTrue(secondInstaller.ExpectedReturnCodes[0].InstallerReturnCode == 1002, "ExpectedReturnCodes InstallerReturnCode for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.Commands, "Commands for the second installer should not be null"); + Assert.IsTrue(secondInstaller.Commands[0] == "fakeCommand2", "Commands for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.Protocols, "Protocols for the second installer should not be null"); + Assert.IsTrue(secondInstaller.Protocols[0] == "fakeProtocol2", "Protocols for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.FileExtensions, "FileExtensions for the second installer should not be null"); + Assert.IsTrue(secondInstaller.FileExtensions[0] == ".msi", "FileExtensions for the second installer should be preserved"); + + // TODO: Uncomment when installer model gets updated to support markets field. + // Assert.IsNotNull(secondInstaller.Markets, "Markets for the first installer should not be null"); + Assert.IsNotNull(secondInstaller.UnsupportedOSArchitectures, "UnsupportedOSArchitectures for the second installer should not be null"); + Assert.IsTrue(secondInstaller.UnsupportedOSArchitectures[0] == UnsupportedOSArchitecture.Arm, "UnsupportedOSArchitectures for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.InstallerSuccessCodes, "InstallerSuccessCodes for the second installer should not be null"); + Assert.IsTrue(secondInstaller.InstallerSuccessCodes[0] == 2, "InstallerSuccessCodes for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.UnsupportedArguments, "UnsupportedArguments for the second installer should not be null"); + Assert.IsTrue(secondInstaller.UnsupportedArguments[0] == UnsupportedArgument.Log, "UnsupportedArguments for the second installer should be preserved"); + Assert.IsNotNull(secondInstaller.InstallationMetadata, "InstallationMetadata for the second installer should not be null"); + Assert.IsTrue(secondInstaller.InstallationMetadata.DefaultInstallLocation == "%ProgramFiles%\\TestApp2", "DefaultInstallLocation for the second installer should be preserved"); + + // Root fields should be null + Assert.IsNull(updatedInstallerManifest.Scope, "Scope at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.MinimumOSVersion, "MinimumOSVersion at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.PackageFamilyName, "PackageFamilyName at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.UpgradeBehavior, "UpgradeBehavior at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.ElevationRequirement, "ElevationRequirement at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.InstallerAbortsTerminal, "InstallerAbortsTerminal at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.InstallLocationRequired, "InstallLocation at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.RequireExplicitUpgrade, "RequireExplicitUpgrade at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.DisplayInstallWarnings, "DisplayInstallWarnings at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.InstallerSwitches, "InstallerSwitches at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.Dependencies, "Dependencies at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.AppsAndFeaturesEntries, "AppsAndFeaturesEntries at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.Platform, "Platform at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.ExpectedReturnCodes, "ExpectedReturnCodes at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.Commands, "Commands at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.Protocols, "Protocols at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.FileExtensions, "FileExtensions at the root level should be null"); + + // TODO: Uncomment when installer model gets updated to support markets field. + // Assert.IsNull(updatedInstallerManifest.Markets, "Markets at the root level should be null"); + Assert.IsNull(updatedInstallerManifest.UnsupportedOSArchitectures, "UnsupportedOSArchitectures at the installer level should be null"); + Assert.IsNull(updatedInstallerManifest.InstallerSuccessCodes, "InstallerSuccessCodes at the installer level should be null"); + Assert.IsNull(updatedInstallerManifest.UnsupportedArguments, "UnsupportedArguments at the installer level should be null"); + Assert.IsNull(updatedInstallerManifest.InstallationMetadata, "InstallationMetadata at the installer level should be null"); + + // Fields that should be moved to root + Assert.IsTrue(updatedInstallerManifest.InstallerType == InstallerType.Zip, "InstallerType at the root level should be ZIP"); + Assert.IsTrue(updatedInstallerManifest.NestedInstallerType == NestedInstallerType.Exe, "NestedInstallerType at the root level should be EXE"); + Assert.IsNotNull(updatedInstallerManifest.NestedInstallerFiles, "NestedInstallerFiles at the root level should not be null"); + Assert.IsTrue(updatedInstallerManifest.NestedInstallerFiles[0].PortableCommandAlias == "TestAlias", "PortableCommandAlias at the root level should be TestAlias"); + } + /// /// Verifies that the appropriate error message is displayed if the nested installer is not found. /// diff --git a/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj b/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj index afa8a83d..a21a583a 100644 --- a/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj +++ b/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj @@ -36,7 +36,10 @@ PreserveNewest - + + PreserveNewest + + PreserveNewest