winget-cli

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

OpenConfigurationSetTests.cs (56283B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="OpenConfigurationSetTests.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.Management.Configuration.UnitTests.Tests
      8 {
      9     using System;
     10     using System.Collections.Generic;
     11     using System.DirectoryServices;
     12     using Microsoft.Management.Configuration.Processor.Extensions;
     13     using Microsoft.Management.Configuration.UnitTests.Fixtures;
     14     using Microsoft.Management.Configuration.UnitTests.Helpers;
     15     using Microsoft.VisualBasic;
     16     using Windows.Foundation.Collections;
     17     using Windows.Storage.Streams;
     18     using WinRT;
     19     using Xunit;
     20     using Xunit.Abstractions;
     21 
     22     /// <summary>
     23     /// Unit tests for parsing configuration sets from streams.
     24     /// </summary>
     25     [Collection("UnitTestCollection")]
     26     [InProc]
     27     [OutOfProc]
     28     public class OpenConfigurationSetTests : ConfigurationProcessorTestBase
     29     {
     30         /// <summary>
     31         /// The directives key for the module property.
     32         /// </summary>
     33         internal const string ModuleDirective = "module";
     34 
     35         /// <summary>
     36         /// Initializes a new instance of the <see cref="OpenConfigurationSetTests"/> class.
     37         /// </summary>
     38         /// <param name="fixture">Unit test fixture.</param>
     39         /// <param name="log">Log helper.</param>
     40         public OpenConfigurationSetTests(UnitTestFixture fixture, ITestOutputHelper log)
     41             : base(fixture, log)
     42         {
     43         }
     44 
     45         /// <summary>
     46         /// Passes a null stream as input.
     47         /// </summary>
     48         [Fact]
     49         public void NullStream()
     50         {
     51             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
     52 
     53             OpenConfigurationSetResult result = processor.OpenConfigurationSet(null);
     54             Assert.Null(result.Set);
     55             Assert.IsType<NullReferenceException>(result.ResultCode);
     56             Assert.Equal(string.Empty, result.Field);
     57         }
     58 
     59         /// <summary>
     60         /// Passes an empty stream as input.
     61         /// </summary>
     62         [Fact]
     63         public void EmptyStream()
     64         {
     65             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
     66 
     67             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(string.Empty));
     68             Assert.Null(result.Set);
     69             Assert.NotNull(result.ResultCode);
     70             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_YAML, result.ResultCode.HResult);
     71             Assert.Equal(string.Empty, result.Field);
     72             Assert.Equal(0U, result.Line);
     73             Assert.Equal(0U, result.Column);
     74         }
     75 
     76         /// <summary>
     77         /// Passes a stream with a single null byte in it.
     78         /// </summary>
     79         [Fact]
     80         public void NullByteStream()
     81         {
     82             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
     83 
     84             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream("\0"));
     85             Assert.Null(result.Set);
     86             Assert.NotNull(result.ResultCode);
     87             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_YAML, result.ResultCode.HResult);
     88             Assert.NotEqual(string.Empty, result.Field);
     89             Assert.Equal(0U, result.Line);
     90             Assert.Equal(0U, result.Column);
     91         }
     92 
     93         /// <summary>
     94         /// Passes YAML, but it isn't anything like a configuration file.
     95         /// </summary>
     96         [Fact]
     97         public void NotConfigYAML()
     98         {
     99             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    100 
    101             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream("yaml: yep"));
    102             Assert.Null(result.Set);
    103             Assert.NotNull(result.ResultCode);
    104             Assert.Equal(Errors.WINGET_CONFIG_ERROR_MISSING_FIELD, result.ResultCode.HResult);
    105             Assert.Equal("$schema", result.Field);
    106             Assert.Equal(0U, result.Line);
    107             Assert.Equal(0U, result.Column);
    108         }
    109 
    110         /// <summary>
    111         /// Passes YAML without a schema version.
    112         /// </summary>
    113         [Fact]
    114         public void NoConfigVersion()
    115         {
    116             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    117 
    118             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    119 properties:
    120   thing: 1
    121 "));
    122             Assert.Null(result.Set);
    123             Assert.NotNull(result.ResultCode);
    124             Assert.Equal(Errors.WINGET_CONFIG_ERROR_MISSING_FIELD, result.ResultCode.HResult);
    125             Assert.Equal("configurationVersion", result.Field);
    126             Assert.Equal(0U, result.Line);
    127             Assert.Equal(0U, result.Column);
    128         }
    129 
    130         /// <summary>
    131         /// Passes YAML that appears to be from the distant future.
    132         /// </summary>
    133         [Fact]
    134         public void UnknownConfigVersion()
    135         {
    136             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    137 
    138             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    139 properties:
    140   configurationVersion: 99999999
    141 "));
    142             Assert.Null(result.Set);
    143             Assert.NotNull(result.ResultCode);
    144             Assert.Equal(Errors.WINGET_CONFIG_ERROR_UNKNOWN_CONFIGURATION_FILE_VERSION, result.ResultCode.HResult);
    145             Assert.Equal("configurationVersion", result.Field);
    146             Assert.Equal("99999999", result.Value);
    147             Assert.Equal(0U, result.Line);
    148             Assert.Equal(0U, result.Column);
    149         }
    150 
    151         /// <summary>
    152         /// Has one of each type of intent to ensure that it is set properly.
    153         /// </summary>
    154         [Fact]
    155         public void EnsureIntent()
    156         {
    157             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    158 
    159             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    160 properties:
    161   configurationVersion: 0.1
    162   assertions:
    163     - resource: Assert
    164   parameters:
    165     - resource: Inform
    166   resources:
    167     - resource: Apply
    168 "));
    169 
    170             Assert.NotNull(result.Set);
    171             Assert.Null(result.ResultCode);
    172             Assert.Equal(string.Empty, result.Field);
    173 
    174             var units = result.Set.Units;
    175             Assert.Equal(3, units.Count);
    176             bool sawAssert = false;
    177             bool sawInform = false;
    178             bool sawApply = false;
    179 
    180             foreach (var unit in units)
    181             {
    182                 Assert.Equal(unit.Type, unit.Intent.ToString());
    183                 switch (unit.Intent)
    184                 {
    185                     case ConfigurationUnitIntent.Assert: sawAssert = true; break;
    186                     case ConfigurationUnitIntent.Inform: sawInform = true; break;
    187                     case ConfigurationUnitIntent.Apply: sawApply = true; break;
    188                     default: Assert.Fail("Unknown intent"); break;
    189                 }
    190             }
    191 
    192             Assert.True(sawAssert);
    193             Assert.True(sawInform);
    194             Assert.True(sawApply);
    195         }
    196 
    197         /// <summary>
    198         /// Passes YAML with resources being something other than a sequence.
    199         /// </summary>
    200         [Fact]
    201         public void NonSequenceUnits()
    202         {
    203             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    204 
    205             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    206 properties:
    207   configurationVersion: 0.1
    208   resources: 1
    209 "));
    210             Assert.Null(result.Set);
    211             Assert.NotNull(result.ResultCode);
    212             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_TYPE, result.ResultCode.HResult);
    213             Assert.Equal("resources", result.Field);
    214             Assert.Equal(4U, result.Line);
    215             Assert.NotEqual(0U, result.Column);
    216         }
    217 
    218         /// <summary>
    219         /// Passes YAML with a resource being something other than a map.
    220         /// </summary>
    221         [Fact]
    222         public void NonMapSequenceUnits()
    223         {
    224             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    225 
    226             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    227 properties:
    228   configurationVersion: 0.1
    229   resources:
    230     - string
    231 "));
    232             Assert.Null(result.Set);
    233             Assert.NotNull(result.ResultCode);
    234             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_TYPE, result.ResultCode.HResult);
    235             Assert.Equal("resources[0]", result.Field);
    236             Assert.Equal(5U, result.Line);
    237             Assert.NotEqual(0U, result.Column);
    238         }
    239 
    240         /// <summary>
    241         /// Passes YAML with all values present.
    242         /// </summary>
    243         [Fact]
    244         public void CheckAllUnitProperties()
    245         {
    246             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    247 
    248             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    249 properties:
    250   configurationVersion: 0.1
    251   resources:
    252     - resource: Resource
    253       id: Identifier
    254       dependsOn:
    255         - Dependency1
    256         - Dependency2
    257       directives:
    258         Directive1: A
    259         Directive2: B
    260       settings:
    261         Setting1: '1'
    262         Setting2: 2
    263 "));
    264             Assert.NotNull(result.Set);
    265             Assert.Null(result.ResultCode);
    266             Assert.Equal(string.Empty, result.Field);
    267 
    268             Assert.NotEqual(Guid.Empty, result.Set.InstanceIdentifier);
    269 
    270             var units = result.Set.Units;
    271             Assert.NotNull(units);
    272             Assert.Equal(1, units.Count);
    273 
    274             ConfigurationUnit unit = units[0];
    275             Assert.NotNull(unit);
    276             Assert.Equal("Resource", unit.Type);
    277             Assert.NotEqual(Guid.Empty, unit.InstanceIdentifier);
    278             Assert.Equal("Identifier", unit.Identifier);
    279             Assert.Equal(ConfigurationUnitIntent.Apply, unit.Intent);
    280 
    281             var dependencies = unit.Dependencies;
    282             Assert.NotNull(dependencies);
    283             Assert.Equal(2, dependencies.Count);
    284             Assert.Contains("Dependency1", dependencies);
    285             Assert.Contains("Dependency2", dependencies);
    286 
    287             var directives = unit.Metadata;
    288             Assert.NotNull(directives);
    289             Assert.Equal(2, directives.Count);
    290             Assert.Contains("Directive1", directives);
    291             Assert.Equal("A", directives["Directive1"]);
    292             Assert.Contains("Directive2", directives);
    293             Assert.Equal("B", directives["Directive2"]);
    294 
    295             var settings = unit.Settings;
    296             Assert.NotNull(settings);
    297             Assert.Equal(2, settings.Count);
    298             Assert.Contains("Setting1", settings);
    299             Assert.Equal("1", settings["Setting1"]);
    300             Assert.Contains("Setting2", settings);
    301             Assert.Equal(2L, settings["Setting2"]);
    302 
    303             Assert.Null(unit.Details);
    304             Assert.Equal(ConfigurationUnitState.Unknown, unit.State);
    305             Assert.Null(unit.ResultInformation);
    306             Assert.True(unit.IsActive);
    307         }
    308 
    309         /// <summary>
    310         /// Test type of scalar nodes.
    311         /// </summary>
    312         [Fact]
    313         public void CheckUnitScalarTypes()
    314         {
    315             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    316 
    317             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    318 properties:
    319   configurationVersion: 0.1
    320   resources:
    321     - resource: Resource
    322       id: Identifier
    323       settings:
    324         SettingInt: 1
    325         SettingString: '1' 
    326         SettingBool: false
    327         SettingStringBool: 'false'
    328 "));
    329             Assert.NotNull(result.Set);
    330             Assert.Null(result.ResultCode);
    331 
    332             var units = result.Set.Units;
    333             Assert.NotNull(units);
    334             Assert.Equal(1, units.Count);
    335 
    336             ConfigurationUnit unit = units[0];
    337             Assert.NotNull(unit);
    338 
    339             var settings = unit.Settings;
    340             Assert.NotNull(settings);
    341             Assert.Equal(4, settings.Count);
    342             Assert.Contains("SettingInt", settings);
    343             Assert.Equal(1L, settings["SettingInt"]);
    344             Assert.Contains("SettingString", settings);
    345             Assert.Equal("1", settings["SettingString"]);
    346             Assert.Contains("SettingBool", settings);
    347             Assert.Equal(false, settings["SettingBool"]);
    348             Assert.Contains("SettingStringBool", settings);
    349             Assert.Equal("false", settings["SettingStringBool"]);
    350         }
    351 
    352         /// <summary>
    353         /// Test that module gets left in resource name in 0.1.
    354         /// </summary>
    355         [Fact]
    356         public void ModuleInResourceName_NotFor0_1()
    357         {
    358             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    359 
    360             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    361 properties:
    362   configurationVersion: 0.1
    363   resources:
    364     - resource: Module/Resource
    365       id: Identifier
    366       settings:
    367         SettingInt: 1
    368 "));
    369 
    370             Assert.NotNull(result.Set);
    371             Assert.Null(result.ResultCode);
    372 
    373             Assert.Equal("0.1", result.Set.SchemaVersion);
    374             Assert.Single(result.Set.Units);
    375 
    376             var unit = result.Set.Units[0];
    377             Assert.NotNull(unit);
    378             Assert.Equal("Module/Resource", unit.Type);
    379             Assert.Empty(unit.Metadata);
    380         }
    381 
    382         /// <summary>
    383         /// Test that module gets parsed out of resource name in 0.2.
    384         /// </summary>
    385         [Fact]
    386         public void ModuleInResourceName()
    387         {
    388             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    389 
    390             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    391 properties:
    392   configurationVersion: 0.2
    393   resources:
    394     - resource: Module/Resource
    395       id: Identifier
    396       directives:
    397         module: Module
    398       settings:
    399         SettingInt: 1
    400 "));
    401 
    402             Assert.NotNull(result.Set);
    403             Assert.Null(result.ResultCode);
    404 
    405             Assert.Equal("0.2", result.Set.SchemaVersion);
    406             Assert.Single(result.Set.Units);
    407 
    408             var unit = result.Set.Units[0];
    409             Assert.NotNull(unit);
    410             Assert.Equal("Resource", unit.Type);
    411             Assert.Single(unit.Metadata);
    412             Assert.True(unit.Metadata.ContainsKey(ModuleDirective));
    413             Assert.Equal("Module", unit.Metadata[ModuleDirective]);
    414         }
    415 
    416         /// <summary>
    417         /// Test that module is in the resource name and the directives and are different.
    418         /// </summary>
    419         [Fact]
    420         public void ModuleInResourceName_DirectiveDifferent()
    421         {
    422             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    423 
    424             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    425 properties:
    426   configurationVersion: 0.2
    427   resources:
    428     - resource: Module/Resource
    429       id: Identifier
    430       directives:
    431         module: DifferentModule
    432       settings:
    433         SettingInt: 1
    434 "));
    435 
    436             Assert.Null(result.Set);
    437             Assert.NotNull(result.ResultCode);
    438             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult);
    439             Assert.Equal(ModuleDirective, result.Field);
    440             Assert.Equal("DifferentModule", result.Value);
    441             Assert.Equal(5U, result.Line);
    442             Assert.NotEqual(0U, result.Column);
    443         }
    444 
    445         /// <summary>
    446         /// Test that providing only the module in the qualified name is an error.
    447         /// </summary>
    448         [Fact]
    449         public void EmptyResourceWithModule()
    450         {
    451             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    452 
    453             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    454 properties:
    455   configurationVersion: 0.2
    456   resources:
    457     - resource: Module/
    458       id: Identifier
    459       settings:
    460         SettingInt: 1
    461 "));
    462 
    463             Assert.Null(result.Set);
    464             Assert.NotNull(result.ResultCode);
    465             Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult);
    466             Assert.Equal("resource", result.Field);
    467             Assert.Equal("Module/", result.Value);
    468             Assert.Equal(5U, result.Line);
    469             Assert.NotEqual(0U, result.Column);
    470         }
    471 
    472         /// <summary>
    473         /// Verifies that the configuration set (0.2) can be serialized and reopened correctly.
    474         /// </summary>
    475         [Fact]
    476         public void TestSet_Serialize_0_2()
    477         {
    478             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    479 
    480             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    481 properties:
    482   configurationVersion: 0.2
    483   assertions:
    484     - resource: FakeModule/FakeResource
    485       id: TestId
    486       directives:
    487         description: FakeDescription
    488         allowPrerelease: true
    489         securityContext: elevated
    490       settings:
    491         TestString: Hello
    492         TestBool: false
    493         TestInt: 1234  
    494   resources:
    495     - resource: FakeModule2/FakeResource2
    496       id: TestId2
    497       dependsOn:
    498         - TestId
    499         - dependency2
    500         - dependency3
    501       directives:
    502         description: FakeDescription2
    503         securityContext: elevated
    504       settings:
    505         TestString: Bye
    506         TestBool: true
    507         TestInt: 4321
    508         Mapping:
    509           Key: TestValue
    510 "));
    511 
    512             // Serialize set.
    513             ConfigurationSet configurationSet = openResult.Set;
    514             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
    515             configurationSet.Serialize(stream);
    516 
    517             string yamlOutput = this.ReadStream(stream);
    518 
    519             // Reopen configuration set from serialized string and verify values.
    520             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
    521             Assert.Null(serializedSetResult.ResultCode);
    522             ConfigurationSet set = serializedSetResult.Set;
    523             Assert.NotNull(set);
    524 
    525             Assert.Equal("0.2", set.SchemaVersion);
    526             Assert.Equal(2, set.Units.Count);
    527 
    528             Assert.Equal("FakeResource", set.Units[0].Type);
    529             Assert.Equal(ConfigurationUnitIntent.Assert, set.Units[0].Intent);
    530             Assert.Equal("TestId", set.Units[0].Identifier);
    531             this.VerifyValueSet(set.Units[0].Metadata, new ("description", "FakeDescription"), new ("allowPrerelease", true), new ("module", "FakeModule"));
    532             this.VerifyValueSet(set.Units[0].Settings, new ("TestString", "Hello"), new ("TestBool", false), new ("TestInt", 1234));
    533 
    534             Assert.Equal("FakeResource2", set.Units[1].Type);
    535             Assert.Equal(ConfigurationUnitIntent.Apply, set.Units[1].Intent);
    536             Assert.Equal("TestId2", set.Units[1].Identifier);
    537             this.VerifyStringArray(set.Units[1].Dependencies, "TestId", "dependency2", "dependency3");
    538             this.VerifyValueSet(set.Units[1].Metadata, new ("description", "FakeDescription2"), new ("module", "FakeModule2"));
    539 
    540             ValueSet mapping = new ValueSet();
    541             mapping.Add("Key", "TestValue");
    542             this.VerifyValueSet(set.Units[1].Settings, new ("TestString", "Bye"), new ("TestBool", true), new ("TestInt", 4321), new ("Mapping", mapping));
    543         }
    544 
    545         /// <summary>
    546         /// Verifies that the configuration set (0.3) can be serialized and reopened correctly.
    547         /// </summary>
    548         [Fact]
    549         public void TestSet_Serialize_0_3()
    550         {
    551             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    552 
    553             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    554 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
    555 metadata:
    556   description: FakeSetDescription
    557 variables:
    558   var1: Test1
    559   var2: 42
    560 parameters:
    561   param1:
    562     type: securestring
    563   param2:
    564     type: int
    565     defaultValue: 89
    566 resources:
    567   - type: FakeModule/FakeResource
    568     name: TestId
    569     metadata:
    570       description: FakeDescription
    571       allowPrerelease: true
    572       myVal: mine
    573     properties:
    574       TestString: Hello
    575       TestBool: false
    576       TestInt: 1234  
    577   - type: FakeModule2/FakeResource2
    578     name: TestId2
    579     dependsOn:
    580       - TestId
    581       - dependency2
    582       - dependency3
    583     metadata:
    584       description: FakeDescription2
    585       myVal: yours
    586     properties:
    587       TestString: Bye
    588       TestBool: true
    589       TestInt: 4321
    590       Mapping:
    591         Key: TestValue
    592   - type: FakeModule/FakeResource3
    593     name: TestId3
    594     metadata:
    595       isGroup: true
    596     properties:
    597       other: value
    598       resources:
    599         - type: Grouped/Resource
    600           name: Child
    601           properties:
    602             b: c
    603 "));
    604 
    605             // Serialize set.
    606             ConfigurationSet configurationSet = openResult.Set;
    607             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
    608             configurationSet.Serialize(stream);
    609 
    610             string yamlOutput = this.ReadStream(stream);
    611 
    612             // Reopen configuration set from serialized string and verify values.
    613             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
    614             Assert.Null(serializedSetResult.ResultCode);
    615             ConfigurationSet set = serializedSetResult.Set;
    616             Assert.NotNull(set);
    617 
    618             Assert.Equal("0.3", set.SchemaVersion);
    619             Assert.Equal(3, set.Units.Count);
    620 
    621             this.VerifyValueSet(set.Metadata, new KeyValuePair<string, object>("description", "FakeSetDescription"));
    622             this.VerifyValueSet(set.Variables, new ("var1", "Test1"), new ("var2", 42));
    623 
    624             Assert.Equal(2, set.Parameters.Count);
    625             this.VerifyParameter(set.Parameters[0], "param1", Windows.Foundation.PropertyType.String, true);
    626             this.VerifyParameter(set.Parameters[1], "param2", Windows.Foundation.PropertyType.Int64, false, 89);
    627 
    628             Assert.Equal("FakeModule/FakeResource", set.Units[0].Type);
    629             Assert.Equal("TestId", set.Units[0].Identifier);
    630             this.VerifyValueSet(set.Units[0].Metadata, new ("description", "FakeDescription"), new ("allowPrerelease", true), new ("myVal", "mine"));
    631             this.VerifyValueSet(set.Units[0].Settings, new ("TestString", "Hello"), new ("TestBool", false), new ("TestInt", 1234));
    632 
    633             Assert.Equal("FakeModule2/FakeResource2", set.Units[1].Type);
    634             Assert.Equal("TestId2", set.Units[1].Identifier);
    635             this.VerifyStringArray(set.Units[1].Dependencies, "TestId", "dependency2", "dependency3");
    636             this.VerifyValueSet(set.Units[1].Metadata, new ("description", "FakeDescription2"), new ("myVal", "yours"));
    637 
    638             ValueSet mapping = new ValueSet();
    639             mapping.Add("Key", "TestValue");
    640             this.VerifyValueSet(set.Units[1].Settings, new ("TestString", "Bye"), new ("TestBool", true), new ("TestInt", 4321), new ("Mapping", mapping));
    641 
    642             Assert.Equal("FakeModule/FakeResource3", set.Units[2].Type);
    643             Assert.Equal("TestId3", set.Units[2].Identifier);
    644             Assert.True(set.Units[2].IsGroup);
    645 
    646             ValueSet childResource = new ValueSet();
    647             childResource.Add("type", "Grouped/Resource");
    648             childResource.Add("name", "Child");
    649             ValueSet childResourceProperties = new ValueSet();
    650             childResourceProperties.Add("b", "c");
    651             childResource.Add("properties", childResourceProperties);
    652 
    653             ValueSet resourcesArray = new ValueSet();
    654             resourcesArray.Add("treatAsArray", true);
    655             resourcesArray.Add("0", childResource);
    656 
    657             this.VerifyValueSet(set.Units[2].Settings, new ("other", "value"), new ("resources", resourcesArray));
    658 
    659             var groupChildren = set.Units[2].Units;
    660             Assert.Single(groupChildren);
    661 
    662             Assert.Equal("Grouped/Resource", groupChildren[0].Type);
    663             Assert.Equal("Child", groupChildren[0].Identifier);
    664             this.VerifyValueSet(groupChildren[0].Settings, new KeyValuePair<string, object>("b", "c"));
    665         }
    666 
    667         /// <summary>
    668         /// Test for using version 0.3 schema.
    669         /// </summary>
    670         [Fact]
    671         public void BasicVersion_0_3()
    672         {
    673             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    674 
    675             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@"
    676 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
    677 metadata:
    678   a: 1
    679   b: '2'
    680 variables:
    681   v1: var1
    682   v2: 42
    683 resources:
    684   - name: Name
    685     type: Module/Resource
    686     metadata:
    687       e: '5'
    688       f: 6
    689     properties:
    690       c: 3
    691       d: '4'
    692     dependsOn:
    693       - g
    694       - h
    695   - name: Name2
    696     type: Module/Resource2
    697     dependsOn:
    698       - m
    699     properties:
    700       l: '10'
    701     metadata:
    702       i: '7'
    703       j: 8
    704       q: 42
    705 "));
    706 
    707             Assert.Null(result.ResultCode);
    708             Assert.NotNull(result.Set);
    709             Assert.Equal(string.Empty, result.Field);
    710             Assert.Equal(string.Empty, result.Value);
    711             Assert.Equal(0U, result.Line);
    712             Assert.Equal(0U, result.Column);
    713 
    714             ConfigurationSet set = result.Set;
    715 
    716             Assert.Equal("0.3", set.SchemaVersion);
    717             Assert.NotNull(set.SchemaUri);
    718             Assert.Equal("https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json", set.SchemaUri.ToString());
    719 
    720             this.VerifyValueSet(set.Metadata, new ("a", 1), new ("b", "2"));
    721             this.VerifyValueSet(set.Variables, new ("v1", "var1"), new ("v2", 42));
    722 
    723             Assert.Empty(set.Parameters);
    724 
    725             Assert.Equal(2, set.Units.Count);
    726 
    727             this.VerifyUnitProperties(set.Units[0], "Name", "Module/Resource");
    728             this.VerifyValueSet(set.Units[0].Metadata, new ("e", "5"), new ("f", 6));
    729             this.VerifyValueSet(set.Units[0].Settings, new ("c", 3), new ("d", "4"));
    730             this.VerifyStringArray(set.Units[0].Dependencies, "g", "h");
    731 
    732             this.VerifyUnitProperties(set.Units[1], "Name2", "Module/Resource2");
    733             this.VerifyValueSet(set.Units[1].Metadata, new ("i", "7"), new ("j", 8), new ("q", 42));
    734             this.VerifyValueSet(set.Units[1].Settings, new KeyValuePair<string, object>("l", "10"));
    735             this.VerifyStringArray(set.Units[1].Dependencies, "m");
    736         }
    737 
    738         /// <summary>
    739         /// Test for the successful parsing of default value of a parameter.
    740         /// </summary>
    741         /// <param name="type">The type.</param>
    742         /// <param name="defaultValue">The default value.</param>
    743         /// <param name="expectedValue">The expected value.</param>
    744         /// <param name="expectedType">The expected type.</param>
    745         /// <param name="secure">The secure state.</param>
    746         [Theory]
    747         [InlineData("string", "abc", "abc", Windows.Foundation.PropertyType.String)]
    748         [InlineData("string", "'42'", "42", Windows.Foundation.PropertyType.String)]
    749         [InlineData("securestring", "abcdef", "abcdef", Windows.Foundation.PropertyType.String, true)]
    750         [InlineData("int", "42", 42, Windows.Foundation.PropertyType.Int64)]
    751         [InlineData("bool", "true", true, Windows.Foundation.PropertyType.Boolean)]
    752         [InlineData("object", "string", "string", Windows.Foundation.PropertyType.Inspectable)]
    753         [InlineData("object", "42", 42, Windows.Foundation.PropertyType.Inspectable)]
    754         [InlineData("secureobject", "string", "string", Windows.Foundation.PropertyType.Inspectable, true)]
    755         [InlineData("secureobject", "42", 42, Windows.Foundation.PropertyType.Inspectable, true)]
    756         public void Parameters_DefaultValue_Success(string type, string defaultValue, object expectedValue, object expectedType, bool secure = false)
    757         {
    758             this.TestParameterDefaultValue(type, defaultValue, expectedValue, Assert.IsType<Windows.Foundation.PropertyType>(expectedType), secure);
    759         }
    760 
    761         /// <summary>
    762         /// Test for the failed parsing of default value of a parameter.
    763         /// </summary>
    764         /// <param name="type">The type.</param>
    765         /// <param name="defaultValue">The default value.</param>
    766         /// <param name="expectedValue">The expected value.</param>
    767         [Theory]
    768         [InlineData("string", "42")]
    769         [InlineData("int", "abc")]
    770         [InlineData("int", "'42'", "42")]
    771         [InlineData("bool", "'true'", "true")]
    772         public void Parameters_DefaultValue_Failure(string type, string defaultValue, object? expectedValue = null)
    773         {
    774             this.TestParameterDefaultValue(type, defaultValue, expectedValue);
    775         }
    776 
    777         /// <summary>
    778         /// Test to ensure that schema version and uri is working as expected.
    779         /// </summary>
    780         /// <param name="version">The version.</param>
    781         /// <param name="uri">The uri.</param>
    782         [Theory]
    783         [InlineData("0.1", null)]
    784         [InlineData("0.2", null)]
    785         [InlineData("0.3", "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json")]
    786         public void Schema_Version_Uri(string version, string? uri)
    787         {
    788             ConfigurationSet set = this.ConfigurationSet();
    789 
    790             set.SchemaVersion = version;
    791             if (uri != null)
    792             {
    793                 Assert.Equal(uri, set.SchemaUri.AbsoluteUri);
    794             }
    795             else
    796             {
    797                 Assert.Null(set.SchemaUri);
    798             }
    799 
    800             if (!string.IsNullOrEmpty(uri))
    801             {
    802                 set.SchemaUri = new Uri(uri);
    803                 Assert.Equal(version, set.SchemaVersion);
    804             }
    805         }
    806 
    807         /// <summary>
    808         /// Verifies that the configuration set (0.2) with environments parses and serializes.
    809         /// </summary>
    810         [Fact]
    811         public void Environment_0_2()
    812         {
    813             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    814 
    815             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    816 properties:
    817   configurationVersion: 0.2
    818   resources:
    819     - resource: FakeModule/FakeResource
    820       id: elevated
    821       directives:
    822         description: FakeDescription
    823         allowPrerelease: true
    824         securityContext: elevated
    825       settings:
    826         TestString: Hello
    827     - resource: FakeModule2/FakeResource2
    828       id: restricted
    829       directives:
    830         description: FakeDescription2
    831         securityContext: restricted
    832       settings:
    833         TestString: Bye
    834     - resource: FakeModule2/FakeResource2
    835       id: current
    836       directives:
    837         securityContext: current
    838       settings:
    839         TestString: Bye
    840     - resource: FakeModule2/FakeResource2
    841       id: default
    842       settings:
    843         TestString: Bye
    844 "));
    845 
    846             Dictionary<string, SecurityContext> expectedEnvironments = new Dictionary<string, SecurityContext>();
    847             expectedEnvironments.Add("elevated", SecurityContext.Elevated);
    848             expectedEnvironments.Add("restricted", SecurityContext.Restricted);
    849             expectedEnvironments.Add("current", SecurityContext.Current);
    850             expectedEnvironments.Add("default", SecurityContext.Current);
    851 
    852             this.ValidateSecurityContexts(openResult, expectedEnvironments);
    853 
    854             // Shuffle security contexts, serialize, parse and validate again
    855             expectedEnvironments["elevated"] = SecurityContext.Restricted;
    856             expectedEnvironments["restricted"] = SecurityContext.Current;
    857             expectedEnvironments["current"] = SecurityContext.Restricted;
    858             expectedEnvironments["default"] = SecurityContext.Elevated;
    859 
    860             var units = openResult.Set.Units;
    861             foreach (var unit in units)
    862             {
    863                 SecurityContext newContext = SecurityContext.Current;
    864                 Assert.True(expectedEnvironments.TryGetValue(unit.Identifier, out newContext));
    865                 unit.Environment.Context = newContext;
    866             }
    867 
    868             // Serialize set.
    869             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
    870             openResult.Set.Serialize(stream);
    871 
    872             string yamlOutput = this.ReadStream(stream);
    873 
    874             // Reopen configuration set from serialized string and verify values.
    875             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
    876 
    877             this.ValidateSecurityContexts(serializedSetResult, expectedEnvironments);
    878         }
    879 
    880         /// <summary>
    881         /// Verifies that the configuration set (0.3) inherits set environment.
    882         /// </summary>
    883         [Fact]
    884         public void SetMetadataEnvironmentInheritance_0_3()
    885         {
    886             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    887 
    888             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    889 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
    890 metadata:
    891   winget:
    892     securityContext: elevated
    893     processor:
    894       identifier: pwsh
    895       properties:
    896         a: b
    897 resources:
    898   - name: first
    899     type: Module/Resource
    900     properties:
    901       c: 3
    902   - name: second
    903     type: Module/Resource2
    904     properties:
    905       l: '10'
    906 "));
    907 
    908             Dictionary<string, string> environmentProperties = new Dictionary<string, string>();
    909             environmentProperties.Add("a", "b");
    910             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties };
    911 
    912             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
    913             expectedEnvironments.Add("first", new ConfigurationEnvironmentData());
    914             expectedEnvironments.Add("second", new ConfigurationEnvironmentData());
    915 
    916             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments);
    917 
    918             // Serialize set.
    919             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
    920             openResult.Set.Serialize(stream);
    921 
    922             string yamlOutput = this.ReadStream(stream);
    923 
    924             // Reopen configuration set from serialized string and verify values.
    925             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
    926 
    927             this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments);
    928         }
    929 
    930         /// <summary>
    931         /// Verifies that the configuration set (0.3) inherits set environment.
    932         /// </summary>
    933         [Fact]
    934         public void SetMetadataEnvironmentInheritance_ProcessorOverridden_0_3()
    935         {
    936             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    937 
    938             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    939 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
    940 metadata:
    941   winget:
    942     securityContext: elevated
    943     processor:
    944       identifier: pwsh
    945       properties:
    946         a: b
    947 resources:
    948   - name: first
    949     type: Module/Resource
    950     properties:
    951       c: 3
    952   - name: second
    953     type: Module/Resource2
    954     properties:
    955       l: '10'
    956     metadata:
    957       winget:
    958         processor: not-pwsh
    959 "));
    960 
    961             Dictionary<string, string> environmentProperties = new Dictionary<string, string>();
    962             environmentProperties.Add("a", "b");
    963             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties };
    964 
    965             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
    966             expectedEnvironments.Add("first", new ConfigurationEnvironmentData());
    967             expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { ProcessorIdentifier = "not-pwsh" });
    968 
    969             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments);
    970 
    971             // Serialize set.
    972             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
    973             openResult.Set.Serialize(stream);
    974 
    975             string yamlOutput = this.ReadStream(stream);
    976 
    977             // Reopen configuration set from serialized string and verify values.
    978             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
    979 
    980             this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments);
    981         }
    982 
    983         /// <summary>
    984         /// Verifies that the configuration set (0.3) inherits set environment.
    985         /// </summary>
    986         [Fact]
    987         public void SetMetadataEnvironmentInheritance_ContextOverridden_0_3()
    988         {
    989             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
    990 
    991             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
    992 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
    993 metadata:
    994   winget:
    995     securityContext: elevated
    996     processor:
    997       identifier: pwsh
    998       properties:
    999         a: b
   1000 resources:
   1001   - name: first
   1002     type: Module/Resource
   1003     properties:
   1004       c: 3
   1005   - name: second
   1006     type: Module/Resource2
   1007     properties:
   1008       l: '10'
   1009     metadata:
   1010       winget:
   1011         securityContext: restricted
   1012 "));
   1013 
   1014             Dictionary<string, string> environmentProperties = new Dictionary<string, string>();
   1015             environmentProperties.Add("a", "b");
   1016             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties };
   1017 
   1018             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
   1019             expectedEnvironments.Add("first", new ConfigurationEnvironmentData());
   1020             expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted });
   1021 
   1022             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments);
   1023 
   1024             // Serialize set.
   1025             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
   1026             openResult.Set.Serialize(stream);
   1027 
   1028             string yamlOutput = this.ReadStream(stream);
   1029 
   1030             // Reopen configuration set from serialized string and verify values.
   1031             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
   1032 
   1033             this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments);
   1034         }
   1035 
   1036         /// <summary>
   1037         /// Verifies that the configuration set (0.3) serializes common environment to the set metadata.
   1038         /// </summary>
   1039         [Fact]
   1040         public void CommonEnvironmentElevatedToSetMetadata_0_3()
   1041         {
   1042             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
   1043 
   1044             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
   1045 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
   1046 resources:
   1047   - name: first
   1048     type: Module/Resource
   1049     metadata:
   1050       winget:
   1051         securityContext: elevated
   1052         processor: pwsh
   1053     properties:
   1054       c: 3
   1055   - name: second
   1056     type: Module/Resource2
   1057     properties:
   1058       l: '10'
   1059     metadata:
   1060       winget:
   1061         securityContext: elevated
   1062         processor:
   1063           identifier: pwsh
   1064 "));
   1065 
   1066             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData();
   1067 
   1068             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
   1069             expectedEnvironments.Add("first", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" });
   1070             expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" });
   1071 
   1072             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments);
   1073 
   1074             // Serialize set.
   1075             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
   1076             openResult.Set.Serialize(stream);
   1077 
   1078             string yamlOutput = this.ReadStream(stream);
   1079 
   1080             // Reopen configuration set from serialized string and verify values.
   1081             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
   1082 
   1083             this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments);
   1084         }
   1085 
   1086         /// <summary>
   1087         /// Verifies that the configuration set (0.3) serializes common environment to the set metadata.
   1088         /// </summary>
   1089         [Fact]
   1090         public void CommonProcessorElevatedToSetMetadata_0_3()
   1091         {
   1092             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
   1093 
   1094             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
   1095 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
   1096 resources:
   1097   - name: first
   1098     type: Module/Resource
   1099     metadata:
   1100       winget:
   1101         securityContext: elevated
   1102         processor: pwsh
   1103     properties:
   1104       c: 3
   1105   - name: second
   1106     type: Module/Resource2
   1107     properties:
   1108       l: '10'
   1109     metadata:
   1110       winget:
   1111         securityContext: restricted
   1112         processor:
   1113           identifier: pwsh
   1114 "));
   1115 
   1116             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData();
   1117 
   1118             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
   1119             expectedEnvironments.Add("first", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" });
   1120             expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted, ProcessorIdentifier = "pwsh" });
   1121 
   1122             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments);
   1123 
   1124             // Serialize set.
   1125             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
   1126             openResult.Set.Serialize(stream);
   1127 
   1128             string yamlOutput = this.ReadStream(stream);
   1129 
   1130             // Reopen configuration set from serialized string and verify values.
   1131             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
   1132 
   1133             this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments);
   1134         }
   1135 
   1136         /// <summary>
   1137         /// Verifies that the configuration set (0.3) environments work with group units.
   1138         /// </summary>
   1139         [Fact]
   1140         public void EnvironmentsWithGroups_0_3()
   1141         {
   1142             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
   1143 
   1144             OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@"
   1145 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
   1146 metadata:
   1147   winget:
   1148     securityContext: elevated
   1149     processor:
   1150       identifier: pwsh
   1151       properties:
   1152         a: b
   1153 resources:
   1154   - name: non-group
   1155     type: Module/Resource2
   1156     properties:
   1157       l: '10'
   1158   - name: group
   1159     type: Module/Resource
   1160     metadata:
   1161       isGroup: true
   1162       winget:
   1163         securityContext: restricted
   1164     properties:
   1165       resources:
   1166         - name: inherit
   1167           type: Module/Resource
   1168           properties:
   1169             a: b
   1170         - name: override
   1171           type: Module/Resource
   1172           properties:
   1173             c: d
   1174           metadata:
   1175             winget:
   1176               processor: not-pwsh
   1177 "));
   1178 
   1179             Dictionary<string, string> environmentProperties = new Dictionary<string, string>();
   1180             environmentProperties.Add("a", "b");
   1181             ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties };
   1182 
   1183             Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
   1184             expectedEnvironments.Add("non-group", new ConfigurationEnvironmentData());
   1185             expectedEnvironments.Add("group", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted });
   1186 
   1187             Dictionary<string, ConfigurationEnvironmentData> groupExpectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>();
   1188             groupExpectedEnvironments.Add("inherit", new ConfigurationEnvironmentData());
   1189             groupExpectedEnvironments.Add("override", new ConfigurationEnvironmentData() { ProcessorIdentifier = "not-pwsh" });
   1190 
   1191             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments, "group", groupExpectedEnvironments);
   1192 
   1193             // Serialize set.
   1194             InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
   1195             openResult.Set.Serialize(stream);
   1196 
   1197             string yamlOutput = this.ReadStream(stream);
   1198 
   1199             // Reopen configuration set from serialized string and verify values.
   1200             OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput));
   1201 
   1202             this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments, "group", groupExpectedEnvironments);
   1203         }
   1204 
   1205         private void ValidateEnvironments(OpenConfigurationSetResult openResult, ConfigurationEnvironmentData setEnvironment, Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments, string? groupToCheck = null, Dictionary<string, ConfigurationEnvironmentData>? groupExpectedEnvironments = null)
   1206         {
   1207             Assert.Null(openResult.ResultCode);
   1208             Assert.NotNull(openResult.Set);
   1209             ConfigurationSet configurationSet = openResult.Set;
   1210 
   1211             this.ValidateEnvironment(setEnvironment, configurationSet.Environment);
   1212 
   1213             var units = configurationSet.Units;
   1214             this.ValidateEnvironments(units, expectedEnvironments, groupToCheck, groupExpectedEnvironments);
   1215         }
   1216 
   1217         private void ValidateEnvironments(IList<ConfigurationUnit> units, Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments, string? groupToCheck = null, Dictionary<string, ConfigurationEnvironmentData>? groupExpectedEnvironments = null)
   1218         {
   1219             Assert.Equal(expectedEnvironments.Count, units.Count);
   1220             foreach (var unit in units)
   1221             {
   1222                 ConfigurationEnvironmentData? expectedEnvironment = null;
   1223                 Assert.True(expectedEnvironments.TryGetValue(unit.Identifier, out expectedEnvironment));
   1224                 this.ValidateEnvironment(expectedEnvironment, unit.Environment);
   1225 
   1226                 if (unit.Identifier == groupToCheck)
   1227                 {
   1228                     Assert.True(unit.IsGroup);
   1229                     Assert.NotNull(groupExpectedEnvironments);
   1230                     var groupUnits = unit.Units;
   1231                     this.ValidateEnvironments(groupUnits, groupExpectedEnvironments);
   1232                 }
   1233             }
   1234         }
   1235 
   1236         private void ValidateEnvironment(ConfigurationEnvironmentData? expectedEnvironment, ConfigurationEnvironment? actualEnvironment)
   1237         {
   1238             Assert.NotNull(expectedEnvironment);
   1239             Assert.NotNull(actualEnvironment);
   1240             Assert.Equal(expectedEnvironment.Context, actualEnvironment.Context);
   1241             Assert.Equal(expectedEnvironment.ProcessorIdentifier, actualEnvironment.ProcessorIdentifier);
   1242             Assert.True(expectedEnvironment.PropertiesEqual(actualEnvironment.ProcessorProperties));
   1243         }
   1244 
   1245         private void ValidateSecurityContexts(OpenConfigurationSetResult openResult, Dictionary<string, SecurityContext> expectedContexts)
   1246         {
   1247             Assert.Null(openResult.ResultCode);
   1248             Assert.NotNull(openResult.Set);
   1249             ConfigurationSet configurationSet = openResult.Set;
   1250 
   1251             var units = configurationSet.Units;
   1252             Assert.Equal(expectedContexts.Count, units.Count);
   1253             foreach (var unit in units)
   1254             {
   1255                 SecurityContext expectedContext = SecurityContext.Current;
   1256                 Assert.True(expectedContexts.TryGetValue(unit.Identifier, out expectedContext));
   1257                 Assert.Equal(expectedContext, unit.Environment.Context);
   1258             }
   1259         }
   1260 
   1261         private void TestParameterDefaultValue(string type, string defaultValue, object? expectedValue = null, Windows.Foundation.PropertyType? expectedType = null, bool secure = false)
   1262         {
   1263             ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics();
   1264 
   1265             OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(string.Format(
   1266                 @"
   1267 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
   1268 parameters:
   1269   {0}:
   1270     type: {0}
   1271     defaultValue: {1}
   1272 ",
   1273                 type,
   1274                 defaultValue)));
   1275 
   1276             if (expectedType != null)
   1277             {
   1278                 Assert.Null(result.ResultCode);
   1279                 Assert.NotNull(result.Set);
   1280                 Assert.Equal(string.Empty, result.Field);
   1281                 Assert.Equal(string.Empty, result.Value);
   1282                 Assert.Equal(0U, result.Line);
   1283                 Assert.Equal(0U, result.Column);
   1284 
   1285                 var parameters = result.Set.Parameters;
   1286                 Assert.NotNull(parameters);
   1287                 Assert.Single(parameters);
   1288 
   1289                 Assert.Equal(type, parameters[0].Name);
   1290                 Assert.Equal(expectedType, parameters[0].Type);
   1291                 Assert.Equal(secure, parameters[0].IsSecure);
   1292 
   1293                 Assert.NotNull(expectedValue);
   1294                 this.VerifyObject(type, expectedValue, parameters[0].DefaultValue);
   1295             }
   1296             else
   1297             {
   1298                 Assert.NotNull(result.ResultCode);
   1299                 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult);
   1300                 Assert.Null(result.Set);
   1301                 Assert.Equal("defaultValue", result.Field);
   1302                 Assert.Equal(expectedValue?.ToString() ?? defaultValue, result.Value);
   1303                 Assert.NotEqual(0U, result.Line);
   1304                 Assert.NotEqual(0U, result.Column);
   1305             }
   1306         }
   1307 
   1308         private void VerifyUnitProperties(ConfigurationUnit unit, string identifier, string type)
   1309         {
   1310             Assert.NotNull(unit);
   1311             Assert.Equal(identifier, unit.Identifier);
   1312             Assert.Equal(type, unit.Type);
   1313         }
   1314 
   1315         private void VerifyValueSet(ValueSet values, params KeyValuePair<string, object>[] expected)
   1316         {
   1317             Assert.NotNull(values);
   1318             Assert.Equal(expected.Length, values.Count);
   1319 
   1320             foreach (var expectation in expected)
   1321             {
   1322                 Assert.True(values.ContainsKey(expectation.Key), $"Not Found {expectation.Key}");
   1323                 object value = values[expectation.Key];
   1324 
   1325                 this.VerifyObject(expectation.Key, expectation.Value, value);
   1326             }
   1327         }
   1328 
   1329         private void VerifyStringArray(IList<string> strings, params string[] expected)
   1330         {
   1331             Assert.NotNull(strings);
   1332             Assert.Equal(expected.Length, strings.Count);
   1333 
   1334             foreach (var expectation in expected)
   1335             {
   1336                 bool found = false;
   1337                 foreach (var value in strings)
   1338                 {
   1339                     if (!found)
   1340                     {
   1341                         found = expectation == value;
   1342                     }
   1343                 }
   1344 
   1345                 Assert.True(found, $"Did not find {expectation} in string array");
   1346             }
   1347         }
   1348 
   1349         private void VerifyParameter(ConfigurationParameter parameter, string name, Windows.Foundation.PropertyType type, bool secure, object? defaultValue = null)
   1350         {
   1351             Assert.Equal(name, parameter.Name);
   1352             Assert.Equal(type, parameter.Type);
   1353             Assert.Equal(secure, parameter.IsSecure);
   1354             this.VerifyObject(name, defaultValue, parameter.DefaultValue);
   1355         }
   1356 
   1357         private void VerifyObject(string name, object? expectedValue, object? actualValue)
   1358         {
   1359             if (expectedValue != null)
   1360             {
   1361                 Assert.NotNull(actualValue);
   1362 
   1363                 switch (expectedValue)
   1364                 {
   1365                     case int i:
   1366                         Assert.True(i == (int)(long)actualValue, $"{name}: expected[{i}], actual[{(int)(long)actualValue}]");
   1367                         break;
   1368                     case string s:
   1369                         Assert.True(s == (string)actualValue, $"{name}: expected[{s}], actual[{(string)actualValue}]");
   1370                         break;
   1371                     case bool b:
   1372                         Assert.True(b == (bool)actualValue, $"{name}: expected[{b}], actual[{(bool)actualValue}]");
   1373                         break;
   1374                     case ValueSet v:
   1375                         var actualValueSet = actualValue.As<ValueSet>();
   1376                         Assert.True(v.ContentEquals(actualValueSet), $"ValueSets not equal: {name}\n---expected---:\n{v.ToYaml()}\n---actual---:\n{actualValueSet.ToYaml()}");
   1377                         break;
   1378                     default:
   1379                         Assert.Fail($"Add expected type `{expectedValue.GetType().Name}` to switch statement for {name}.");
   1380                         break;
   1381                 }
   1382             }
   1383         }
   1384     }
   1385 }