DscResource.Tests/Tests/Unit/TestHelper.Tests.ps1

$script:ModuleName = 'TestHelper'
$script:moduleRootPath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent

Import-Module -Name (Join-Path -Path $script:moduleRootPath -ChildPath "$($script:ModuleName).psm1") -Force

InModuleScope $script:ModuleName {
    Describe 'TestHelper\Get-DscIntegrationTestOrderNumber' {
        BeforeAll {
            # Set up TestDrive
            $filePath_NoAttribute = Join-Path -Path $TestDrive -ChildPath 'NoAttribute.ps1'
            $filePath_WrongAttribute = Join-Path -Path $TestDrive -ChildPath 'WrongAttribute.ps1'
            $filePath_CorrectAttribute = Join-Path -Path $TestDrive -ChildPath 'CorrectAttribute.ps1'
            $filePath_CorrectAttributeWithExtraNamedArgument = Join-Path -Path $TestDrive -ChildPath 'CorrectAttributeWithExtraNamedArgument.ps1'

            '
            param()
            '
 | Out-File -FilePath $filePath_NoAttribute

            '
            [Microsoft.DscResourceKit.IntegrationTest(UnknownParameter = 2)]
            param()
            '
 | Out-File -FilePath $filePath_WrongAttribute

            '
            [Microsoft.DscResourceKit.IntegrationTest(OrderNumber = 2)]
            param()
            '
 | Out-File -FilePath $filePath_CorrectAttribute

            '
            [Microsoft.DscResourceKit.IntegrationTest(OrderNumber = 2, UnknownParameter = ''Test'')]
            param()
            '
 | Out-File -FilePath $filePath_CorrectAttributeWithExtraNamedArgument

        }

        Context 'When configuration file does not contain a attribute' {
            It 'Should not return any value' {
                $result = Get-DscIntegrationTestOrderNumber -Path $filePath_NoAttribute
                $result | Should -BeNullOrEmpty
            }
        }

        Context 'When configuration file contain a attribute but without the correct named attribute argument' {
            It 'Should not return any value' {
                $result = Get-DscIntegrationTestOrderNumber -Path $filePath_WrongAttribute
                $result | Should -BeNullOrEmpty
            }
        }

        Context 'When configuration file does contain an attribute and with the correct named attribute argument' {
            It 'Should not return any value' {
                $result = Get-DscIntegrationTestOrderNumber -Path $filePath_CorrectAttribute
                $result | Should -BeExactly 2
            }
        }

        Context 'When configuration file does contain an attribute and with the correct named attribute argument, and there is also another named argument' {
            It 'Should not return any value' {
                $result = Get-DscIntegrationTestOrderNumber -Path $filePath_CorrectAttributeWithExtraNamedArgument
                $result | Should -BeExactly 2
            }
        }
    }

    Describe 'TestHelper\Get-DscTestContainerInformation' {
        BeforeAll {
            $mockContainerImageName = 'Organization/ImageName:Tag'
            $mockContainerName = 'ContainerName'
        }

        Context 'When the test is an integration test' {
            BeforeAll {
                # Set up TestDrive
                $filePath_NoAttribute = Join-Path -Path $TestDrive -ChildPath 'NoAttribute.ps1'
                $filePath_WrongAttribute = Join-Path -Path $TestDrive -ChildPath 'WrongAttribute.ps1'
                $filePath_CorrectAttribute = Join-Path -Path $TestDrive -ChildPath 'CorrectAttribute.ps1'
                $filePath_CorrectAttributeOnlyContainerName = Join-Path -Path $TestDrive -ChildPath 'CorrectAttributeOnlyContainerName.ps1'
                $filePath_CorrectAttributeWithOrderNumber = Join-Path -Path $TestDrive -ChildPath 'CorrectAttributeWithOrderNumber.ps1'

                '
                param()
                '
 | Out-File -FilePath $filePath_NoAttribute

                '
                [Microsoft.DscResourceKit.IntegrationTest(UnknownParameter = 2)]
                param()
                '
 | Out-File -FilePath $filePath_WrongAttribute

                ('
                [Microsoft.DscResourceKit.IntegrationTest(ContainerName = ''{0}'')]
                param()
                '
 -f $mockContainerName) | Out-File -FilePath $filePath_CorrectAttributeOnlyContainerName

                ('
                [Microsoft.DscResourceKit.IntegrationTest(ContainerName = ''{0}'', ContainerImage = ''{1}'')]
                param()
                '
 -f $mockContainerName, $mockContainerImageName) | Out-File -FilePath $filePath_CorrectAttribute

                ('
                [Microsoft.DscResourceKit.IntegrationTest(OrderNumber = 1, ContainerName = ''{0}'', ContainerImage = ''{1}'')]
                param()
                '
 -f $mockContainerName, $mockContainerImageName) | Out-File -FilePath $filePath_CorrectAttributeWithOrderNumber
            }

            Context 'When configuration file does not contain the correct attribute' {
                It 'Should not return any value' {
                    $result = Get-DscTestContainerInformation -Path $filePath_NoAttribute
                    $result | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file contain a attribute but without the correct named attribute arguments' {
                It 'Should not return any value' {
                    $result = Get-DscTestContainerInformation -Path $filePath_WrongAttribute
                    $result | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file does contain a attribute and with only the correct named attribute argument ''ContainerName''' {
                It 'Should return the correct container name, and not return a container image name' {
                    $result = Get-DscTestContainerInformation -Path $filePath_CorrectAttributeOnlyContainerName
                    $result | Should -BeOfType [System.Collections.Hashtable]
                    $result.ContainerName | Should -Be $mockContainerName
                    $result.ContainerImage | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file does contain a attribute and with the correct named attribute arguments' {
                It 'Should return the correct container name and container image name' {
                    $result = Get-DscTestContainerInformation -Path $filePath_CorrectAttribute
                    $result | Should -BeOfType [System.Collections.Hashtable]
                    $result.ContainerName | Should -Be $mockContainerName
                    $result.ContainerImage | Should -Be $mockContainerImageName
                }
            }

            Context 'When configuration file contain more attributes than just the correct named attribute arguments' {
                It 'Should return the correct container name and container image name' {
                    $result = Get-DscTestContainerInformation -Path $filePath_CorrectAttributeWithOrderNumber
                    $result | Should -BeOfType [System.Collections.Hashtable]
                    $result.ContainerName | Should -Be $mockContainerName
                    $result.ContainerImage | Should -Be $mockContainerImageName
                }
            }
        }

        Context 'When the test is a unit tests' {
            BeforeAll {
                # Set up TestDrive
                $filePath_NoAttribute = Join-Path -Path $TestDrive -ChildPath 'NoAttribute.ps1'
                $filePath_WrongAttribute = Join-Path -Path $TestDrive -ChildPath 'WrongAttribute.ps1'
                $filePath_CorrectAttribute = Join-Path -Path $TestDrive -ChildPath 'CorrectAttribute.ps1'
                $filePath_CorrectAttributeOnlyContainerName = Join-Path -Path $TestDrive -ChildPath 'CorrectAttributeOnlyContainerName.ps1'

                '
                param()
                '
 | Out-File -FilePath $filePath_NoAttribute

                '
                [Microsoft.DscResourceKit.UnitTest(UnknownParameter = 2)]
                param()
                '
 | Out-File -FilePath $filePath_WrongAttribute

                ('
                [Microsoft.DscResourceKit.UnitTest(ContainerName = ''{0}'')]
                param()
                '
 -f $mockContainerName) | Out-File -FilePath $filePath_CorrectAttributeOnlyContainerName

                ('
                [Microsoft.DscResourceKit.UnitTest(ContainerName = ''{0}'', ContainerImage = ''{1}'')]
                param()
                '
 -f $mockContainerName, $mockContainerImageName) | Out-File -FilePath $filePath_CorrectAttribute
            }

            Context 'When configuration file does not contain the correct attribute' {
                It 'Should not return any value' {
                    $result = Get-DscTestContainerInformation -Path $filePath_NoAttribute
                    $result | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file contain a attribute but without the correct named attribute arguments' {
                It 'Should not return any value' {
                    $result = Get-DscTestContainerInformation -Path $filePath_WrongAttribute
                    $result | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file does contain a attribute and with only the correct named attribute argument ''ContainerName''' {
                It 'Should return the correct container name, and not return a container image name' {
                    $result = Get-DscTestContainerInformation -Path $filePath_CorrectAttributeOnlyContainerName
                    $result | Should -BeOfType [System.Collections.Hashtable]
                    $result.ContainerName | Should -Be $mockContainerName
                    $result.ContainerImage | Should -BeNullOrEmpty
                }
            }

            Context 'When configuration file does contain a attribute and with the correct named attribute arguments' {
                It 'Should return the correct container name and container image name' {
                    $result = Get-DscTestContainerInformation -Path $filePath_CorrectAttribute
                    $result | Should -BeOfType [System.Collections.Hashtable]
                    $result.ContainerName | Should -Be $mockContainerName
                    $result.ContainerImage | Should -Be $mockContainerImageName
                }
            }
        }
    }


    Describe 'TestHelper\Test-IsRepositoryDscResourceTests' {
        Context 'When the repository is DscResource.Tests' {
            BeforeAll {
                Mock -CommandName 'Split-Path'
                Mock -CommandName 'Get-ChildItem' -MockWith {
                    return $null
                }
            }

            It 'Should return $true' {
                Test-IsRepositoryDscResourceTests | Should -Be $true

                Assert-MockCalled -CommandName 'Split-Path' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Get-ChildItem' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When the repository is not DscResource.Tests' {
            BeforeAll {
                Mock -CommandName 'Split-Path'
                Mock -CommandName 'Get-ChildItem' -MockWith {
                    return 'manifest.psd1'
                }
            }

            It 'Should return $false' {
                Test-IsRepositoryDscResourceTests | Should -Be $false

                Assert-MockCalled -CommandName 'Split-Path' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Get-ChildItem' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Install-DependentModule' {
        Context 'When a dependent module need to be installed' {
            BeforeAll {
                # Only save the original value if the test is running in AppVeyor.
                if ($env:APPVEYOR -eq $true)
                {
                    $originalAppVeyorEnvironmentVariable = $env:APPVEYOR
                }

                Mock -CommandName 'Install-Module'
                Mock -CommandName 'Write-Warning'
                Mock -CommandName 'Get-Module' -MockWith {
                    return $false
                }
            }

            AfterAll {
                <#
                    if $originalAppVeyorEnvironmentVariable is null then we ran
                    this outside of AppVeyor
                #>

                if ($null -ne $originalAppVeyorEnvironmentVariable)
                {
                    <#
                        Restore the environment variable if the test are running
                        in AppVeyor.
                    #>

                    $env:APPVEYOR = $originalAppVeyorEnvironmentVariable
                }
                else
                {
                    <#
                        Remove the environment variable if we are running tests
                        outside of AppVeyor.
                    #>

                    Remove-Item env:APPVEYOR
                }
            }

            $moduleName1 = 'ModuleWithoutVersion'
            $moduleName2 = 'ModuleWithSpecificVersion'
            $moduleName3 = 'ModuleWhenTestIsNotRunInAppVeyor'

            $testCases = @(
                @{
                    MockModuleName = $moduleName1
                    MockModule     = @{
                        Name = $moduleName1
                    }
                    MockAppVeyor   = $true
                },
                @{
                    MockModuleName = $moduleName2
                    MockModule     = @{
                        Name    = $moduleName2
                        Version = '2.0.0.0'
                    }
                    MockAppVeyor   = $true
                },
                @{
                    MockModuleName = $moduleName3
                    MockModule     = @{
                        Name = $moduleName3
                    }
                    MockAppVeyor   = $false
                }
            )

            It 'Should install the dependent module ''<MockModuleName>'' without throwing' -TestCases $testCases {
                param
                (
                    # Name of the module being tests, for use in the It-block
                    [Parameter()]
                    [System.String]
                    $MockModuleName,

                    # Hash table containing the mock module
                    [Parameter()]
                    [System.Collections.HashTable]
                    $MockModule,

                    # Boolean value to mock environment variable $env:APPVEYOR
                    [Parameter()]
                    [System.Boolean]
                    $MockAppVeyor
                )

                if ($MockAppVeyor)
                {
                    $env:APPVEYOR = $true
                }
                else
                {
                    $env:APPVEYOR = $false
                }

                { Install-DependentModule -Module $MockModule } | Should -Not -Throw

                if ($MockAppVeyor)
                {
                    Assert-MockCalled -CommandName 'Get-Module' -Exactly -Times 1 -Scope It
                    Assert-MockCalled -CommandName 'Install-Module' -Exactly -Times 1 -Scope It
                }
                else
                {
                    Assert-MockCalled -CommandName 'Get-Module' -Exactly -Times 1 -Scope It
                    Assert-MockCalled -CommandName 'Write-Warning' -Exactly -Times 1 -Scope It
                }
            }
        }
    }

    Describe 'TestHelper\Get-ResourceModulesInConfiguration' {
        BeforeAll {
            $moduleName1 = 'ModuleWithoutVersion'
            $moduleName2 = 'ModuleWithSpecificVersion'
            $moduleVersion = '2.0.0.0'

            $arrayModuleName1 = 'ModuleNameArray1'
            $arrayModuleName2 = 'ModuleNameArray2'

            $scriptPath = Join-Path -Path $TestDrive -ChildPath 'TestConfiguration.ps1'
        }

        Context 'When a script file requires a module' {
            It 'Should return the correct module name' {
                "
                    Configuration Test
                    {
                        Import-DscResource -ModuleName $moduleName1
                    }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-ResourceModulesInConfiguration -ConfigurationPath $scriptPath
                $result.Name | Should -Be $moduleName1
                $result.Version | Should -BeNullOrEmpty
            }
        }

        Context 'When a script file requires a module with specific version' {
            It 'Should return the correct module name and version' {
                "
                    Configuration Test
                    {
                        Import-DscResource -ModuleName $moduleName2 -ModuleVersion $moduleVersion
                    }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-ResourceModulesInConfiguration -ConfigurationPath $scriptPath
                $result.Name | Should -Be $moduleName2
                $result.Version | Should -Be $moduleVersion
            }
        }

        Context 'When a script file requires two modules' {
            It 'Should return the correct module names' {
                "
                    Configuration Test
                    {
                        Import-DscResource -ModuleName $moduleName1
                        Import-DscResource -ModuleName $moduleName2
                    }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-ResourceModulesInConfiguration -ConfigurationPath $scriptPath
                $result.Count | Should -Be 2
                $result[0].Name | Should -Be $moduleName1
                $result[0].Version | Should -BeNullOrEmpty
                $result[1].Name | Should -Be $moduleName2
                $result[1].Version | Should -BeNullOrEmpty
            }
        }

        Context 'When a script file requires two modules which are written in an string array' {
            It 'Should return the correct module name when using an array' {
                "
                    Configuration Test
                    {
                        Import-DscResource -ModuleName $arrayModuleName1,$arrayModuleName2
                    }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-ResourceModulesInConfiguration -ConfigurationPath $scriptPath
                $result.Count | Should -Be 2
                $result[0].Name | Should -Be $arrayModuleName1
                $result[0].Version | Should -BeNullOrEmpty
                $result[1].Name | Should -Be $arrayModuleName2
                $result[1].Version | Should -BeNullOrEmpty
            }
        }
    }

    Describe 'TestHelper\Get-RelativePathFromModuleRoot' {
        Context 'When to get the relative path from module root' {
            BeforeAll {
                $relativePath = 'Modules'
                $filePath = Join-Path $TestDrive -ChildPath $relativePath
                $moduleRootPath = $TestDrive

                # Adds a backslash to make sure it gets trimmed.
                $filePath += '\'
            }

            It 'Should return the correct relative path' {
                $result = Get-RelativePathFromModuleRoot `
                    -FilePath $filePath `
                    -ModuleRootFilePath $moduleRootPath

                $result | Should -Be $relativePath
            }
        }
    }

    Describe 'TestHelper\Test-FileHasByteOrderMark' {
        Context 'When a file has Byte Order Mark (BOM)' {
            BeforeAll {
                $fileName = 'TestByteOrderMark.ps1'
                $filePath = Join-Path $TestDrive -ChildPath $fileName

                $fileName | Out-File -FilePath $filePath -Encoding utf8
            }

            It 'Should return $true' {
                $result = Test-FileHasByteOrderMark -FilePath $filePath
                $result | Should -Be $true
            }
        }

        Context 'When a file has no Byte Order Mark (BOM)' {
            BeforeAll {
                $fileName = 'TestNoByteOrderMark.ps1'
                $filePath = Join-Path $TestDrive -ChildPath $fileName

                $fileName | Out-File -FilePath $filePath -Encoding ascii
            }

            It 'Should return $false' {
                $result = Test-FileHasByteOrderMark -FilePath $filePath
                $result | Should -Be $false
            }
        }
    }

    Describe 'TestHelper\Get-PSModulePathItem' {
        Context 'When querying for folder path' {
            It 'Should return the correct folder' {
                $systemModulePath = Join-Path `
                    -Path $env:SystemRoot `
                    -ChildPath 'system32\WindowsPowerShell\v1.0\Modules'

                Get-PSModulePathItem -Prefix $env:SystemRoot | Should -Be $systemModulePath
            }
        }

        Context 'When querying for a wrong path' {
            BeforeAll {
                Mock -CommandName 'Write-Error'
            }

            It 'Should write an error message the correct folder' {
                Get-PSModulePathItem -Prefix 'DummyPath' | Should -BeNullOrEmpty

                Assert-MockCalled -CommandName 'Write-Error' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Get-PSHomePSModulePathItem' {
        Context 'When querying for the modules folder path' {
            BeforeAll {
                $path = $TestDrive

                Mock -CommandName Get-PSModulePathItem -MockWith {
                    return $path
                }
            }

            It 'Should return the correct folder' {
                Get-PSHomePSModulePathItem | Should -Be $path
            }
        }
    }

    Describe 'TestHelper\Get-UserProfilePSModulePathItem' {
        Context 'When querying for the user profile modules folder path' {
            BeforeAll {
                $path = $TestDrive

                Mock -CommandName Get-PSModulePathItem -MockWith {
                    return $path
                }
            }

            It 'Should return the correct folder' {
                Get-UserProfilePSModulePathItem | Should -Be $path
            }
        }
    }

    <#
        The following helper functions are tested with these tests:
 
        Get-PesterDescribeOptInStatus
        Get-PesterDescribeName
        Get-CommandNameParameterValue
    #>

    $describeName = 'TestHelper\Get-PesterDescribeOptInStatus'
    Describe $describeName {
        Context 'When querying for the status of an opted-in test' {
            It 'Should return $true' {
                $result = Get-PesterDescribeOptInStatus -OptIns @($describeName)
                $result | Should -Be $true
            }
        }

        Context 'When querying for the status of an opted-out test' {
            It 'Should return $false' {
                $result = Get-PesterDescribeOptInStatus -OptIns @('Opt-Out')
                $result | Should -Be $false
            }
        }

        # Regression test for empty array (or null value).
        Context 'When querying for the status of an opted-in test, but there were no opt-ins read from .MetaTestOptIn.json' {
            It 'Should not throw an error' {
                Mock -Command Write-Warning

                { Get-PesterDescribeOptInStatus -OptIns @() } | Should -Not -Throw

                Assert-MockCalled -CommandName Write-Warning
            }
        }
    }

    Describe 'TestHelper\Get-OptInStatus' {
        Context 'When querying for the status of an opted-in test' {
            It 'Should return $true when querying for the it status of an opted-in test' {
                $result = Get-OptInStatus -OptIns @('Opt-In') -Name 'Opt-In'
                $result | Should -Be $true
            }
        }

        Context 'When querying for the status of an opted-out test' {
            It 'Should return $false when querying for the it of an opted-out test' {
                $result = Get-OptInStatus -OptIns @('Opt-Out') -Name 'Opt-In'
                $result | Should -Be $false
            }
        }

        # Regression test for empty array (or null value).
        Context 'When querying for the status of an opted-in test, but there were no opt-ins read from .MetaTestOptIn.json' {
            It 'Should not throw an error' {
                Mock -Command Write-Warning

                { Get-OptInStatus -OptIns @() -Name 'Opt-In' } | Should -Not -Throw

                Assert-MockCalled -CommandName Write-Warning
            }
        }
    }

    Describe 'TestHelper\Install-NuGetExe' {
        Context 'When downloading NuGet' {
            BeforeAll {
                Mock -CommandName 'Invoke-WebRequest'
            }

            It 'Should download NuGet without throwing' {
                { Install-NuGetExe -OutFile $TestDrive } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Invoke-WebRequest' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Get-SuppressedPSSARuleNameList' {
        BeforeAll {
            $rule1 = "'PSAvoidUsingConvertToSecureStringWithPlainText'"
            $rule2 = "'PSAvoidGlobalVars'"

            $scriptPath = Join-Path -Path $TestDrive -ChildPath 'TestModule.psm1'
        }

        Context 'When a module files contains suppressed rules' {
            It 'Should return the all the suppressed rules' {
                "
                # Testing suppressing this rule
                [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute($rule1, '')]
                [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute($rule2, '')]
                param()
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-SuppressedPSSARuleNameList -FilePath $scriptPath
                $result.Count | Should -Be 4
                $result[0] | Should -Be $rule1
                $result[1] | Should -Be "''"
                $result[2] | Should -Be $rule2
                $result[3] | Should -Be "''"
            }
        }
    }

    Describe 'TestHelper\Get-ModuleScriptResourceNames' {
        BeforeAll {
            $resourceName1 = 'TestResource1'
            $resourceName2 = 'TestResource2'
            $resourcesPath = Join-Path -Path $TestDrive -ChildPath 'DscResources'
            $testResourcePath1 = (Join-Path -Path $resourcesPath -ChildPath $resourceName1)
            $testResourcePath2 = (Join-Path -Path $resourcesPath -ChildPath $resourceName2)

            New-Item -Path $resourcesPath -ItemType Directory
            New-Item -Path $testResourcePath1 -ItemType Directory
            New-Item -Path $testResourcePath2 -ItemType Directory

            'resource_schema1' | Out-File -FilePath ('{0}.schema.mof' -f $testResourcePath1) -Encoding ascii
            'resource_schema2' | Out-File -FilePath ('{0}.schema.mof' -f $testResourcePath2) -Encoding ascii
        }

        Context 'When a module contains resources' {
            It 'Should return all the resource names' {
                $result = Get-ModuleScriptResourceNames -ModulePath $TestDrive
                $result.Count | Should -Be 2
                $result[0] | Should -Be $resourceName1
                $result[1] | Should -Be $resourceName2
            }
        }
    }

    Describe 'TestHelper\Test-ModuleContainsScriptResource' {
        Context 'When a module contains script resources' {
            BeforeAll {
                $resourceName1 = 'TestResource1'
                $resourceName2 = 'TestResource2'
                $resourcesPath = Join-Path -Path $TestDrive -ChildPath 'DscResources'
                $testResourcePath1 = (Join-Path -Path $resourcesPath -ChildPath $resourceName1)
                $testResourcePath2 = (Join-Path -Path $resourcesPath -ChildPath $resourceName2)

                New-Item -Path $resourcesPath -ItemType Directory
                New-Item -Path $testResourcePath1 -ItemType Directory
                New-Item -Path $testResourcePath2 -ItemType Directory

                'resource_schema1' | Out-File -FilePath ('{0}.schema.mof' -f $testResourcePath1) -Encoding ascii
                'resource_schema2' | Out-File -FilePath ('{0}.schema.mof' -f $testResourcePath2) -Encoding ascii
            }

            It 'Should return $true' {
                $result = Test-ModuleContainsScriptResource -ModulePath $TestDrive
                $result | Should -Be $true
            }
        }

        Context 'When a module does not contain a script resource' {
            It 'Should return $false' {
                $result = Test-ModuleContainsScriptResource -ModulePath $TestDrive
                $result | Should -Be $false
            }
        }
    }

    Describe 'TestHelper\Test-FileInUnicode' {
        Context 'When a file is unicode' {
            BeforeAll {
                $fileName = 'TestUnicode.ps1'
                $filePath = Join-Path $TestDrive -ChildPath $fileName

                $fileName | Out-File -FilePath $filePath -Encoding unicode
            }

            It 'Should return $true' {
                $result = Test-FileInUnicode -FileInfo $filePath
                $result | Should -Be $true
            }
        }

        Context 'When a file is not unicode' {
            BeforeAll {
                $fileName = 'TestNotUnicode.ps1'
                $filePath = Join-Path $TestDrive -ChildPath $fileName

                $fileName | Out-File -FilePath $filePath -Encoding ascii
            }

            It 'Should return $false' {
                $result = Test-FileInUnicode -FileInfo $filePath
                $result | Should -Be $false
            }
        }
    }

    Describe 'TestHelper\Get-TextFilesList' {
        BeforeAll {
            $mofFileType = 'test.schema.mof'
            $psm1FileType = 'test.psm1'

            'resource_schema1' | Out-File -FilePath (Join-Path -Path $TestDrive -ChildPath $mofFileType) -Encoding ascii
            'resource_schema2' | Out-File -FilePath (Join-Path -Path $TestDrive -ChildPath $psm1FileType) -Encoding ascii
        }

        Context 'When a module contains text files' {
            It 'Should return all the file names of all the text files' {
                $result = Get-TextFilesList -Root $TestDrive
                $result.Count | Should -Be 2

                # Uncertain of returned order, so verify so each value is in the array.
                $result[0] | Should -BeIn @($mofFileType, $psm1FileType)
                $result[1] | Should -BeIn @($mofFileType, $psm1FileType)
            }
        }
    }

    Describe 'TestHelper\Get-Psm1FileList' {
        BeforeAll {
            $psm1FileType = 'test.psm1'
            $filePath = Join-Path -Path $TestDrive -ChildPath $psm1FileType
            'testfile' | Out-File -FilePath $filePath -Encoding ascii
        }

        Context 'When a module contains module files' {
            It 'Should return all the file names of all the module files' {
                $result = Get-Psm1FileList -FilePath $TestDrive
                $result.Name | Should -Be $psm1FileType
            }
        }
    }

    Describe 'TestHelper\Get-FileParseErrors' {
        BeforeAll {
            $filePath = (Join-Path -Path $TestDrive -ChildPath 'test.psm1')
        }

        Context 'When a module does not contain parse errors' {
            BeforeEach {
                'function MockTestFunction {}' | Out-File -FilePath $filePath -Encoding ascii
            }

            It 'Should return $null' {
                Get-FileParseErrors -FilePath $filePath | Should -BeNullOrEmpty
            }
        }

        Context 'When a module do contain parse errors' {
            BeforeEach {
                # The param() is deliberately spelled wrong to get a parse error.
                'function MockTestFunction { parm() }' | Out-File -FilePath $filePath -Encoding ascii
            }

            It 'Should return the correct error string' {
                Get-FileParseErrors -FilePath $filePath | Should -Match 'An expression was expected after ''\('''
            }
        }
    }

    Describe 'TestHelper\Test-ModuleContainsClassResource' {
        BeforeAll {
            $filePath = (Join-Path -Path $TestDrive -ChildPath 'test.psm1')
            'testfile' | Out-File -FilePath $filePath -Encoding ascii
        }

        Context 'When a module contains class resources' {
            BeforeEach {
                Mock -CommandName 'Test-FileContainsClassResource' -MockWith {
                    return $true
                }
            }

            It 'Should return $true' {
                $result = Test-ModuleContainsClassResource -ModulePath $TestDrive
                $result | Should -Be $true

                Assert-MockCalled -CommandName 'Test-FileContainsClassResource' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When a module does not contain a class resource' {
            BeforeEach {
                Mock -CommandName 'Test-FileContainsClassResource' -MockWith {
                    return $false
                }
            }

            It 'Should return $false' {
                $result = Test-ModuleContainsClassResource -ModulePath $TestDrive
                $result | Should -Be $false

                Assert-MockCalled -CommandName 'Test-FileContainsClassResource' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When a module does not contain any resources' {
            BeforeEach {
                Mock -CommandName 'Get-Psm1FileList'
                Mock -CommandName 'Test-FileContainsClassResource'
            }

            It 'Should return $false' {
                $result = Test-ModuleContainsClassResource -ModulePath $TestDrive
                $result | Should -Be $false

                Assert-MockCalled -CommandName 'Get-Psm1FileList' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Test-FileContainsClassResource' -Exactly -Times 0 -Scope It
            }
        }
    }

    Describe 'TestHelper\Get-ClassResourceNameFromFile' {
        BeforeAll {
            $mockResourceName1 = 'TestResourceName1'
            $mockResourceName2 = 'TestResourceName2'

            $scriptPath = Join-Path -Path $TestDrive -ChildPath 'TestModule.psm1'
        }

        Context 'When querying for the name of a class-based resource' {
            It 'Should return the correct name of the resource' {
                "
                [DscResource()]
                class $mockResourceName1
                {
                }
 
                [DscResource()]
                class $mockResourceName2
                {
                }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Get-ClassResourceNameFromFile -FilePath $scriptPath
                $result.Count | Should -Be 2
                $result[0] | Should -Be $mockResourceName1
                $result[1] | Should -Be $mockResourceName2
            }
        }
    }

    Describe 'TestHelper\Test-FileContainsClassResource' {
        BeforeAll {
            $mockResourceName1 = 'TestResourceName1'
            $mockResourceName2 = 'TestResourceName2'

            $scriptPath = Join-Path -Path $TestDrive -ChildPath 'TestModule.psm1'
        }

        Context 'When module file contain class-based resources' {
            It 'Should return $true' {
                "
                [DscResource()]
                class $mockResourceName1
                {
                }
 
                [DscResource()]
                class $mockResourceName2
                {
                }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Test-FileContainsClassResource -FilePath $scriptPath
                $result | Should -Be $true
            }
        }

        Context 'When module file does not contain class-based resources' {
            It 'Should return $false' {
                "
                function $mockResourceName1
                {
                }
                "
 | Out-File -FilePath $scriptPath -Encoding ascii -Force

                $result = Test-FileContainsClassResource -FilePath $scriptPath
                $result | Should -Be $false
            }
        }
    }

    Describe 'TestHelper\Reset-Dsc' {
        BeforeAll {
            Mock -CommandName 'Stop-DscConfiguration'
            Mock -CommandName 'Remove-DscConfigurationDocument'
        }

        Context 'When resetting the DSC LCM' {
            It 'Should reset the LCM without throwing' {
                { Reset-Dsc } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Stop-DscConfiguration' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Remove-DscConfigurationDocument' -ParameterFilter {
                    $Stage -eq 'Current'
                } -Exactly -Times 1 -Scope It

                Assert-MockCalled -CommandName 'Remove-DscConfigurationDocument' -ParameterFilter {
                    $Stage -eq 'Pending'
                } -Exactly -Times 1 -Scope It

                Assert-MockCalled -CommandName 'Remove-DscConfigurationDocument' -ParameterFilter {
                    $Stage -eq 'Previous'
                } -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Restore-TestEnvironment' {
        BeforeAll {
            Mock -CommandName 'Reset-DSC'
            Mock -CommandName 'Set-PSModulePath'
            Mock -CommandName 'Set-ExecutionPolicy'

            $testCases = @(
                @{
                    TestDescription = 'when restoring from a unit test'
                    TestEnvironment = @{
                        DSCModuleName      = 'TestModule'
                        DSCResourceName    = 'TestResource'
                        TestType           = 'Unit'
                        ImportedModulePath = $moduleToImportFilePath
                        OldPSModulePath    = $env:PSModulePath
                        OldExecutionPolicy = Get-ExecutionPolicy
                    }
                },

                @{
                    TestDescription = 'when restoring from an integration test'
                    TestEnvironment = @{
                        DSCModuleName      = 'TestModule'
                        DSCResourceName    = 'TestResource'
                        TestType           = 'Integration'
                        ImportedModulePath = $moduleToImportFilePath
                        OldPSModulePath    = $env:PSModulePath
                        OldExecutionPolicy = Get-ExecutionPolicy
                    }
                }
            )
        }

        Context 'When restoring the test environment' {
            It 'Should restore without throwing <TestDescription>' -TestCases $testCases {
                param
                (
                    # String containing a description to add to the It-block name
                    [Parameter()]
                    [System.String]
                    $TestDescription,

                    # Hash table containing the test environment
                    [Parameter()]
                    [System.Collections.HashTable]
                    $TestEnvironment
                )

                { Restore-TestEnvironment -TestEnvironment $TestEnvironment } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Set-PSModulePath' -Exactly -Times 0
            }
        }

        # Regression test for issue #70.
        Context 'When restoring the test environment from an integration test that changed the PSModulePath' {
            It 'Should restore without throwing and call the correct mocks' {
                $testEnvironmentParameter = @{
                    DSCModuleName      = 'TestModule'
                    DSCResourceName    = 'TestResource'
                    TestType           = 'Integration'
                    ImportedModulePath = $moduleToImportFilePath
                    OldPSModulePath    = 'Wrong paths'
                    OldExecutionPolicy = Get-ExecutionPolicy
                }

                { Restore-TestEnvironment -TestEnvironment $testEnvironmentParameter } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Reset-DSC' -Exactly -Times 1 -Scope It
                #Assert-MockCalled -CommandName 'Set-ExecutionPolicy' -Exactly -Times 1 -Scope It

                Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
                    $Path -eq $testEnvironmentParameter.OldPSModulePath `
                        -and $PSBoundParameters.ContainsKey('Machine') -eq $false
                } -Exactly -Times 1 -Scope It

                Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
                    $Path -eq $testEnvironmentParameter.OldPSModulePath `
                        -and $PSBoundParameters.ContainsKey('Machine') -eq $true
                } -Exactly -Times 1 -Scope It
            }
        }

        Context 'When restoring the test environment from an integration test that has the wrong execution policy' {
            BeforeAll {
                <#
                    Find out which execution policy should be used when mocking
                    the test parameters.
                #>

                if ((Get-ExecutionPolicy) -ne [Microsoft.PowerShell.ExecutionPolicy]::AllSigned )
                {
                    $mockExecutionPolicy = [Microsoft.PowerShell.ExecutionPolicy]::AllSigned
                }
                else
                {
                    $mockExecutionPolicy = [Microsoft.PowerShell.ExecutionPolicy]::Unrestricted
                }
            }

            It 'Should restore without throwing' {
                $testEnvironmentParameter = @{
                    DSCModuleName      = 'TestModule'
                    DSCResourceName    = 'TestResource'
                    TestType           = 'Integration'
                    ImportedModulePath = $moduleToImportFilePath
                    OldPSModulePath    = $env:PSModulePath
                    OldExecutionPolicy = $mockExecutionPolicy
                }

                { Restore-TestEnvironment -TestEnvironment $testEnvironmentParameter } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Set-ExecutionPolicy' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Initialize-TestEnvironment' {
        Context 'When initializing the test environment' {
            BeforeAll {
                $mockDscModuleName = 'TestModule'
                $mockDscResourceName = 'TestResource'

                Mock -CommandName 'Set-PSModulePath'
                Mock -CommandName 'Reset-DSC'
                Mock -CommandName 'Set-ExecutionPolicy'
                Mock -CommandName 'Import-Module'

                Mock -CommandName 'Split-Path' -MockWith {
                    return $TestDrive
                }

                Mock -CommandName 'Get-ExecutionPolicy' -MockWith {
                    'Restricted'
                }

                <#
                    Build the mocked resource folder and file structure for both
                    mof- and class-based resources.
                #>

                $filePath = Join-Path -Path $TestDrive -ChildPath ('{0}.psd1' -f $mockDscModuleName)
                'test manifest' | Out-File -FilePath $filePath -Encoding ascii

                $mockDscResourcesPath = Join-Path -Path $TestDrive -ChildPath 'DSCResources'
                $mockDscClassResourcesPath = Join-Path -Path $TestDrive -ChildPath 'DSCClassResources'
                New-Item -Path $mockDscResourcesPath -ItemType Directory
                New-Item -Path $mockDscClassResourcesPath -ItemType Directory

                $mockMofResourcePath = Join-Path -Path $mockDscResourcesPath -ChildPath $mockDscResourceName
                $mockClassResourcePath = Join-Path -Path $mockDscClassResourcesPath -ChildPath $mockDscResourceName
                New-Item -Path $mockMofResourcePath -ItemType Directory
                New-Item -Path $mockClassResourcePath -ItemType Directory

                $filePath = Join-Path -Path $mockMofResourcePath -ChildPath ('{0}.psm1' -f $mockDscResourceName)
                'test mof resource module file' | Out-File -FilePath $filePath -Encoding ascii
                $filePath = Join-Path -Path $mockClassResourcePath -ChildPath ('{0}.psm1' -f $mockDscResourceName)
                'test class resource module file' | Out-File -FilePath $filePath -Encoding ascii

                $testCases = @(
                    @{
                        TestType     = 'Unit'
                        ResourceType = 'Mof'
                    },

                    @{
                        TestType     = 'Unit'
                        ResourceType = 'Class'
                    },

                    @{
                        TestType     = 'Integration'
                        ResourceType = 'Mof'
                    }
                )
            }

            It 'Should initializing without throwing when test type is <TestType> and resource type is <ResourceType>' -TestCases $testCases {
                param
                (
                    # String containing the test type; Unit or Integration.
                    [Parameter()]
                    [System.String]
                    $TestType,

                    # String containing a resource type; Mof or Class.
                    [Parameter()]
                    [System.String]
                    $ResourceType
                )

                $initializeTestEnvironmentParameters = @{
                    DSCModuleName   = $mockDscModuleName
                    DSCResourceName = $mockDscResourceName
                    TestType        = $TestType
                    ResourceType    = $ResourceType
                }

                { Initialize-TestEnvironment @initializeTestEnvironmentParameters } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Split-Path' -Exactly -Times 2 -Scope It
                Assert-MockCalled -CommandName 'Import-Module' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
                    $PSBoundParameters.ContainsKey('Machine') -eq $false
                } -Exactly -Times 1 -Scope It

                if ($TestEnvironment.TestType -eq 'Integration')
                {
                    Assert-MockCalled -CommandName 'Reset-DSC' -Exactly -Times 1 -Scope It
                    Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
                        $PSBoundParameters.ContainsKey('Machine') -eq $true
                    } -Exactly -Times 1 -Scope It
                }

                Assert-MockCalled -CommandName 'Get-ExecutionPolicy' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Set-ExecutionPolicy' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When there is no module manifest file' {
            BeforeAll {
                Mock -CommandName 'Split-Path' -MockWith {
                    return $TestDrive
                }
            }

            It 'Should throw the correct error' {
                $initializeTestEnvironmentParameters = @{
                    DSCModuleName   = $mockDscModuleName
                    DSCResourceName = $mockDscResourceName
                    TestType        = 'Unit'
                }

                $errorMessage = 'Module manifest could not be found for the module {0} in the root folder {1}' -f $mockDscModuleName, $TestDrive
                { Initialize-TestEnvironment @initializeTestEnvironmentParameters } | Should -Throw $errorMessage

                Assert-MockCalled -CommandName 'Split-Path' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Install-ModuleFromPowerShellGallery' {
        BeforeAll {
            <#
                A placeholder/wrapper for the nuget.exe so the code is tricked
                in thinking it exist, and so that we can mock it.
            #>

            function nuget.exe
            {
            }

            Mock -CommandName 'Get-Command'
            Mock -CommandName 'Test-Path' -MockWith {
                return $true
            }
        }

        Context 'When installing a module using NuGet' {
            BeforeAll {
                <#
                    Mocking the nuget.exe but we are actually mocking the function
                    above. Using powershell.exe to set $LASTEXITCODE to 0.
                #>

                Mock -CommandName 'nuget.exe' -MockWith {
                    powershell.exe -Command 'exit 0'
                }
            }

            It 'Should install module without throwing' {
                $installModuleFromPowerShellGalleryParameters = @{
                    ModuleName      = 'DummyTestModule'
                    DestinationPath = $TestDrive
                }

                { Install-ModuleFromPowerShellGallery @installModuleFromPowerShellGalleryParameters } | Should -Not -Throw

                Assert-MockCalled -CommandName 'nuget.exe' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Get-Command' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When failing to install a module using NuGet' {
            BeforeAll {
                <#
                    Mocking the nuget.exe but we are actually mocking the function
                    above. Using powershell.exe to set $LASTEXITCODE to 1.
                #>

                Mock -CommandName 'nuget.exe' -MockWith {
                    powershell.exe -Command 'exit 1'
                }
            }

            It 'Should throw the correct error' {
                $mockModuleName = 'DummyTestModule'

                $installModuleFromPowerShellGalleryParameters = @{
                    ModuleName      = $mockModuleName
                    DestinationPath = $TestDrive
                }

                $errorMessage = 'Installation of module {0} using Nuget failed with exit code {1}.' -f $mockModuleName, '1'
                { Install-ModuleFromPowerShellGallery @installModuleFromPowerShellGalleryParameters } | Should -Throw $errorMessage
            }
        }
    }

    Describe 'TestHelper\New-Nuspec' {
        Context 'When resetting the DSC LCM' {
            $mockDestinationPath = Join-Path -Path $TestDrive -ChildPath 'Package'

            BeforeAll {
                $mockPackageName = 'TestPackage'
                $mockVersion = '2.0.0.0'
                $mockAuthor = 'AutomaticUnitTest'
                $mockOwners = 'Microsoft'
                $mockDestinationPath = $mockDestinationPath
                $mockLicenseUrl = 'https://testlicense'
                $mockProjectUrl = 'https://testproject'
                $mockIconUrl = 'https://testicon'
                $mockPackageDescription = 'Test description'
                $mockReleaseNotes = 'Test release notes'
                $mockTags = 'DSCResource Tag'
            }

            It 'Should reset the LCM without throwing' {
                $newNuspecParameters = @{
                    PackageName        = $mockPackageName
                    Version            = $mockVersion
                    Author             = $mockAuthor
                    Owners             = $mockOwners
                    DestinationPath    = $mockDestinationPath
                    LicenseUrl         = $mockLicenseUrl
                    ProjectUrl         = $mockProjectUrl
                    IconUrl            = $mockIconUrl
                    PackageDescription = $mockPackageDescription
                    ReleaseNotes       = $mockReleaseNotes
                    Tags               = $mockTags
                }

                { New-Nuspec @newNuspecParameters } | Should -Not -Throw

                $testFilePath = (Join-Path -Path $mockDestinationPath -ChildPath ('{0}.nuspec' -f $mockPackageName))
                $testFilePath | Should -FileContentMatchExactly ('<id>{0}</id>' -f $mockPackageName)
                $testFilePath | Should -FileContentMatchExactly ('<version>{0}</version>' -f $mockVersion)
                $testFilePath | Should -FileContentMatchExactly ('<authors>{0}</authors>' -f $mockAuthor)
                $testFilePath | Should -FileContentMatchExactly ('<owners>{0}</owners>' -f $mockOwners)
                $testFilePath | Should -FileContentMatchExactly ('<licenseUrl>{0}</licenseUrl>' -f $mockLicenseUrl)
                $testFilePath | Should -FileContentMatchExactly ('<projectUrl>{0}</projectUrl>' -f $mockProjectUrl)
                $testFilePath | Should -FileContentMatchExactly ('<iconUrl>{0}</iconUrl>' -f $mockIconUrl)
                $testFilePath | Should -FileContentMatchExactly ('<description>{0}</description>' -f $mockPackageDescription)
                $testFilePath | Should -FileContentMatchExactly ('<releaseNotes>{0}</releaseNotes>' -f $mockReleaseNotes)
                $testFilePath | Should -FileContentMatchExactly ('<tags>{0}</tags>' -f $mockTags)
                $testFilePath | Should -FileContentMatchExactly '<requireLicenseAcceptance>true</requireLicenseAcceptance>'
                $testFilePath | Should -FileContentMatchExactly ('<copyright>Copyright {0}</copyright>' -f (Get-Date).Year)
            }
        }
    }

    Describe 'TestHelper\Get-LocalizedData' {
        $mockTestPath = {
            return $mockTestPathReturnValue
        }

        $mockImportLocalizedData = {
            $BaseDirectory | Should -Be $mockExpectedLanguagePath
        }

        BeforeEach {
            Mock -CommandName 'Test-Path' -MockWith $mockTestPath -Verifiable
            Mock -CommandName 'Import-LocalizedData' -MockWith $mockImportLocalizedData -Verifiable
        }

        Context 'When loading localized data for Swedish' {
            $mockExpectedLanguagePath = 'sv-SE'
            $mockTestPathReturnValue = $true

            It 'Should call Import-LocalizedData with sv-SE language' {
                Mock -CommandName 'Join-Path' -MockWith {
                    return 'sv-SE'
                } -Verifiable

                { Get-LocalizedData -ModuleName 'DummyResource' -ModuleRoot $TestDrive } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Join-Path' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Test-Path' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Import-LocalizedData' -Exactly -Times 1 -Scope It
            }

            $mockExpectedLanguagePath = 'en-US'
            $mockTestPathReturnValue = $false

            It 'Should call Import-LocalizedData and fallback to en-US if sv-SE language does not exist' {
                Mock -CommandName 'Join-Path' -MockWith {
                    return $ChildPath
                } -Verifiable

                { Get-LocalizedData -ModuleName 'DummyResource' -ModuleRoot $TestDrive } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Join-Path' -Exactly -Times 2 -Scope It
                Assert-MockCalled -CommandName 'Test-Path' -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName 'Import-LocalizedData' -Exactly -Times 1 -Scope It
            }
        }

        Context 'When loading localized data for English' {
            Mock -CommandName 'Join-Path' -MockWith {
                return 'en-US'
            } -Verifiable

            $mockExpectedLanguagePath = 'en-US'
            $mockTestPathReturnValue = $true

            It 'Should call Import-LocalizedData with en-US language' {
                { Get-LocalizedData -ModuleName 'DummyResource' -ModuleRoot $TestDrive } | Should -Not -Throw
            }
        }

        Assert-VerifiableMock
    }

    Describe 'TestHelper\Write-Info' {
        Context 'When writing a message to console' {
            BeforeAll {
                $testMessageText = 'UnitTestTestMessage'

                Mock -CommandName 'Write-Host' -ParameterFilter {
                    $Message -match $testMessageText
                }
            }

            It 'Should call the correct Cmdlets and not throw' {
                { Write-Info -Message $testMessageText -ForegroundColor 'Red' } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Write-Host' -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\Get-PublishFileName' {
        Context 'When filename starts with a numeric value followed by a slash (-)' {
            BeforeAll {
                $mockName = 'MyFile'
                $mockPath = Join-Path -Path $TestDrive -ChildPath "99-$mockName.ps1"
                New-Item -Path $mockPath -ItemType File -Force
            }

            It 'Should return the correct name' {
                $getPublishFileNameResult = Get-PublishFileName -Path $mockPath
                $getPublishFileNameResult | Should -Be $mockName
            }
        }

        Context 'When filename does not start with a numeric value followed by a slash (-)' {
            BeforeAll {
                $mockName = 'MyFile'
                $mockPath = Join-Path -Path $TestDrive -ChildPath "$mockName.ps1"
                New-Item -Path $mockPath -ItemType File -Force
            }

            It 'Should return the correct name' {
                $getPublishFileNameResult = Get-PublishFileName -Path $mockPath
                $getPublishFileNameResult | Should -Be $mockName
            }
        }
    }

    Describe 'TestHelper\Copy-ResourceModuleToPSModulePath' {
        Context 'When a module is copied' {
            BeforeAll {
                Mock -CommandName New-Item
                Mock -CommandName Copy-Item
            }

            It 'Should call the correct mocks' {
                { Copy-ResourceModuleToPSModulePath -ResourceModuleName 'a' -ModuleRootPath $TestDrive } | Should -Not -Throw

                Assert-MockCalled -CommandName New-Item -Exactly -Times 1 -Scope It
                Assert-MockCalled -CommandName Copy-Item -Exactly -Times 1 -Scope It
            }
        }
    }

    Describe 'TestHelper\New-DscSelfSignedCertificate' {
        BeforeAll {
            $mockCertificateDNSNames = @('TestDscEncryptionCert')
            $mockCertificateKeyUsage = @('KeyEncipherment', 'DataEncipherment')
            $mockCertificateEKU = @('Document Encryption')
            $mockCertificateSubject = 'TestDscEncryptionCert'
            $mockCertificateFriendlyName = 'TestDscEncryptionCert'
            $mockCertificateThumbprint = '1111111111111111111111111111111111111111'

            $validCertificate = New-Object -TypeName PSObject -Property @{
                Thumbprint        = $mockCertificateThumbprint
                Subject           = "CN=$mockCertificateSubject"
                Issuer            = "CN=$mockCertificateSubject"
                FriendlyName      = $mockCertificateFriendlyName
                DnsNameList       = @(
                    @{ Unicode = $mockCertificateDNSNames[0] }
                )
                Extensions        = @(
                    @{ EnhancedKeyUsages = ($mockCertificateKeyUsage -join ', ') }
                )
                EnhancedKeyUsages = @(
                    @{ FriendlyName = $mockCertificateEKU[0] }
                    @{ FriendlyName = $mockCertificateEKU[1] }
                )
                NotBefore         = (Get-Date).AddDays(-30) # Issued on
                NotAfter          = (Get-Date).AddDays(31) # Expires after
            }

            <#
                This stub is needed because the real Export-Certificate's $cert
                parameter requires an actual [X509Certificate2] object.
            #>

            function Export-Certificate
            {
            }
        }

        Context 'When creating a self-signed certificate for Windows Server 2012 R2' {
            BeforeAll {
                <#
                    Stub to have something to mock on since we can't wait for
                    the Expand-Archive to create the stub that is dot-sourced
                    on runtime.
                #>

                function New-SelfSignedCertificateEx
                {
                }

                Mock -CommandName Get-ChildItem
                Mock -CommandName Get-Command
                Mock -CommandName Install-Module
                Mock -CommandName Import-Module
                Mock -CommandName Export-Certificate
                Mock -CommandName Set-EnvironmentVariable
                Mock -CommandName New-SelfSignedCertificateEx -MockWith {
                    return $validCertificate
                }
            }

            It 'Should return a certificate and call the correct mocks' {
                $result = New-DscSelfSignedCertificate
                $result.Thumbprint | Should -Be $mockCertificateThumbprint
                $result.Subject | Should -Be "CN=$mockCertificateSubject"

                Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1
                Assert-MockCalled -CommandName Get-Command -Exactly -Times 1
                Assert-MockCalled -CommandName Install-Module -Exactly -Times 1
                Assert-MockCalled -CommandName Import-Module -Exactly -Times 1
                Assert-MockCalled -CommandName New-SelfSignedCertificateEx -Exactly -Times 1

                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscPublicCertificatePath' `
                        -and $Value -eq (Join-Path -Path $env:temp -ChildPath 'DscPublicKey.cer')
                } -Exactly -Times 1

                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscCertificateThumbprint' `
                        -and $Value -eq $mockCertificateThumbprint
                } -Exactly -Times 1
            }
        }

        Context 'When creating a self-signed certificate for Windows Server 2016' {
            BeforeAll {
                <#
                    Stub is needed if tests is run on operating system older
                    than Windows 10 and Windows Server 2016.
                #>

                function New-SelfSignedCertificate
                {
                }

                Mock -CommandName Get-ChildItem
                Mock -CommandName Get-Command -MockWith {
                    return @{
                        Parameters = @{
                            Keys = @('Type')
                        }
                    }
                }

                Mock -CommandName Export-Certificate
                Mock -CommandName Set-EnvironmentVariable
                Mock -CommandName New-SelfSignedCertificate -MockWith {
                    return $validCertificate
                }
            }

            It 'Should return a certificate and call the correct cmdlets' {
                $result = New-DscSelfSignedCertificate
                $result.Thumbprint | Should -Be $mockCertificateThumbprint
                $result.Subject | Should -Be "CN=$mockCertificateSubject"

                Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1
                Assert-MockCalled -CommandName Get-Command -Exactly -Times 1
                Assert-MockCalled -CommandName New-SelfSignedCertificate -Exactly -Times 1
                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscPublicCertificatePath' `
                        -and $Value -eq (Join-Path -Path $env:temp -ChildPath 'DscPublicKey.cer')
                } -Exactly -Times 1

                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscCertificateThumbprint' `
                        -and $Value -eq $mockCertificateThumbprint
                } -Exactly -Times 1
            }
        }

        Context 'When a self-signed certificate already exists' {
            BeforeAll {
                Mock -CommandName Get-ChildItem -MockWith {
                    return $validCertificate
                }

                <#
                    Stub to have something to mock on since we can't wait for
                    the Expand-Archive to create the stub that is dot-sourced
                    on runtime.
                #>

                function New-SelfSignedCertificateEx
                {
                }

                Mock -CommandName New-SelfSignedCertificateEx
                Mock -CommandName New-SelfSignedCertificate
                Mock -CommandName Set-EnvironmentVariable
                Mock -CommandName Install-Module
                Mock -CommandName Import-Module
                Mock -CommandName Export-Certificate
            }

            It 'Should return a certificate and call the correct cmdlets' {
                $result = New-DscSelfSignedCertificate
                $result.Thumbprint | Should -Be $mockCertificateThumbprint
                $result.Subject | Should -Be "CN=$mockCertificateSubject"

                Assert-MockCalled -CommandName New-SelfSignedCertificate -Exactly -Times 0
                Assert-MockCalled -CommandName New-SelfSignedCertificateEx -Exactly -Times 0
                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscPublicCertificatePath' `
                        -and $Value -eq (Join-Path -Path $env:temp -ChildPath 'DscPublicKey.cer')
                } -Exactly -Times 1

                Assert-MockCalled -CommandName Set-EnvironmentVariable -ParameterFilter {
                    $Name -eq 'DscCertificateThumbprint' `
                        -and $Value -eq $mockCertificateThumbprint
                } -Exactly -Times 1
                Assert-MockCalled -CommandName Install-Module -Exactly -Times 0
                Assert-MockCalled -CommandName Import-Module -Exactly -Times 0
                Assert-MockCalled -CommandName Export-Certificate -Exactly -Times 1
            }
        }
    }

    Describe 'TestHelper\Initialize-LocalConfigurationManager' {
        BeforeAll {
            Mock -CommandName New-Item
            Mock -CommandName Remove-Item
            Mock -CommandName Invoke-Command
            Mock -CommandName Set-DscLocalConfigurationManager

            # Stub of the generated configuration so it can be mocked.
            function LocalConfigurationManagerConfiguration
            {
            }

            Mock -CommandName LocalConfigurationManagerConfiguration
        }

        Context 'When Local Configuration Manager should have consistency disabled' {
            BeforeAll {
                $expectedConfigurationMetadata = '
                    Configuration LocalConfigurationManagerConfiguration
                    {
                        LocalConfigurationManager
                        {
                            ConfigurationMode = ''ApplyOnly''
                        }
                    }
                '


                # Truncating everything to one line so easier to compare.
                $expectedConfigurationMetadataOneLine = $expectedConfigurationMetadata -replace '[ \r\n]'
            }

            It 'Should call Invoke-Command with the correct configuration' {
                { Initialize-LocalConfigurationManager -DisableConsistency } | Should -Not -Throw

                Assert-MockCalled -CommandName Invoke-Command -ParameterFilter {
                    ($ScriptBlock.ToString() -replace '[ \r\n]') -eq $expectedConfigurationMetadataOneLine
                } -Exactly -Times 1
                Assert-MockCalled -CommandName Set-DscLocalConfigurationManager -Exactly -Times 1
            }
        }

        Context 'When Local Configuration Manager should have consistency disabled' {
            BeforeAll {
                $env:DscCertificateThumbprint = '1111111111111111111111111111111111111111'

                $expectedConfigurationMetadata = "
                    Configuration LocalConfigurationManagerConfiguration
                    {
                        LocalConfigurationManager
                        {
                            CertificateId = '$($env:DscCertificateThumbprint)'
                        }
                    }
                "


                # Truncating everything to one line so easier to compare.
                $expectedConfigurationMetadataOneLine = $expectedConfigurationMetadata -replace '[ \r\n]'
            }

            AfterAll {
                Remove-Item -Path 'env:DscCertificateThumbprint' -Force
            }

            It 'Should call Invoke-Command with the correct configuration' {
                { Initialize-LocalConfigurationManager -Encrypt } | Should -Not -Throw

                Assert-MockCalled -CommandName Invoke-Command -ParameterFilter {
                    ($ScriptBlock.ToString() -replace '[ \r\n]') -eq $expectedConfigurationMetadataOneLine
                } -Exactly -Times 1
                Assert-MockCalled -CommandName Set-DscLocalConfigurationManager -Exactly -Times 1
            }
        }
    }

    Describe 'TestHelper\Write-PsScriptAnalyzerWarning' {
        Context 'When writing a PsScriptAnalyzer warning' {
            BeforeAll {
                $testPssaRuleOutput = [PSCustomObject]@{
                    Line   = '51'
                    Message  = 'Test Message'
                    RuleName = 'TestRule'
                    ScriptName = 'Pester.ps1'
                }
                $testRuleType = 'Test'
                
                Mock -CommandName 'Write-Warning'
            }

            It 'Should call the correct Cmdlets and not throw' {
                { Write-PsScriptAnalyzerWarning -PssaRuleOutput $testPssaRuleOutput -RuleType $testRuleType } | Should -Not -Throw

                Assert-MockCalled -CommandName 'Write-Warning' -ParameterFilter {
                    $message -eq "The following PSScriptAnalyzer rule '$($testPssaRuleOutput.RuleName)' errors need to be fixed:"
                } -Exactly -Times 1
                Assert-MockCalled -CommandName 'Write-Warning' -ParameterFilter {
                    $message -eq "$($testPssaRuleOutput.ScriptName) (Line $($testPssaRuleOutput.Line)): $($testPssaRuleOutput.Message)"
                } -Exactly -Times 1
                Assert-MockCalled -CommandName 'Write-Warning' -ParameterFilter {
                    $message -eq "$testRuleType PSSA rule(s) did not pass."
                } -Exactly -Times 1
            }
        }
    }
}