Tests/xDscResourceDesigner.Tests.ps1

#requires -RunAsAdministrator
# Test-xDscResource requires administrator privileges, so we may as well enforce that here.

end
{
    Get-Module xDscResourceDesigner -All | Remove-Module -Force
    $script:modulePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'xDscResourceDesigner.psd1'
    Import-Module -Name $script:modulePath -ErrorAction Stop

    Describe 'xDscResourceDesigner' {
        It 'Should not error if imported twice' {
            Get-Module xDscResourceDesigner -All | Remove-Module -Force
            { Import-Module $script:modulePath -ErrorAction Stop } | Should Not Throw
        }
    }

    Describe Test-xDscResource {
        Context 'A module with a psm1 file but no matching schema.mof' {
            Setup -Dir TestResource
            Setup -File TestResource\TestResource.psm1 -Content (Get-TestDscResourceModuleContent)

            It 'Should fail the test' {
                $null = $($result = Test-xDscResource -Name $TestDrive\TestResource) 2>&1
                $result | Should Be $false
            }
        }

        Context 'A module with a schema.mof file but no psm1 file' {
            Setup -Dir TestResource
            Setup -File TestResource\TestResource.schema.mof -Content (Get-TestDscResourceSchemaContent)

            It 'Should fail the test' {
                $null = $($result = Test-xDscResource -Name $TestDrive\TestResource) 2>&1
                $result | Should Be $false
            }
        }

        Context 'A resource with both required files, valid contents' {
            Setup -Dir TestResource
            Setup -File TestResource\TestResource.schema.mof -Content (Get-TestDscResourceSchemaContent)
            Setup -File TestResource\TestResource.psm1 -Content (Get-TestDscResourceModuleContent)

            It 'Should pass the test' {
                $result = Test-xDscResource -Name $TestDrive\TestResource
                $result | Should Be $true
            }
        }

        Context 'A resource with both required files, but schema mof has encoding UTF8 BOM' {
            BeforeAll {
                Mock -CommandName 'Write-Error' -ModuleName 'xDscResourceDesigner'
            }

            Setup -Dir TestResource
            Setup -File TestResource\TestResource.psm1 -Content (Get-TestDscResourceModuleContent)
            Get-TestDscResourceSchemaContent |
                Out-File -Encoding utf8 -FilePath (Join-Path -Path $TestDrive -ChildPath 'TestResource\TestResource.schema.mof') -Force

            It 'Should write out the correct error to console, and return $false' {
                $result = Test-xDscResource -Name $TestDrive\TestResource
                $result | Should Be $false

                Assert-MockCalled -CommandName 'Write-Error' -ParameterFilter {
                    $message -eq 'The encoding for the schema file is not supported. Please use Unicode or ASCII (Unicode is not well supported in GIT.)'
                } -Exactly -Times 1 -ModuleName 'xDscResourceDesigner'
            }
        }
    }

    Describe New-xDscResourceProperty {
        $hash = @{ Result = $null }

        It 'Allows the use of the ValidateSet parameter' {
            $scriptBlock = {
                $hash.Result = New-xDscResourceProperty  -Name Ensure  -Type String  -Attribute Required  -ValidateSet 'Present','Absent'
            }

            $scriptBlock | Should Not Throw

            $hash.Result.Values.Count | Should Be 2
            $hash.Result.Values[0]    | Should Be 'Present'
            $hash.Result.Values[1]    | Should Be 'Absent'

            $hash.Result.ValueMap.Count | Should Be 2
            $hash.Result.ValueMap[0]    | Should Be 'Present'
            $hash.Result.ValueMap[1]    | Should Be 'Absent'
        }

        It 'Allows the use of the ValueMap and Values parameters' {
            $scriptBlock = {
                $hash.Result = New-xDscResourceProperty  -Name Ensure  -Type String  -Attribute Required  -Values 'Present','Absent' -ValueMap 'Present','Absent'
            }

            $scriptBlock | Should Not Throw

            $hash.Result.Values.Count | Should Be 2
            $hash.Result.Values[0]    | Should Be 'Present'
            $hash.Result.Values[1]    | Should Be 'Absent'

            $hash.Result.ValueMap.Count | Should Be 2
            $hash.Result.ValueMap[0]    | Should Be 'Present'
            $hash.Result.ValueMap[1]    | Should Be 'Absent'
        }

        It 'Does not allow ValidateSet and Values / ValueMap to be used together' {
            $scriptBlock = {
                New-xDscResourceProperty  -Name Ensure `
                                          -Type String `
                                          -Attribute Required `
                                          -Values 'Present','Absent' `
                                          -ValueMap 'Present','Absent' `
                                          -ValidateSet 'Present', 'Absent'
            }

            $scriptBlock | Should Throw 'Parameter set cannot be resolved'
        }
    }

    InModuleScope xDscResourceDesigner {
        function Get-xDSCSchemaFriendlyName
        {
            Param(
                $Path
            )
            $cimClass = 0
            Try
            {
                [System.Void](Test-xDscSchemaInternal -Schema $Path -SchemaCimClass ([ref]$cimClass) -ErrorAction Stop 2>&1)
                if($cimClass -ne 0)
                {
                    $FriendlyName = $cimClass.CimClassQualifiers.Where{$_.Name -eq 'FriendlyName'}.Value
                }
            }
            Catch
            {
                Throw
            }
            return $FriendlyName
        }
        Describe 'Creating and updating resources' {
            Context 'Creating and updating a DSC Resource' {
                Setup -Dir TestResource
                #region Create New Resource
                $ResourceProperties = $(
                    New-xDscResourceProperty -Name KeyProperty -Type String -Attribute Key
                    New-xDscResourceProperty -Name RequiredProperty -Type String -Attribute Required
                    New-xDscResourceProperty -Name WriteProperty -Type String -Attribute Write
                    New-xDscResourceProperty -Name ReadProperty -Type String -Attribute Read
                )
                New-xDscResource -Name TestResource -FriendlyName cTestResource -Path $TestDrive -Property $ResourceProperties -Force
                $OriginalFriendlyName = Get-xDSCSchemaFriendlyName -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof"
                $NewSchemaContent = Get-Content -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof" -Raw
                $NewModuleContent = Get-Content -Path "$TestDrive\DSCResources\TestResource\TestResource.psm1" -Raw

                It 'Creates a valid module script and schema' {
                    Test-xDscResource -Name "$TestDrive\DSCResources\TestResource" | Should Be $true
                }

                #endregion

                #region Update Resource using exact same config (should result in unchanged resource)
                Update-xDscResource -Path "$TestDrive\DSCResources\TestResource" -Property $ResourceProperties -Force
                $UpdatedFriendlyName = Get-xDSCSchemaFriendlyName -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof"
                $UpdatedSchemaContent = Get-Content -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof" -Raw
                $UpdatedModuleContent = Get-Content -Path "$TestDrive\DSCResources\TestResource\TestResource.psm1" -Raw

                It 'Updated Module Script and Schema should be equal to original' {
                    $NewSchemaContent -eq $UpdatedSchemaContent | Should Be $true
                    $NewModuleContent -eq $UpdatedModuleContent | Should Be $true
                }

                #endregion

                #region Update Resurce again using same config but specify new FriendlyName
                Update-xDscResource -Path "$TestDrive\DSCResources\TestResource" -Property $ResourceProperties -FriendlyName TestResource -Force
                $ChangedFriendlyName = Get-xDSCSchemaFriendlyName -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof"

                It 'Changes friendly name in Schema when using -FriendlyName with Update-xDscResource' {
                    $OriginalFriendlyName -ne $ChangedFriendlyName | Should Be $true
                    $ChangedFriendlyName -eq 'TestResource' | Should Be $true
                }

                #endregion

                #region Change FrientlyName back to original value and validate that schema is identical to original schema
                Update-xDscResource -Path "$TestDrive\DSCResources\TestResource" -Property $ResourceProperties -FriendlyName cTestResource -Force
                $RestoredSchemaContent = Get-Content -Path "$TestDrive\DSCResources\TestResource\TestResource.schema.mof" -Raw

                It 'Changes ONLY friendly name in Schema when using -FriendlyName with Update-xDscResource' {
                    $NewSchemaContent -eq $RestoredSchemaContent | Should Be $true
                }

                #endregion



            }
        }
    }
}

begin
{
    function Get-TestDscResourceModuleContent
    {
        $content = @'
            function Get-TargetResource
            {
                [OutputType([hashtable])]
                [CmdletBinding()]
                param (
                    [Parameter(Mandatory)]
                    [string] $KeyProperty,
 
                    [Parameter(Mandatory)]
                    [string] $RequiredProperty
                )
 
                return @{
                    KeyProperty = $KeyProperty
                    RequiredProperty = 'Required Property'
                    WriteProperty = 'Write Property'
                    ReadProperty = 'Read Property'
                }
            }
 
            function Set-TargetResource
            {
                [CmdletBinding()]
                param (
                    [Parameter(Mandatory)]
                    [string] $KeyProperty,
 
                    [Parameter(Mandatory)]
                    [string] $RequiredProperty,
 
                    [string] $WriteProperty,
 
                    [Parameter()]
                    [Microsoft.Management.Infrastructure.CimInstance]
                    $SubClass
                )
            }
 
            function Test-TargetResource
            {
                [OutputType([bool])]
                [CmdletBinding()]
                param (
                    [Parameter(Mandatory)]
                    [string] $KeyProperty,
 
                    [Parameter(Mandatory)]
                    [string] $RequiredProperty,
 
                    [string] $WriteProperty,
 
                    [Parameter()]
                    [Microsoft.Management.Infrastructure.CimInstance]
                    $SubClass
                )
 
                return $false
            }
'@


        return $content
    }

    function Get-TestDscResourceSchemaContent
    {
        $content = @'
[ClassVersion("1.0.0"), FriendlyName("cTestResource")]
class TestResource : OMI_BaseResource
{
    [Key] string KeyProperty;
    [required] string RequiredProperty;
    [write] string WriteProperty;
    [read] string ReadProperty;
    [write, EmbeddedInstance("SubClass")] string SubClass;
};
 
[ClassVersion("1.0.0")]
class SubClass
{
    [write] string WriteProperty1;
    [write] string WriteProperty2;
};
 
'@


        return $content
    }

}