Tests/QA/Localization.common.Tests.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-ParameterBlockParameterAttribute', '', Scope='Function', Target='*')] param ( $ModuleName, $ModuleBase, $ModuleManifest, $ProjectPath, $SourcePath, $SourceManifest, $Tag, $ExcludeTag, $ExcludeModuleFile, $ExcludeSourceFile ) Describe 'Common Tests - Validate Localization' -Tag 'Common Tests - Validate Localization' { $allFolders = Get-ChildItem -Path (Join-Path -Path $ModuleBase -ChildPath 'DscResources') -Directory $allFolders += Get-ChildItem -Path (Join-Path -Path $ModuleBase -ChildPath 'Modules') -Directory $allFolders = $allFolders | Sort-Object -Property Name Context 'When a resource or module should have localization files' { BeforeAll { $foldersToTest = @() foreach ($folder in $allFolders) { $foldersToTest += @{ Folder = $folder.Name Path = $folder.FullName } } } It 'Should have en-US localization folder for the resource/module <Folder>' -TestCases $foldersToTest { param ( [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $Path ) $localizationFolderPath = Join-Path -Path $Path -ChildPath 'en-US' Test-Path -Path $localizationFolderPath | Should -BeTrue -Because 'the en-US folder must exist' } It 'Should have en-US localization folder with the correct casing for the resource/module <Folder>' -TestCases $foldersToTest { param ( [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $Path ) <# This will return both 'en-us' and 'en-US' folders so we can evaluate casing. #> $localizationFolderOnDisk = Get-ChildItem -Path $Path -Directory -Filter 'en-US' $localizationFolderOnDisk.Name | Should -MatchExactly 'en-US' -Because 'the en-US folder must have the correct casing' } It 'Should have en-US localization string resource file for the resource/module <Folder>' -TestCases $foldersToTest { param ( [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $Path ) $localizationResourceFilePath = Join-Path -Path (Join-Path -Path $Path -ChildPath 'en-US') -ChildPath "$Folder.strings.psd1" Test-Path -Path $localizationResourceFilePath | Should -BeTrue -Because 'there must exist a string resource file in the localization folder en-US' } foreach ($testCase in $foldersToTest) { $skipTest_LocalizedKeys = $false $skipTest_UsedLocalizedKeys = $false $testCases_LocalizedKeys = @() $testCases_UsedLocalizedKeys = @() $sourceLocalizationFolderPath = Join-Path -Path $testCase.Path -ChildPath 'en-US' $localizationResourceFile = '{0}.strings.psd1' -f $testCase.Folder # Skip files that do not exist yet (they were caught in a previous test above) if (-not (Test-Path -Path (Join-Path -Path $sourceLocalizationFolderPath -ChildPath $localizationResourceFile))) { Write-Warning -Message ('Missing the localized string resource file ''{0}''' -f $testCase.Path) continue } Import-LocalizedData ` -BindingVariable 'englishLocalizedStrings' ` -FileName $localizationResourceFile ` -BaseDirectory $sourceLocalizationFolderPath foreach ($localizedKey in $englishLocalizedStrings.Keys) { $testCases_LocalizedKeys += @{ LocalizedKey = $localizedKey } } $modulePath = Join-Path -Path $testCase.Path -ChildPath "$($testCase.Folder).psm1" $parseErrors = $null $definitionAst = [System.Management.Automation.Language.Parser]::ParseFile($modulePath, [ref] $null, [ref] $parseErrors) if ($parseErrors) { throw $parseErrors } $astFilter = { $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst] ` -and $args[0].Parent -is [System.Management.Automation.Language.MemberExpressionAst] ` -and $args[0].Parent.Expression -is [System.Management.Automation.Language.VariableExpressionAst] ` -and $args[0].Parent.Expression.VariablePath.UserPath -eq 'script:localizedData' } $localizationStringConstantsAst = $definitionAst.FindAll($astFilter, $true) if ($localizationStringConstantsAst) { $usedLocalizationKeys = $localizationStringConstantsAst.Value | Sort-Object -Unique foreach ($localizedKey in $usedLocalizationKeys) { $testCases_UsedLocalizedKeys += @{ LocalizedKey = $localizedKey } } } Context ('When validating resource/module {0}' -f $testCase.Folder) { # If there are no test cases built, skip this test. $skipTest_LocalizedKeys = -not $testCases_LocalizedKeys It 'Should use the localized string key <LocalizedKey> from the localization resource file' -TestCases $testCases_LocalizedKeys -Skip:$skipTest_LocalizedKeys { param ( [Parameter()] [System.String] $LocalizedKey ) $usedLocalizationKeys | Should -Contain $LocalizedKey -Because 'the key exists in the localized string resource file so it should also exist in the code' } # If there are no test cases built, skip this test. $skipTest_UsedLocalizedKeys = -not $testCases_UsedLocalizedKeys It 'Should not be missing the localized string key <LocalizedKey> from the localization resource file' -TestCases $testCases_UsedLocalizedKeys -Skip:$skipTest_UsedLocalizedKeys { param ( [Parameter()] [System.String] $LocalizedKey ) $englishLocalizedStrings.Keys | Should -Contain $LocalizedKey -Because 'the key is used in the resource/module script file so it should also exist in the localized string resource files' } } } } Context 'When a resource or module is localized to other languages' { BeforeAll { $otherLanguagesToTest = @() foreach ($folder in $allFolders) { <# Get all localization folders except the en-US. We want all regardless of casing. #> $localizationFolders = Get-ChildItem -Path $folder.FullName -Directory -Filter '*-*' | Where-Object -FilterScript { $_.Name -ne 'en-US' } foreach ($localizationFolder in $localizationFolders) { $otherLanguagesToTest += @{ Folder = $folder.Name Path = $folder.FullName LocalizationFolder = $localizationFolder.Name } } } } # Only run these tests if there are test cases to be tested. $skipTests = -not $otherLanguagesToTest It 'Should have a localization string resource file for the resource/module <Folder> and localization folder <LocalizationFolder>' -TestCases $otherLanguagesToTest -Skip:$skipTests { param ( [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $Path, [Parameter()] [System.String] $LocalizationFolder ) $localizationResourceFilePath = Join-Path -Path (Join-Path -Path $Path -ChildPath $LocalizationFolder) -ChildPath "$Folder.strings.psd1" Test-Path -Path $localizationResourceFilePath | Should -BeTrue -Because ('there must exist a string resource file in the localization folder {0}' -f $LocalizationFolder) } It 'Should have a localization folder with the correct casing for the resource/module <Folder> and localization folder <LocalizationFolder>' -TestCases $otherLanguagesToTest -Skip:$skipTests { param ( [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $Path, [Parameter()] [System.String] $LocalizationFolder ) $localizationFolderOnDisk = Get-ChildItem -Path $Path -Directory -Filter $LocalizationFolder $localizationFolderOnDisk.Name | Should -MatchExactly '[a-z]{2}-[A-Z]{2}' -Because 'the localization folder must have the correct casing' } foreach ($testCase in $otherLanguagesToTest) { $testCases_CompareAgainstEnglishLocalizedKeys = @() $testCases_MissingEnglishLocalizedKeys = @() $sourceLocalizationFolderPath = Join-Path -Path $testCase.Path -ChildPath 'en-US' Import-LocalizedData ` -BindingVariable 'englishLocalizedStrings' ` -FileName "$($testCase.Folder).strings.psd1" ` -BaseDirectory $sourceLocalizationFolderPath $localizationFolderPath = Join-Path -Path $testCase.Path -ChildPath $testCase.LocalizationFolder Import-LocalizedData ` -BindingVariable 'localizedStrings' ` -FileName "$($testCase.Folder).strings.psd1" ` -BaseDirectory $localizationFolderPath foreach ($localizedKey in $englishLocalizedStrings.Keys) { $testCases_CompareAgainstEnglishLocalizedKeys += @{ LocalizationFolder = $testCase.LocalizationFolder Folder = $testCase.Folder LocalizedKey = $localizedKey } } foreach ($localizedKey in $localizedStrings.Keys) { $testCases_MissingEnglishLocalizedKeys += @{ LocalizationFolder = $testCase.LocalizationFolder Folder = $testCase.Folder LocalizedKey = $localizedKey } } Context ('When validating resource/module {0}' -f $testCase.Folder) { It "Should have the english localization string key <LocalizedKey> in the localization resource file '<LocalizationFolder>\<Folder>.strings.psd1' for the resource/module <Folder>" -TestCases $testCases_CompareAgainstEnglishLocalizedKeys { param ( [Parameter()] [System.String] $LocalizedKey, [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $LocalizationFolder ) $localizedStrings.Keys | Should -Contain $LocalizedKey -Because 'the key exists in the en-US localization resource file so the key should also exist in this language file' } -ErrorVariable itBlockError <# If the It-block did not pass the test, output the a text explaining how to resolve the issue. #> if ($itBlockError.Count -ne 0) { $message = @" If you cannot translate the english string in the localized file, then please just add the en-US localization string key together with the en-US text string. "@ Write-Host -BackgroundColor Yellow -ForegroundColor Black -Object $message Write-Host -ForegroundColor White -Object '' } It "Should not be missing the localization string key <LocalizedKey> from the english resource file for the resource/module <Folder>" -TestCases $testCases_MissingEnglishLocalizedKeys { param ( [Parameter()] [System.String] $LocalizedKey, [Parameter()] [System.String] $Folder, [Parameter()] [System.String] $LocalizationFolder ) $englishLocalizedStrings.Keys | Should -Contain $LocalizedKey -Because ('the key exists in the resource file for the location folder {0} so it should also exist in the en-US string resource file' -f $LocalizationFolder) } } } } } |