From 825cc8af8894b33d9fb7e5d9201bf3f35a69ff3b Mon Sep 17 00:00:00 2001 From: Daniel Hughes <2237515+dan-hughes@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:56:00 +0100 Subject: [PATCH] Migrate tests to Pester 5 (#27) --- CHANGELOG.md | 1 + RequiredModules.psd1 | 3 +- build.yaml | 31 +- source/Private/Get-LocalizedData.ps1 | 277 +++---- source/Public/Measure-CatchClause.ps1 | 8 +- source/Public/Measure-DoUntilStatement.ps1 | 8 +- source/Public/Measure-DoWhileStatement.ps1 | 8 +- source/Public/Measure-ForEachStatement.ps1 | 8 +- source/Public/Measure-ForStatement.ps1 | 8 +- source/Public/Measure-FunctionBlockBrace.ps1 | 8 +- source/Public/Measure-Hashtable.ps1 | 4 +- source/Public/Measure-IfStatement.ps1 | 8 +- source/Public/Measure-Keyword.ps1 | 5 +- source/Public/Measure-ParamBlock.ps1 | 6 +- ...e-ParameterBlockMandatoryNamedArgument.ps1 | 4 +- ...asure-ParameterBlockParameterAttribute.ps1 | 6 +- source/Public/Measure-SwitchStatement.ps1 | 8 +- source/Public/Measure-TryStatement.ps1 | 8 +- source/Public/Measure-TypeDefinition.ps1 | 14 +- source/Public/Measure-WhileStatement.ps1 | 8 +- ...=> DscResource.AnalyzerRules.strings.psd1} | 0 source/suffix.ps1 | 2 +- tests/QA/module.tests.ps1 | 300 +++++--- .../CommonTestHelper.psm1} | 30 + .../Unit/Private/Get-LocalizedData.Tests.ps1 | 95 ++- .../Private/Get-StatementBlockAsRow.Tests.ps1 | 81 +- .../Private/New-SuggestedCorrection.tests.ps1 | 87 ++- tests/Unit/Private/Test-IsInClass.Tests.ps1 | 130 ++-- ...mentEmptyParenthsesHasWhitespace.Tests.ps1 | 94 ++- ...ceIsFollowedByMoreThanOneNewLine.Tests.ps1 | 73 +- ...eningBraceIsNotFollowedByNewLine.Tests.ps1 | 83 ++- ...-StatementOpeningBraceOnSameLine.Tests.ps1 | 85 ++- ...ementOpeningParenthsesOnSameLine.Tests.ps1 | 76 +- .../Unit/Public/Get-TokensFromDefinition.ps1 | 29 - .../Unit/Public/Measure-CatchClause.Tests.ps1 | 324 +++++--- .../Public/Measure-DoUntilStatement.Tests.ps1 | 313 +++++--- .../Public/Measure-DoWhileStatement.Tests.ps1 | 249 ++++--- .../Public/Measure-ForEachStatement.Tests.ps1 | 282 ++++--- .../Public/Measure-ForStatement.Tests.ps1 | 275 ++++--- .../Measure-FunctionBlockBrace.Tests.ps1 | 432 ++++++----- tests/Unit/Public/Measure-Hashtable.Tests.ps1 | 394 ++++++---- .../Unit/Public/Measure-IfStatement.Tests.ps1 | 317 +++++--- tests/Unit/Public/Measure-Keyword.Tests.ps1 | 283 ++++--- .../Unit/Public/Measure-ParamBlock.Tests.ps1 | 307 +++++--- ...meterBlockMandatoryNamedArgument.Tests.ps1 | 697 ++++++++++-------- ...ParameterBlockParameterAttribute.Tests.ps1 | 593 +++++++++------ .../Public/Measure-SwitchStatement.Tests.ps1 | 338 +++++---- .../Public/Measure-TryStatement.Tests.ps1 | 324 +++++--- .../Public/Measure-TypeDefinition.Tests.ps1 | 422 +++++++---- .../Public/Measure-WhileStatement.Tests.ps1 | 289 +++++--- 50 files changed, 4735 insertions(+), 2700 deletions(-) rename source/en-US/{DscResource.AnalyzerRules.psd1 => DscResource.AnalyzerRules.strings.psd1} (100%) rename tests/{Unit/Public/Get-AstFromDefinition.ps1 => TestHelpers/CommonTestHelper.psm1} (60%) delete mode 100644 tests/Unit/Public/Get-TokensFromDefinition.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 56799c4..ec7164d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and [#9](https://github.com/dsccommunity/DscResource.AnalyzerRules/issues/9). ### Changed - Renamed default branch to `main`. Fixes [#12](https://github.com/dsccommunity/DscResource.AnalyzerRules/issues/22). +- Migrate to Pester 5 ## [0.2.0] - 2019-11-21 diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index f400c22..cc25bf8 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -9,10 +9,11 @@ InvokeBuild = 'latest' PSScriptAnalyzer = 'latest' - Pester = '4.10.1' + Pester = 'latest' Plaster = 'latest' ModuleBuilder = 'latest' ChangelogManagement = 'latest' Sampler = 'latest' 'Sampler.GitHubTasks' = 'latest' + 'DscResource.Test' = 'latest' } diff --git a/build.yaml b/build.yaml index 2b1f57c..dd737c2 100644 --- a/build.yaml +++ b/build.yaml @@ -15,6 +15,8 @@ ModuleBuildTasks: - '*.build.Sampler.ib.tasks' Sampler.GitHubTasks: - '*.ib.tasks' + DscResource.Test: + - 'Task.*' TaskHeader: | param($Path) @@ -47,6 +49,7 @@ BuildWorkflow: test: - Pester_Tests_Stop_On_Fail + - Convert_Pester_Coverage - Pester_if_Code_Coverage_Under_Threshold merge: @@ -60,24 +63,28 @@ BuildWorkflow: # Pester Configuration (Sampler) # #################################################### Pester: - OutputFormat: NUnitXML - # Will look at every *.ps1 & *.psm1 under ModulePath, excepts when $_.FullName -match (Join-Path $ProjectPath $ExcludeFromCodeCoverageItem) + Configuration: + Run: + Path: + - tests/QA + - tests/Unit + Output: + Verbosity: Detailed + StackTraceVisibility: Full + CIFormat: Auto + CodeCoverage: + CoveragePercentTarget: 80 + OutputEncoding: ascii + UseBreakpoints: false ExcludeFromCodeCoverage: - tasks - Template - # Default is to use the tests folder in the project folder or source folder (if present) - # can use it to prioritize: tests/QA, tests/Unit, tests/Integration - Script: - # - tests/QA/module.tests.ps1 - # - tests/QA - # - tests/Unit - # - tests/Integration ExcludeTag: - helpQuality - Tag: - CodeCoverageThreshold: 80 # Set to 0 to bypass - CodeCoverageOutputFileEncoding: ascii +#################################################### +# Code Coverage Configuration # +#################################################### CodeCoverage: CodeCoverageMergedOutputFile: JaCoCo_coverage.xml # the file that is created for the merged code coverage CodeCoverageFilePattern: Codecov*.xml # the pattern used to search all pipeline test job artifacts diff --git a/source/Private/Get-LocalizedData.ps1 b/source/Private/Get-LocalizedData.ps1 index 40ceea4..38de848 100644 --- a/source/Private/Get-LocalizedData.ps1 +++ b/source/Private/Get-LocalizedData.ps1 @@ -1,133 +1,134 @@ <# -.SYNOPSIS -Gets language-specific data into scripts and functions based on the UI culture -that is selected for the operating system. -Similar to Import-LocalizedData, with extra parameter 'DefaultUICulture'. - -.DESCRIPTION -The Get-LocalizedData cmdlet dynamically retrieves strings from a subdirectory -whose name matches the UI language set for the current user of the operating system. -It is designed to enable scripts to display user messages in the UI language selected -by the current user. - -Get-LocalizedData imports data from .psd1 files in language-specific subdirectories -of the script directory and saves them in a local variable that is specified in the -command. The cmdlet selects the subdirectory and file based on the value of the -$PSUICulture automatic variable. When you use the local variable in the script to -display a user message, the message appears in the user's UI language. - -You can use the parameters of G-LocalizedData to specify an alternate UI culture, -path, and file name, to add supported commands, and to suppress the error message that -appears if the .psd1 files are not found. - -The G-LocalizedData cmdlet supports the script internationalization -initiative that was introduced in Windows PowerShell 2.0. This initiative -aims to better serve users worldwide by making it easy for scripts to display -user messages in the UI language of the current user. For more information -about this and about the format of the .psd1 files, see about_Script_Internationalization. - -.PARAMETER BindingVariable -Specifies the variable into which the text strings are imported. Enter a variable -name without a dollar sign ($). - -In Windows PowerShell 2.0, this parameter is required. In Windows PowerShell 3.0, -this parameter is optional. If you omit this parameter, Import-LocalizedData -returns a hash table of the text strings. The hash table is passed down the pipeline -or displayed at the command line. - -When using Import-LocalizedData to replace default text strings specified in the -DATA section of a script, assign the DATA section to a variable and enter the name -of the DATA section variable in the value of the BindingVariable parameter. Then, -when Import-LocalizedData saves the imported content in the BindingVariable, the -imported data will replace the default text strings. If you are not specifying -default text strings, you can select any variable name. -.PARAMETER UICulture -Specifies an alternate UI culture. The default is the value of the $PsUICulture -automatic variable. Enter a UI culture in - format, such as -en-US, de-DE, or ar-SA. - -The value of the UICulture parameter determines the language-specific subdirectory -(within the base directory) from which Import-LocalizedData gets the .psd1 file -for the script. - -The cmdlet searches for a subdirectory with the same name as the value of the -UICulture parameter or the $PsUICulture automatic variable, such as de-DE or -ar-SA. If it cannot find the directory, or the directory does not contain a .psd1 -file for the script, it searches for a subdirectory with the name of the language -code, such as de or ar. If it cannot find the subdirectory or .psd1 file, the -command fails and the data is displayed in the default language specified in the -script. - -.PARAMETER BaseDirectory -Specifies the base directory where the .psd1 files are located. The default is -the directory where the script is located. Import-LocalizedData searches for -the .psd1 file for the script in a language-specific subdirectory of the base -directory. - -.PARAMETER FileName -Specifies the name of the data file (.psd1) to be imported. Enter a file name. -You can specify a file name that does not include its .psd1 file name extension, -or you can specify the file name including the .psd1 file name extension. - -The FileName parameter is required when Import-LocalizedData is not used in a -script. Otherwise, the parameter is optional and the default value is the base -name of the script. You can use this parameter to direct Import-LocalizedData -to search for a different .psd1 file. - -For example, if the FileName is omitted and the script name is FindFiles.ps1, -Import-LocalizedData searches for the FindFiles.psd1 data file. - -.PARAMETER SupportedCommand -Specifies cmdlets and functions that generate only data. - -Use this parameter to include cmdlets and functions that you have written or -tested. For more information, see about_Script_Internationalization. - -.PARAMETER DefaultUICulture -Specifies which UICulture to default to if current UI culture or its parents -culture don't have matching data file. - -For example, if you have a data file in 'en-US' but not in 'en' or 'en-GB' and -your current culture is 'en-GB', you can default back to 'en-US'. - -.NOTES -Before using Import-LocalizedData, localize your user messages. Format the messages -for each locale (UI culture) in a hash table of key/value pairs, and save the -hash table in a file with the same name as the script and a .psd1 file name extension. -Create a directory under the script directory for each supported UI culture, and -then save the .psd1 file for each UI culture in the directory with the UI -culture name. - -For example, localize your user messages for the de-DE locale and format them in -a hash table. Save the hash table in a .psd1 file. Then create a de-DE -subdirectory under the script directory, and save the de-DE .psd1 -file in the de-DE subdirectory. Repeat this method for each locale that you support. - -Import-LocalizedData performs a structured search for the localized user -messages for a script. - -Import-LocalizedData begins the search in the directory where the script file -is located (or the value of the BaseDirectory parameter). It then searches within -the base directory for a subdirectory with the same name as the value of the -$PsUICulture variable (or the value of the UICulture parameter), such as de-DE or -ar-SA. Then, it searches in that subdirectory for a .psd1 file with the same name -as the script (or the value of the FileName parameter). - -If Import-LocalizedData cannot find a subdirectory with the name of the UI culture, -or the subdirectory does not contain a .psd1 file for the script, it searches for -a .psd1 file for the script in a subdirectory with the name of the language code, -such as de or ar. If it cannot find the subdirectory or .psd1 file, the command -fails, the data is displayed in the default language in the script, and an error -message is displayed explaining that the data could not be imported. To suppress -the message and fail gracefully, use the ErrorAction common parameter with a value -of SilentlyContinue. - -If Import-LocalizedData finds the subdirectory and the .psd1 file, it imports the -hash table of user messages into the value of the BindingVariable parameter in the -command. Then, when you display a message from the hash table in the variable, the -localized message is displayed. - -For more information, see about_Script_Internationalization. + .SYNOPSIS + Gets language-specific data into scripts and functions based on the UI culture + that is selected for the operating system. + Similar to Import-LocalizedData, with extra parameter 'DefaultUICulture'. + + .DESCRIPTION + The Get-LocalizedData cmdlet dynamically retrieves strings from a subdirectory + whose name matches the UI language set for the current user of the operating system. + It is designed to enable scripts to display user messages in the UI language selected + by the current user. + + Get-LocalizedData imports data from .psd1 files in language-specific subdirectories + of the script directory and saves them in a local variable that is specified in the + command. The cmdlet selects the subdirectory and file based on the value of the + $PSUICulture automatic variable. When you use the local variable in the script to + display a user message, the message appears in the user's UI language. + + You can use the parameters of G-LocalizedData to specify an alternate UI culture, + path, and file name, to add supported commands, and to suppress the error message that + appears if the .psd1 files are not found. + + The G-LocalizedData cmdlet supports the script internationalization + initiative that was introduced in Windows PowerShell 2.0. This initiative + aims to better serve users worldwide by making it easy for scripts to display + user messages in the UI language of the current user. For more information + about this and about the format of the .psd1 files, see about_Script_Internationalization. + + .PARAMETER BindingVariable + Specifies the variable into which the text strings are imported. Enter a variable + name without a dollar sign ($). + + In Windows PowerShell 2.0, this parameter is required. In Windows PowerShell 3.0, + this parameter is optional. If you omit this parameter, Import-LocalizedData + returns a hash table of the text strings. The hash table is passed down the pipeline + or displayed at the command line. + + When using Import-LocalizedData to replace default text strings specified in the + DATA section of a script, assign the DATA section to a variable and enter the name + of the DATA section variable in the value of the BindingVariable parameter. Then, + when Import-LocalizedData saves the imported content in the BindingVariable, the + imported data will replace the default text strings. If you are not specifying + default text strings, you can select any variable name. + + .PARAMETER UICulture + Specifies an alternate UI culture. The default is the value of the $PsUICulture + automatic variable. Enter a UI culture in - format, such as + en-US, de-DE, or ar-SA. + + The value of the UICulture parameter determines the language-specific subdirectory + (within the base directory) from which Import-LocalizedData gets the .psd1 file + for the script. + + The cmdlet searches for a subdirectory with the same name as the value of the + UICulture parameter or the $PsUICulture automatic variable, such as de-DE or + ar-SA. If it cannot find the directory, or the directory does not contain a .psd1 + file for the script, it searches for a subdirectory with the name of the language + code, such as de or ar. If it cannot find the subdirectory or .psd1 file, the + command fails and the data is displayed in the default language specified in the + script. + + .PARAMETER BaseDirectory + Specifies the base directory where the .psd1 files are located. The default is + the directory where the script is located. Import-LocalizedData searches for + the .psd1 file for the script in a language-specific subdirectory of the base + directory. + + .PARAMETER FileName + Specifies the name of the data file (.psd1) to be imported. Enter a file name. + You can specify a file name that does not include its .psd1 file name extension, + or you can specify the file name including the .psd1 file name extension. + + The FileName parameter is required when Import-LocalizedData is not used in a + script. Otherwise, the parameter is optional and the default value is the base + name of the script. You can use this parameter to direct Import-LocalizedData + to search for a different .psd1 file. + + For example, if the FileName is omitted and the script name is FindFiles.ps1, + Import-LocalizedData searches for the FindFiles.psd1 data file. + + .PARAMETER SupportedCommand + Specifies cmdlets and functions that generate only data. + + Use this parameter to include cmdlets and functions that you have written or + tested. For more information, see about_Script_Internationalization. + + .PARAMETER DefaultUICulture + Specifies which UICulture to default to if current UI culture or its parents + culture don't have matching data file. + + For example, if you have a data file in 'en-US' but not in 'en' or 'en-GB' and + your current culture is 'en-GB', you can default back to 'en-US'. + + .NOTES + Before using Import-LocalizedData, localize your user messages. Format the messages + for each locale (UI culture) in a hash table of key/value pairs, and save the + hash table in a file with the same name as the script and a .psd1 file name extension. + Create a directory under the script directory for each supported UI culture, and + then save the .psd1 file for each UI culture in the directory with the UI + culture name. + + For example, localize your user messages for the de-DE locale and format them in + a hash table. Save the hash table in a .psd1 file. Then create a de-DE + subdirectory under the script directory, and save the de-DE .psd1 + file in the de-DE subdirectory. Repeat this method for each locale that you support. + + Import-LocalizedData performs a structured search for the localized user + messages for a script. + + Import-LocalizedData begins the search in the directory where the script file + is located (or the value of the BaseDirectory parameter). It then searches within + the base directory for a subdirectory with the same name as the value of the + $PsUICulture variable (or the value of the UICulture parameter), such as de-DE or + ar-SA. Then, it searches in that subdirectory for a .psd1 file with the same name + as the script (or the value of the FileName parameter). + + If Import-LocalizedData cannot find a subdirectory with the name of the UI culture, + or the subdirectory does not contain a .psd1 file for the script, it searches for + a .psd1 file for the script in a subdirectory with the name of the language code, + such as de or ar. If it cannot find the subdirectory or .psd1 file, the command + fails, the data is displayed in the default language in the script, and an error + message is displayed explaining that the data could not be imported. To suppress + the message and fail gracefully, use the ErrorAction common parameter with a value + of SilentlyContinue. + + If Import-LocalizedData finds the subdirectory and the .psd1 file, it imports the + hash table of user messages into the value of the BindingVariable parameter in the + command. Then, when you display a message from the hash table in the variable, the + localized message is displayed. + + For more information, see about_Script_Internationalization. #> function Get-LocalizedData { @@ -137,27 +138,27 @@ function Get-LocalizedData [Alias('Variable')] [ValidateNotNullOrEmpty()] [string] - ${BindingVariable}, + $BindingVariable, [Parameter(Position = 1, ParameterSetName = 'TargetedUICulture')] [string] - ${UICulture}, + $UICulture, [Parameter()] [string] - ${BaseDirectory}, + $BaseDirectory, [Parameter()] [string] - ${FileName}, + $FileName, [Parameter()] [string[]] - ${SupportedCommand}, + $SupportedCommand, [Parameter(Position = 1, ParameterSetName = 'DefaultUICulture')] [string] - ${DefaultUICulture} + $DefaultUICulture ) begin @@ -174,8 +175,8 @@ function Get-LocalizedData { $file = [io.FileInfo]$myInvocation.MyCommand.Module.Path } - $FileName = $file.BaseName - $PSBoundParameters.add('FileName', $file.Name) + $FileName = $file.BaseName + '.strings' + $PSBoundParameters.add('FileName', ($FileName + $file.Extension)) } if ($PSBoundParameters.ContainsKey('BaseDirectory')) @@ -196,7 +197,7 @@ function Get-LocalizedData # and if we see it will return the wrong thing, set the UICulture to DefaultUI culture, and return the logic to Import-LocalizedData $currentCulture = Get-UICulture - $fullFileName = $FileName + ".psd1" + $fullFileName = $FileName + '.psd1' $LanguageFile = $null while ($null -ne $currentCulture -and $currentCulture.Name -and !$LanguageFile) diff --git a/source/Public/Measure-CatchClause.ps1 b/source/Public/Measure-CatchClause.ps1 index 0f80ac3..0b1e0de 100644 --- a/source/Public/Measure-CatchClause.ps1 +++ b/source/Public/Measure-CatchClause.ps1 @@ -18,7 +18,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-CatchClause @@ -44,19 +44,19 @@ function Measure-CatchClause if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.CatchClauseOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.CatchClauseOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-DoUntilStatement.ps1 b/source/Public/Measure-DoUntilStatement.ps1 index 23ed177..e481d2e 100644 --- a/source/Public/Measure-DoUntilStatement.ps1 +++ b/source/Public/Measure-DoUntilStatement.ps1 @@ -15,7 +15,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-DoUntilStatement @@ -41,19 +41,19 @@ function Measure-DoUntilStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoUntilStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoUntilStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-DoWhileStatement.ps1 b/source/Public/Measure-DoWhileStatement.ps1 index 5aa84de..be2864c 100644 --- a/source/Public/Measure-DoWhileStatement.ps1 +++ b/source/Public/Measure-DoWhileStatement.ps1 @@ -16,7 +16,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-DoWhileStatement @@ -42,19 +42,19 @@ function Measure-DoWhileStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoWhileStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoWhileStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-ForEachStatement.ps1 b/source/Public/Measure-ForEachStatement.ps1 index 3e1362a..c925415 100644 --- a/source/Public/Measure-ForEachStatement.ps1 +++ b/source/Public/Measure-ForEachStatement.ps1 @@ -16,7 +16,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-ForEachStatement @@ -42,19 +42,19 @@ function Measure-ForEachStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForEachStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForEachStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-ForStatement.ps1 b/source/Public/Measure-ForStatement.ps1 index e563bd3..72b6ee2 100644 --- a/source/Public/Measure-ForStatement.ps1 +++ b/source/Public/Measure-ForStatement.ps1 @@ -16,7 +16,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-ForStatement @@ -42,19 +42,19 @@ function Measure-ForStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-FunctionBlockBrace.ps1 b/source/Public/Measure-FunctionBlockBrace.ps1 index 5828591..2fcaae3 100644 --- a/source/Public/Measure-FunctionBlockBrace.ps1 +++ b/source/Public/Measure-FunctionBlockBrace.ps1 @@ -16,7 +16,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-FunctionBlockBrace @@ -42,19 +42,19 @@ function Measure-FunctionBlockBrace if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.FunctionOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.FunctionOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-Hashtable.ps1 b/source/Public/Measure-Hashtable.ps1 index 7b20894..e8d2111 100644 --- a/source/Public/Measure-Hashtable.ps1 +++ b/source/Public/Measure-Hashtable.ps1 @@ -47,7 +47,7 @@ function Measure-Hashtable $hashtableLines[-1] -notmatch '\s*}') { $script:diagnosticRecord['Extent'] = $hashtable.Extent - $script:diagnosticRecord['Message'] = $localizedData.HashtableShouldHaveCorrectFormat + $script:diagnosticRecord['Message'] = $script:localizedData.HashtableShouldHaveCorrectFormat $script:diagnosticRecord -as $diagnosticRecordType } else @@ -61,7 +61,7 @@ function Measure-Hashtable if ($keyValuePair.Item1.Extent.StartColumnNumber -ne $expectedLineIndent) { $script:diagnosticRecord['Extent'] = $hashtable.Extent - $script:diagnosticRecord['Message'] = $localizedData.HashtableShouldHaveCorrectFormat + $script:diagnosticRecord['Message'] = $script:localizedData.HashtableShouldHaveCorrectFormat $script:diagnosticRecord -as $diagnosticRecordType break } diff --git a/source/Public/Measure-IfStatement.ps1 b/source/Public/Measure-IfStatement.ps1 index 3d7d016..8353269 100644 --- a/source/Public/Measure-IfStatement.ps1 +++ b/source/Public/Measure-IfStatement.ps1 @@ -16,7 +16,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-IfStatement @@ -42,19 +42,19 @@ function Measure-IfStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.IfStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.IfStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-Keyword.ps1 b/source/Public/Measure-Keyword.ps1 index a21f381..e82e82c 100644 --- a/source/Public/Measure-Keyword.ps1 +++ b/source/Public/Measure-Keyword.ps1 @@ -47,7 +47,7 @@ function Measure-Keyword foreach ($item in $upperCaseTokens) { $script:diagnosticRecord['Extent'] = $item.Extent - $script:diagnosticRecord['Message'] = $localizedData.StatementsContainsUpperCaseLetter -f $item.Text + $script:diagnosticRecord['Message'] = $script:localizedData.StatementsContainsUpperCaseLetter -f $item.Text $suggestedCorrections = New-Object -TypeName Collections.Generic.List[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent] $splat = @{ Extent = $item.Extent @@ -55,7 +55,6 @@ function Measure-Keyword Description = ('Replace {0} with {1}' -f ($item.Extent.Text, $item.Extent.Text.ToLower())) } $suggestedCorrections.Add((New-SuggestedCorrection @splat)) | Out-Null - $suggestedCorrections.Add($suggestedCorrection) | Out-Null $script:diagnosticRecord['suggestedCorrections'] = $suggestedCorrections $script:diagnosticRecord -as $diagnosticRecordType @@ -64,7 +63,7 @@ function Measure-Keyword foreach ($item in $tokenWithNoSpace) { $script:diagnosticRecord['Extent'] = $item.Extent - $script:diagnosticRecord['Message'] = $localizedData.OneSpaceBetweenKeywordAndParenthesis + $script:diagnosticRecord['Message'] = $script:localizedData.OneSpaceBetweenKeywordAndParenthesis $suggestedCorrections = New-Object -TypeName Collections.Generic.List[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent] $splat = @{ Extent = $item.Extent diff --git a/source/Public/Measure-ParamBlock.ps1 b/source/Public/Measure-ParamBlock.ps1 index e78ea29..3a715a8 100644 --- a/source/Public/Measure-ParamBlock.ps1 +++ b/source/Public/Measure-ParamBlock.ps1 @@ -43,7 +43,7 @@ function Measure-ParamBlock { if (Test-StatementOpeningParenthsesOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } @@ -51,13 +51,13 @@ function Measure-ParamBlock { if (-not (Test-StatementOpeningParenthsesOnSameLine @testParameters)) { - $script:diagnosticRecord['Message'] = $localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementEmptyParenthsesHasWhitespace @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace + $script:diagnosticRecord['Message'] = $script:localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-ParameterBlockMandatoryNamedArgument.ps1 b/source/Public/Measure-ParameterBlockMandatoryNamedArgument.ps1 index 2275738..9a39ab6 100644 --- a/source/Public/Measure-ParameterBlockMandatoryNamedArgument.ps1 +++ b/source/Public/Measure-ParameterBlockMandatoryNamedArgument.ps1 @@ -53,7 +53,7 @@ function Measure-ParameterBlockMandatoryNamedArgument $value = $NamedAttributeArgumentAst.Argument.SafeGetValue() if ($value -eq $false) { - $script:diagnosticRecord['Message'] = $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $script:diagnosticRecord['Message'] = $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat $script:diagnosticRecord -as $script:diagnosticRecordType } @@ -73,7 +73,7 @@ function Measure-ParameterBlockMandatoryNamedArgument if ($invalidFormat) { - $script:diagnosticRecord['Message'] = $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $script:diagnosticRecord['Message'] = $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat $script:diagnosticRecord -as $script:diagnosticRecordType } diff --git a/source/Public/Measure-ParameterBlockParameterAttribute.ps1 b/source/Public/Measure-ParameterBlockParameterAttribute.ps1 index 8e7ef92..36f5724 100644 --- a/source/Public/Measure-ParameterBlockParameterAttribute.ps1 +++ b/source/Public/Measure-ParameterBlockParameterAttribute.ps1 @@ -45,19 +45,19 @@ function Measure-ParameterBlockParameterAttribute { if ($ParameterAst.Attributes.TypeName.FullName -notContains 'parameter') { - $script:diagnosticRecord['Message'] = $localizedData.ParameterBlockParameterAttributeMissing + $script:diagnosticRecord['Message'] = $script:localizedData.ParameterBlockParameterAttributeMissing $script:diagnosticRecord -as $script:diagnosticRecordType } elseif ($ParameterAst.Attributes[0].TypeName.FullName -ne 'parameter') { - $script:diagnosticRecord['Message'] = $localizedData.ParameterBlockParameterAttributeWrongPlace + $script:diagnosticRecord['Message'] = $script:localizedData.ParameterBlockParameterAttributeWrongPlace $script:diagnosticRecord -as $script:diagnosticRecordType } elseif ($ParameterAst.Attributes[0].TypeName.FullName -cne 'Parameter') { - $script:diagnosticRecord['Message'] = $localizedData.ParameterBlockParameterAttributeLowerCase + $script:diagnosticRecord['Message'] = $script:localizedData.ParameterBlockParameterAttributeLowerCase $script:diagnosticRecord -as $script:diagnosticRecordType } diff --git a/source/Public/Measure-SwitchStatement.ps1 b/source/Public/Measure-SwitchStatement.ps1 index 4740a25..077fd0c 100644 --- a/source/Public/Measure-SwitchStatement.ps1 +++ b/source/Public/Measure-SwitchStatement.ps1 @@ -15,7 +15,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-SwitchStatement @@ -46,18 +46,18 @@ function Measure-SwitchStatement #> if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.SwitchStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.SwitchStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if elseif (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-TryStatement.ps1 b/source/Public/Measure-TryStatement.ps1 index 9d7ec31..75edc6d 100644 --- a/source/Public/Measure-TryStatement.ps1 +++ b/source/Public/Measure-TryStatement.ps1 @@ -15,7 +15,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-TryStatement @@ -41,19 +41,19 @@ function Measure-TryStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.TryStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.TryStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/Public/Measure-TypeDefinition.ps1 b/source/Public/Measure-TypeDefinition.ps1 index c5a1ad9..8242800 100644 --- a/source/Public/Measure-TypeDefinition.ps1 +++ b/source/Public/Measure-TypeDefinition.ps1 @@ -14,7 +14,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-TypeDefinition @@ -42,19 +42,19 @@ function Measure-TypeDefinition { if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.EnumOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.EnumOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.EnumOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.EnumOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } # if @@ -62,19 +62,19 @@ function Measure-TypeDefinition { if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ClassOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.ClassOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ClassOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ClassOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } # if diff --git a/source/Public/Measure-WhileStatement.ps1 b/source/Public/Measure-WhileStatement.ps1 index 0f89dbb..651d511 100644 --- a/source/Public/Measure-WhileStatement.ps1 +++ b/source/Public/Measure-WhileStatement.ps1 @@ -15,7 +15,7 @@ .OUTPUTS [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES + .NOTES None #> function Measure-WhileStatement @@ -41,19 +41,19 @@ function Measure-WhileStatement if (Test-StatementOpeningBraceOnSameLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.WhileStatementOpeningBraceNotOnSameLine + $script:diagnosticRecord['Message'] = $script:localizedData.WhileStatementOpeningBraceNotOnSameLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsNotFollowedByNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if if (Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testParameters) { - $script:diagnosticRecord['Message'] = $localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $script:diagnosticRecord['Message'] = $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine $script:diagnosticRecord -as $diagnosticRecordType } # if } diff --git a/source/en-US/DscResource.AnalyzerRules.psd1 b/source/en-US/DscResource.AnalyzerRules.strings.psd1 similarity index 100% rename from source/en-US/DscResource.AnalyzerRules.psd1 rename to source/en-US/DscResource.AnalyzerRules.strings.psd1 diff --git a/source/suffix.ps1 b/source/suffix.ps1 index d5ed8bf..1331242 100644 --- a/source/suffix.ps1 +++ b/source/suffix.ps1 @@ -1,2 +1,2 @@ # Import Localized Data -Get-LocalizedData -BindingVariable localizedData -DefaultUICulture 'en-US' +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' diff --git a/tests/QA/module.tests.ps1 b/tests/QA/module.tests.ps1 index 967cab3..51c65a8 100644 --- a/tests/QA/module.tests.ps1 +++ b/tests/QA/module.tests.ps1 @@ -1,120 +1,250 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path - -# Convert-path required for PS7 or Join-Path fails -$ProjectPath = "$here\..\.." | Convert-Path -$ProjectName = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch{$false}) } -).BaseName - -$SourcePath = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch { $false }) } - ).Directory.FullName +BeforeDiscovery { + $projectPath = "$($PSScriptRoot)\..\.." | Convert-Path + + <# + If the QA tests are run outside of the build script (e.g with Invoke-Pester) + the parent scope has not set the variable $ProjectName. + #> + if (-not $ProjectName) + { + # Assuming project folder name is project name. + $ProjectName = Get-SamplerProjectName -BuildRoot $projectPath + } + + $script:moduleName = $ProjectName + + Remove-Module -Name $script:moduleName -Force -ErrorAction SilentlyContinue + + $mut = Get-Module -Name $script:moduleName -ListAvailable | + Select-Object -First 1 | + Import-Module -Force -ErrorAction Stop -PassThru +} + +BeforeAll { + # Convert-Path required for PS7 or Join-Path fails + $projectPath = "$($PSScriptRoot)\..\.." | Convert-Path + + # Get git-related project path. This is relevant for modules that will not be deployed in the root folder of Git. + $gitTopLevelPath = (&git rev-parse --show-toplevel) + $gitRelatedModulePath = (($projectPath -replace [regex]::Escape([IO.Path]::DirectorySeparatorChar), '/') -replace $gitTopLevelPath, '') + if (-not [string]::IsNullOrEmpty($gitRelatedModulePath)) { $gitRelatedModulePath = $gitRelatedModulePath.Trim('/') + '/' } + $escapedGitRelatedModulePath = [regex]::Escape($gitRelatedModulePath) + + <# + If the QA tests are run outside of the build script (e.g with Invoke-Pester) + the parent scope has not set the variable $ProjectName. + #> + if (-not $ProjectName) + { + # Assuming project folder name is project name. + $ProjectName = Get-SamplerProjectName -BuildRoot $projectPath + } -$mut = Import-Module -Name $ProjectName -ErrorAction Stop -PassThru -Force -$allModuleFunctions = &$mut {Get-Command -Module $args[0] -CommandType Function } $ProjectName + $script:moduleName = $ProjectName + + $sourcePath = ( + Get-ChildItem -Path $projectPath\*\*.psd1 | + Where-Object -FilterScript { + ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) ` + -and $( + try + { + Test-ModuleManifest -Path $_.FullName -ErrorAction Stop + } + catch + { + $false + } + ) + } + ).Directory.FullName +} Describe 'Changelog Management' -Tag 'Changelog' { - It 'Changelog has been updated' -skip:( - !([bool](Get-Command git -EA SilentlyContinue) -and - [bool](&(Get-Process -id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) - ) { - # Get the list of changed files compared with branch main - $HeadCommit = &git rev-parse HEAD - $defaultBranchCommit = &git rev-parse origin/main - $filesChanged = &git @('diff', "$defaultBranchCommit...$HeadCommit", '--name-only') - - if($HeadCommit -ne $defaultBranchCommit) { # if we're not testing same commit (i.e. main..main) - $filesChanged.Where{ (Split-Path $_ -Leaf) -match '^changelog' } | Should -Not -BeNullOrEmpty + It 'Changelog has been updated' -Skip:( + -not ([bool](Get-Command git -ErrorAction SilentlyContinue) -and + [bool](&(Get-Process -Id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) + ) { + <# + Get the list of changed files compared with branch main to verify + that required files are changed. + #> + + # Only run if there is a remote called origin + if (((git remote) -match 'origin')) + { + $headCommit = &git rev-parse HEAD + $defaultBranchCommit = &git rev-parse origin/main + $filesChanged = (&git @('diff', "$defaultBranchCommit...$headCommit", '--name-only') | + Where-Object { $_ -match "^$escapedGitRelatedModulePath" }) -replace "^$escapedGitRelatedModulePath", "" + } + + $filesStagedAndUnstaged = (&git @('diff', 'HEAD', '--name-only') 2>&1 | + Where-Object { $_ -match "^$escapedGitRelatedModulePath" }) -replace "^$escapedGitRelatedModulePath", "" + + $filesChanged += $filesStagedAndUnstaged + + # Only check if there are any changed files. + if ($filesChanged) + { + $filesChanged | Should -Contain 'CHANGELOG.md' -Because 'the CHANGELOG.md must be updated with at least one entry in the Unreleased section for each PR' } } - It 'Changelog format compliant with keepachangelog format' -skip:(![bool](Get-Command git -EA SilentlyContinue)) { - { Get-ChangelogData (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw + It 'Changelog format compliant with keepachangelog format' -Skip:(![bool](Get-Command git -EA SilentlyContinue)) { + { Get-ChangelogData -Path (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw } It 'Changelog should have an Unreleased header' -Skip:$skipTest { - (Get-ChangelogData -Path (Join-Path -Path $ProjectPath -ChildPath 'CHANGELOG.md') -ErrorAction 'Stop').Unreleased.RawData | Should -Not -BeNullOrEmpty + (Get-ChangelogData -Path (Join-Path -Path $ProjectPath -ChildPath 'CHANGELOG.md') -ErrorAction Stop).Unreleased | Should -Not -BeNullOrEmpty } } - Describe 'General module control' -Tags 'FunctionalQuality' { +Describe 'General module control' -Tags 'FunctionalQuality' { + It 'Should import without errors' { + { Import-Module -Name $script:moduleName -Force -ErrorAction Stop } | Should -Not -Throw - It 'imports without errors' { - { Import-Module -Name $ProjectName -Force -ErrorAction Stop } | Should -Not -Throw - Get-Module $ProjectName | Should -Not -BeNullOrEmpty - } + Get-Module -Name $script:moduleName | Should -Not -BeNullOrEmpty + } - It 'Removes without error' { - { Remove-Module -Name $ProjectName -ErrorAction Stop } | Should -not -Throw - Get-Module $ProjectName | Should -beNullOrEmpty - } + It 'Should remove without error' { + { Remove-Module -Name $script:moduleName -ErrorAction Stop } | Should -Not -Throw + + Get-Module $script:moduleName | Should -BeNullOrEmpty } +} - if (Get-Command Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) { - $scriptAnalyzerRules = Get-ScriptAnalyzerRule +BeforeDiscovery { + # Must use the imported module to build test cases. + $allModuleFunctions = & $mut { Get-Command -Module $args[0] -CommandType Function } $script:moduleName + + # Build test cases. + $testCases = @() + + foreach ($function in $allModuleFunctions) + { + $testCases += @{ + Name = $function.Name + } } - else { - if ($ErrorActionPreference -ne 'Stop') { - Write-Warning "ScriptAnalyzer not found!" +} + +Describe 'Quality for module' -Tags 'TestQuality' { + BeforeDiscovery { + if (Get-Command -Name Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) + { + $scriptAnalyzerRules = Get-ScriptAnalyzerRule } - else { - Throw "ScriptAnalyzer not found!" + else + { + if ($ErrorActionPreference -ne 'Stop') + { + Write-Warning -Message 'ScriptAnalyzer not found!' + } + else + { + throw 'ScriptAnalyzer not found!' + } } } - # As per https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Tests/Engine/GetScriptAnalyzerRule.tests.ps1#L68-L70 - # for PowerShell Core, PSUseSingularNouns is not - # shipped because it uses APIs that are not present - # in dotnet core. - foreach ($function in $allModuleFunctions) { - $functionFile = Get-ChildItem -path $SourcePath -Recurse -Include "$($function.Name).ps1" - Describe "Quality for $($function.Name)" -Tags 'TestQuality' { - It "$($function.Name) has a unit test" { - Get-ChildItem "tests\" -recurse -include "$($function.Name).Tests.ps1" | Should Not BeNullOrEmpty - } + It 'Should have a unit test for ' -ForEach $testCases { + Get-ChildItem -Path 'tests\' -Recurse -Include "$Name.Tests.ps1" | Should -Not -BeNullOrEmpty + } - if ($scriptAnalyzerRules) { - It "Script Analyzer for $($functionFile.FullName)" { - $PSSAResult = (Invoke-ScriptAnalyzer -Path $functionFile.FullName) - $Report = $PSSAResult | Format-Table -AutoSize | Out-String -Width 110 - $PSSAResult | Should -BeNullOrEmpty -Because ` - "some rule triggered.`r`n`r`n $Report" - } + It 'Should pass Script Analyzer for ' -ForEach $testCases -Skip:(-not $scriptAnalyzerRules) { + $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" - } - } + $pssaResult = (Invoke-ScriptAnalyzer -Path $functionFile.FullName) + $report = $pssaResult | Format-Table -AutoSize | Out-String -Width 110 + $pssaResult | Should -BeNullOrEmpty -Because ` + "some rule triggered.`r`n`r`n $report" + } +} + +Describe 'Help for module' -Tags 'helpQuality' { + It 'Should have .SYNOPSIS for ' -ForEach $testCases { + $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" + + $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName - Describe "Help for $($function.Name)" -Tags 'helpQuality' { - $AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: - ParseInput((Get-Content -raw $functionFile.FullName), [ref]$null, [ref]$null) - $AstSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } - $ParsedFunction = $AbstractSyntaxTree.FindAll( $AstSearchDelegate, $true ) | - Where-Object Name -eq $function.Name + $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) - $FunctionHelp = $ParsedFunction.GetHelpContent() + $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } - It 'Has a SYNOPSIS' { - $FunctionHelp.Synopsis | should not BeNullOrEmpty + $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | + Where-Object -FilterScript { + $_.Name -eq $Name } - It 'Has a Description, with length > 40' { - $FunctionHelp.Description.Length | Should beGreaterThan 40 + $functionHelp = $parsedFunction.GetHelpContent() + + $functionHelp.Synopsis | Should -Not -BeNullOrEmpty + } + + It 'Should have a .DESCRIPTION with length greater than 40 characters for ' -ForEach $testCases { + $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" + + $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName + + $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) + + $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } + + $parsedFunction = $abstractSyntaxTree.FindAll($astSearchDelegate, $true) | + Where-Object -FilterScript { + $_.Name -eq $Name } - It 'Has at least 1 example' { - $FunctionHelp.Examples.Count | Should beGreaterThan 0 - $FunctionHelp.Examples[0] | Should match ([regex]::Escape($function.Name)) - $FunctionHelp.Examples[0].Length | Should BeGreaterThan ($function.Name.Length + 10) + $functionHelp = $parsedFunction.GetHelpContent() + + $functionHelp.Description.Length | Should -BeGreaterThan 40 + } + + It 'Should have at least one (1) example for ' -ForEach $testCases { + $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" + + $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName + + $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) + + $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } + + $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | + Where-Object -FilterScript { + $_.Name -eq $Name } - $parameters = $ParsedFunction.Body.ParamBlock.Parameters.name.VariablePath.Foreach{ $_.ToString() } - foreach ($parameter in $parameters) { - It "Has help for Parameter: $parameter" { - $FunctionHelp.Parameters.($parameter.ToUpper()) | Should Not BeNullOrEmpty - $FunctionHelp.Parameters.($parameter.ToUpper()).Length | Should BeGreaterThan 25 - } + $functionHelp = $parsedFunction.GetHelpContent() + + $functionHelp.Examples.Count | Should -BeGreaterThan 0 + $functionHelp.Examples[0] | Should -Match ([regex]::Escape($function.Name)) + $functionHelp.Examples[0].Length | Should -BeGreaterThan ($function.Name.Length + 10) + + } + + It 'Should have described all parameters for ' -ForEach $testCases { + $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" + + $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName + + $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) + + $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } + + $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | + Where-Object -FilterScript { + $_.Name -eq $Name } + + $functionHelp = $parsedFunction.GetHelpContent() + + $parameters = $parsedFunction.Body.ParamBlock.Parameters.Name.VariablePath.ForEach({ $_.ToString() }) + + foreach ($parameter in $parameters) + { + $functionHelp.Parameters.($parameter.ToUpper()) | Should -Not -BeNullOrEmpty -Because ('the parameter {0} must have a description' -f $parameter) + $functionHelp.Parameters.($parameter.ToUpper()).Length | Should -BeGreaterThan 25 -Because ('the parameter {0} must have descriptive description' -f $parameter) } } +} diff --git a/tests/Unit/Public/Get-AstFromDefinition.ps1 b/tests/TestHelpers/CommonTestHelper.psm1 similarity index 60% rename from tests/Unit/Public/Get-AstFromDefinition.ps1 rename to tests/TestHelpers/CommonTestHelper.psm1 index 85fc804..e330889 100644 --- a/tests/Unit/Public/Get-AstFromDefinition.ps1 +++ b/tests/TestHelpers/CommonTestHelper.psm1 @@ -41,3 +41,33 @@ function Get-AstFromDefinition return $definitionAst.FindAll($astFilter, $true) } + +<# + .SYNOPSIS + Helper function to return tokens, + to be able to test custom rules. + + .PARAMETER ScriptDefinition + The script definition to return ast for. +#> +function Get-TokensFromDefinition +{ + [CmdletBinding()] + [OutputType([System.Management.Automation.Language.Token[]])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ScriptDefinition + ) + + $parseErrors = $token = $null + $null = [System.Management.Automation.Language.Parser]::ParseInput($ScriptDefinition, [ref] $token, [ref] $parseErrors) + + if ($parseErrors) + { + throw $parseErrors + } + + return $token +} diff --git a/tests/Unit/Private/Get-LocalizedData.Tests.ps1 b/tests/Unit/Private/Get-LocalizedData.Tests.ps1 index 79899f1..c3ae104 100644 --- a/tests/Unit/Private/Get-LocalizedData.Tests.ps1 +++ b/tests/Unit/Private/Get-LocalizedData.Tests.ps1 @@ -1,49 +1,92 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} -Import-Module $ProjectName +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') -InModuleScope $ProjectName { - Describe 'Get-LocalizedData' { - Context 'When using the default Import-LocalizedData behavior' { - BeforeAll { - New-Item -Force -Path 'TestDrive:\ar-SA' -ItemType Directory - $null = " + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Get-LocalizedData' { + Context 'When using the default Import-LocalizedData behavior' { + BeforeAll { + New-Item -Force -Path 'TestDrive:\ar-SA' -ItemType Directory + $null = " ConvertFrom-StringData @`' # English strings ParameterBlockParameterAttributeMissing = A [Parameter()] attribute must be the first attribute of each parameter and be on its own line. See https://dsccommunity.org/styleguidelines/parameters/#correct-format-for-parameter-block '@ " | Out-File -Force -FilePath 'TestDrive:\ar-SA\Strings.psd1' - "Get-LocalizedData -FileName 'Strings' -EA Stop" | - Out-File -Force -FilePath 'TestDrive:\execute.ps1' - } + "Get-LocalizedData -FileName 'Strings' -EA Stop" | + Out-File -Force -FilePath 'TestDrive:\execute.ps1' + } + + It 'Should fail finding a Strings file in different locale' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should fail finding a Strings file in different locale' { { $null = &'TestDrive:\execute.ps1' } | Should -Throw } - - } + } - Context 'When falling back to a DefaultUICulture' { - BeforeAll { - New-Item -Force -Path 'TestDrive:\ar-SA' -ItemType Directory - $null = " + Context 'When falling back to a DefaultUICulture' { + BeforeAll { + New-Item -Force -Path 'TestDrive:\ar-SA' -ItemType Directory + $null = " ConvertFrom-StringData @`' # ar-SA strings ParameterBlockParameterAttributeMissing = A [Parameter()] attribute must be the first attribute of each parameter and be on its own line. See https://dsccommunity.org/styleguidelines/parameters/#correct-format-for-parameter-block '@ " | Out-File -Force -FilePath 'TestDrive:\ar-SA\Strings.psd1' - "Get-LocalizedData -FileName 'Strings' -DefaultUICulture 'ar-SA' -EA Stop" | - Out-File -Force -FilePath 'TestDrive:\execute.ps1' - } + "Get-LocalizedData -FileName 'Strings' -DefaultUICulture 'ar-SA' -EA Stop" | + Out-File -Force -FilePath 'TestDrive:\execute.ps1' + } + + It 'Should retrieve the data' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should retrieve the data' { { $null = &'TestDrive:\execute.ps1' } | Should -Not -Throw &'TestDrive:\execute.ps1' | Should -Not -BeNullOrEmpty } diff --git a/tests/Unit/Private/Get-StatementBlockAsRow.Tests.ps1 b/tests/Unit/Private/Get-StatementBlockAsRow.Tests.ps1 index e3841c0..f0f4ebf 100644 --- a/tests/Unit/Private/Get-StatementBlockAsRow.Tests.ps1 +++ b/tests/Unit/Private/Get-StatementBlockAsRow.Tests.ps1 @@ -1,21 +1,66 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' -Import-Module $ProjectName -InModuleScope $ProjectName { - Describe 'Get-StatementBlockAsRow' { - Context 'When string contains CRLF as new line' { - BeforeAll { - $expectedReturnValue1 = 'First line' - $expectedReturnValue2 = 'Second line' - } + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Get-StatementBlockAsRow' -Tag 'Private' { + BeforeAll { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:expectedReturnValue1 = 'First line' + $script:expectedReturnValue2 = 'Second line' + } + } + + Context 'When string contains CRLF as new line' { + It 'Should return the correct array of strings' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return the correct array of strings' { $getStatementBlockAsRowsParameters = @{ StatementBlock = "First line`r`nSecond line" } @@ -27,9 +72,13 @@ InModuleScope $ProjectName { $getStatementBlockAsRowsResult[1] | Should -Be $expectedReturnValue2 } } + } + + Context 'When string contains LF as new line' { + It 'Should return the correct array of strings' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When string contains LF as new line' { - It 'Should return the correct array of strings' { $getStatementBlockAsRowsParameters = @{ StatementBlock = "First line`nSecond line" } diff --git a/tests/Unit/Private/New-SuggestedCorrection.tests.ps1 b/tests/Unit/Private/New-SuggestedCorrection.tests.ps1 index f2bbe87..f6dfa7b 100644 --- a/tests/Unit/Private/New-SuggestedCorrection.tests.ps1 +++ b/tests/Unit/Private/New-SuggestedCorrection.tests.ps1 @@ -1,26 +1,71 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try - { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null } - catch - { $false - } ) - }).BaseName + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') -Import-Module $ProjectName + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} -InModuleScope $ProjectName { - Describe 'New-SuggestedCorrection tests' { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = "$PSScriptRoot\..\..\..\output\builtModule\DscResource.AnalyzerRules" | Convert-Path - IncludeRule = 'Measure-Keyword' +Describe 'New-SuggestedCorrection' -Tag 'Private' { + BeforeAll { + InModuleScope -Parameters @{ + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + IncludeRule = 'Measure-Keyword' + } } + } + + Context 'When suggested correction should be created' { + It 'Should create suggested correction' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When suggested correction should be created' { - It 'Should create suggested correction' { $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' if("example" -eq "example" -or "magic") { @@ -33,8 +78,12 @@ InModuleScope $ProjectName { $record.SuggestedCorrections | Should -Not -BeNullOrEmpty } } - Context 'When suggested correction should not be created' { - It 'Should create suggested correction' { + } + Context 'When suggested correction should not be created' { + It 'Should create suggested correction' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' if ("example" -eq "example" -or "magic") { diff --git a/tests/Unit/Private/Test-IsInClass.Tests.ps1 b/tests/Unit/Private/Test-IsInClass.Tests.ps1 index 65a3991..de6986c 100644 --- a/tests/Unit/Private/Test-IsInClass.Tests.ps1 +++ b/tests/Unit/Private/Test-IsInClass.Tests.ps1 @@ -1,16 +1,57 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -Import-Module $ProjectName + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-isInClass' -Tag 'Private' { + Context 'Non Class AST' { + It 'Should return false for an AST not in a Class AST' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-isInClass' { - Context 'Non Class AST' { - It 'Should return false for an AST not in a Class AST' { $definition = ' function Get-Something { @@ -26,21 +67,25 @@ InModuleScope $ProjectName { ' $Ast = [System.Management.Automation.Language.Parser]::ParseInput($definition, [ref] $null, [ref] $null) $ParameterAst = $Ast.Find( { - param - ( - [System.Management.Automation.Language.Ast] - $AST - ) - $Ast -is [System.Management.Automation.Language.ParameterAst] - }, $true) - ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -Be $true + param + ( + [System.Management.Automation.Language.Ast] + $AST + ) + $Ast -is [System.Management.Automation.Language.ParameterAst] + }, $true) + ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -BeTrue $isInClass = Test-isInClass -Ast $ParameterAst - $isInClass | Should -Be $false + $isInClass | Should -BeFalse } } + } + + Context 'Class AST' { + It 'Should return True for an AST contained in a class AST' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'Class AST' { - It 'Should Return True for an AST contained in a class AST' { $definition = ' class Something { @@ -52,19 +97,23 @@ InModuleScope $ProjectName { ' $Ast = [System.Management.Automation.Language.Parser]::ParseInput($definition, [ref] $null, [ref] $null) $ParameterAst = $Ast.Find( { - param - ( - [System.Management.Automation.Language.Ast] - $AST - ) - $Ast -is [System.Management.Automation.Language.ParameterAst] - }, $true) - ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -Be $true + param + ( + [System.Management.Automation.Language.Ast] + $AST + ) + $Ast -is [System.Management.Automation.Language.ParameterAst] + }, $true) + ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -BeTrue $isInClass = Test-isInClass -Ast $ParameterAst - $isInClass | Should -Be $true + $isInClass | Should -BeTrue } + } + + It 'Should return false for an AST contained in a ScriptBlock that is a value assignment for a property or method in a class AST' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It "Should return false for an AST contained in a ScriptBlock`r`n`t that is a value assignment for a property or method in a class AST" { $definition = ' class Something { @@ -81,17 +130,16 @@ InModuleScope $ProjectName { ' $Ast = [System.Management.Automation.Language.Parser]::ParseInput($definition, [ref] $null, [ref] $null) $ParameterAst = $Ast.Find( { - param - ( - [System.Management.Automation.Language.Ast] - $AST - ) - $Ast -is [System.Management.Automation.Language.ParameterAst] - }, $true) - ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -Be $true + param + ( + [System.Management.Automation.Language.Ast] + $AST + ) + $Ast -is [System.Management.Automation.Language.ParameterAst] + }, $true) + ($ParameterAst -is [System.Management.Automation.Language.ParameterAst]) | Should -BeTrue $isInClass = Test-isInClass -Ast $ParameterAst - $isInClass | Should -Be $false - + $isInClass | Should -BeFalse } } } diff --git a/tests/Unit/Private/Test-StatementEmptyParenthsesHasWhitespace.Tests.ps1 b/tests/Unit/Private/Test-StatementEmptyParenthsesHasWhitespace.Tests.ps1 index b32f04f..31697a9 100644 --- a/tests/Unit/Private/Test-StatementEmptyParenthsesHasWhitespace.Tests.ps1 +++ b/tests/Unit/Private/Test-StatementEmptyParenthsesHasWhitespace.Tests.ps1 @@ -1,61 +1,103 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) { - Test-ModuleManifest -Path $_.FullName -ErrorAction Stop + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null } - catch - { - $false - } ) - }).BaseName + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -Import-Module $ProjectName + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-StatementEmptyParenthsesHasWhitespace' -Tag 'Private' { + Context 'When statement has just whitespace in parentheses' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-StatementEmptyParenthsesHasWhitespace' { - Context 'When statement has just whitespace in parentheses' { - It 'Should return $true' { $testStatementEmptyParenthsesHasWhitespaceParameters = @{ StatementBlock = ` - 'param ( )' + 'param ( )' } $testStatementEmptyParenthsesHasWhitespaceResult = ` Test-StatementEmptyParenthsesHasWhitespace @testStatementEmptyParenthsesHasWhitespaceParameters - $testStatementEmptyParenthsesHasWhitespaceResult | Should -Be $true + $testStatementEmptyParenthsesHasWhitespaceResult | Should -BeTrue } } + } + + Context 'When statement has a newline in parentheses' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement has a newline in parentheses' { - It 'Should return $true' { $testStatementEmptyParenthsesHasWhitespaceParameters = @{ StatementBlock = ` - 'param ( - )' + 'param ( + )' } $testStatementEmptyParenthsesHasWhitespaceResult = ` Test-StatementEmptyParenthsesHasWhitespace @testStatementEmptyParenthsesHasWhitespaceParameters - $testStatementEmptyParenthsesHasWhitespaceResult | Should -Be $true + $testStatementEmptyParenthsesHasWhitespaceResult | Should -BeTrue } } + } + + Context 'When statement follows style guideline' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement follows style guideline' { - It 'Should return $false' { $testStatementEmptyParenthsesHasWhitespaceParameters = @{ StatementBlock = ` - 'param ()' + 'param ()' } $testStatementEmptyParenthsesHasWhitespaceResult = ` Test-StatementEmptyParenthsesHasWhitespace @testStatementEmptyParenthsesHasWhitespaceParameters - $testStatementEmptyParenthsesHasWhitespaceResult | Should -Be $false + $testStatementEmptyParenthsesHasWhitespaceResult | Should -BeFalse } } } diff --git a/tests/Unit/Private/Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine.Tests.ps1 b/tests/Unit/Private/Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine.Tests.ps1 index faacdab..c5ff65b 100644 --- a/tests/Unit/Private/Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine.Tests.ps1 +++ b/tests/Unit/Private/Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine.Tests.ps1 @@ -1,16 +1,57 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -Import-Module $ProjectName + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine' -Tag 'Private' { + Context 'When statement opening brace is not followed by a new line' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine' { - Context 'When statement opening brace is not followed by a new line' { - It 'Should return $true' { $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineParameters = @{ StatementBlock = ` 'if ($true) @@ -26,12 +67,16 @@ InModuleScope $ProjectName { $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult = ` Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testStatementOpeningBraceIsFollowedByMoreThanOneNewLineParameters - $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult | Should -Be $true + $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult | Should -BeTrue } } + } + + Context 'When statement follows style guideline' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement follows style guideline' { - It 'Should return $false' { $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineParameters = @{ StatementBlock = ` 'if ($true) @@ -46,7 +91,7 @@ InModuleScope $ProjectName { $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult = ` Test-StatementOpeningBraceIsFollowedByMoreThanOneNewLine @testStatementOpeningBraceIsFollowedByMoreThanOneNewLineParameters - $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult | Should -Be $false + $testStatementOpeningBraceIsFollowedByMoreThanOneNewLineResult | Should -BeFalse } } } diff --git a/tests/Unit/Private/Test-StatementOpeningBraceIsNotFollowedByNewLine.Tests.ps1 b/tests/Unit/Private/Test-StatementOpeningBraceIsNotFollowedByNewLine.Tests.ps1 index 5fce711..1fae688 100644 --- a/tests/Unit/Private/Test-StatementOpeningBraceIsNotFollowedByNewLine.Tests.ps1 +++ b/tests/Unit/Private/Test-StatementOpeningBraceIsNotFollowedByNewLine.Tests.ps1 @@ -1,22 +1,63 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -Import-Module $ProjectName + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-StatementOpeningBraceIsNotFollowedByNewLine' -Tag 'Private' { + Context 'When statement opening brace is not followed by a new line' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-StatementOpeningBraceIsNotFollowedByNewLine' { - Context 'When statement opening brace is not followed by a new line' { - It 'Should return $true' { $testStatementOpeningBraceIsNotFollowedByNewLineParameters = @{ StatementBlock = ` 'if ($true) { if ($false) - { - } + { + } } ' } @@ -24,19 +65,23 @@ InModuleScope $ProjectName { $testStatementOpeningBraceIsNotFollowedByNewLineResult = ` Test-StatementOpeningBraceIsNotFollowedByNewLine @testStatementOpeningBraceIsNotFollowedByNewLineParameters - $testStatementOpeningBraceIsNotFollowedByNewLineResult | Should -Be $true + $testStatementOpeningBraceIsNotFollowedByNewLineResult | Should -BeTrue } } + } + + Context 'When statement follows style guideline' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement follows style guideline' { - It 'Should return $false' { $testStatementOpeningBraceIsNotFollowedByNewLineParameters = @{ StatementBlock = ` 'if ($true) { - if ($false) - { - } + if ($false) + { + } } ' } @@ -44,7 +89,7 @@ InModuleScope $ProjectName { $testStatementOpeningBraceIsNotFollowedByNewLineResult = ` Test-StatementOpeningBraceIsNotFollowedByNewLine @testStatementOpeningBraceIsNotFollowedByNewLineParameters - $testStatementOpeningBraceIsNotFollowedByNewLineResult | Should -Be $false + $testStatementOpeningBraceIsNotFollowedByNewLineResult | Should -BeFalse } } } diff --git a/tests/Unit/Private/Test-StatementOpeningBraceOnSameLine.Tests.ps1 b/tests/Unit/Private/Test-StatementOpeningBraceOnSameLine.Tests.ps1 index 8f698f4..a642f75 100644 --- a/tests/Unit/Private/Test-StatementOpeningBraceOnSameLine.Tests.ps1 +++ b/tests/Unit/Private/Test-StatementOpeningBraceOnSameLine.Tests.ps1 @@ -1,16 +1,57 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -Import-Module $ProjectName + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-StatementOpeningBraceOnSameLine' { + Context 'When statement has an opening brace on the same line' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-StatementOpeningBraceOnSameLine' { - Context 'When statement has an opening brace on the same line' { - It 'Should return $true' { $testStatementOpeningBraceOnSameLineParameters = @{ StatementBlock = ` 'if ($true) { @@ -21,13 +62,17 @@ InModuleScope $ProjectName { $testStatementOpeningBraceOnSameLineResult = ` Test-StatementOpeningBraceOnSameLine @testStatementOpeningBraceOnSameLineParameters - $testStatementOpeningBraceOnSameLineResult | Should -Be $true + $testStatementOpeningBraceOnSameLineResult | Should -BeTrue } } + } + + # Regression test for issue reported in review comment for PR #180. + Context 'When statement is using braces in the evaluation expression' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - # Regression test for issue reported in review comment for PR #180. - Context 'When statement is using braces in the evaluation expression' { - It 'Should return $false' { $testStatementOpeningBraceOnSameLineParameters = @{ StatementBlock = ` 'if (Get-Command | Where-Object -FilterScript { $_.Name -eq ''Get-Help'' } ) @@ -39,12 +84,16 @@ InModuleScope $ProjectName { $testStatementOpeningBraceOnSameLineResult = ` Test-StatementOpeningBraceOnSameLine @testStatementOpeningBraceOnSameLineParameters - $testStatementOpeningBraceOnSameLineResult | Should -Be $false + $testStatementOpeningBraceOnSameLineResult | Should -BeFalse } } + } + + Context 'When statement follows style guideline' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement follows style guideline' { - It 'Should return $false' { $testStatementOpeningBraceOnSameLineParameters = @{ StatementBlock = ` 'if ($true) @@ -56,7 +105,7 @@ InModuleScope $ProjectName { $testStatementOpeningBraceOnSameLineResult = ` Test-StatementOpeningBraceOnSameLine @testStatementOpeningBraceOnSameLineParameters - $testStatementOpeningBraceOnSameLineResult | Should -Be $false + $testStatementOpeningBraceOnSameLineResult | Should -BeFalse } } } diff --git a/tests/Unit/Private/Test-StatementOpeningParenthsesOnSameLine.Tests.ps1 b/tests/Unit/Private/Test-StatementOpeningParenthsesOnSameLine.Tests.ps1 index 78d5730..9f4696b 100644 --- a/tests/Unit/Private/Test-StatementOpeningParenthsesOnSameLine.Tests.ps1 +++ b/tests/Unit/Private/Test-StatementOpeningParenthsesOnSameLine.Tests.ps1 @@ -1,23 +1,57 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) { - Test-ModuleManifest -Path $_.FullName -ErrorAction Stop + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null } - catch - { - $false - } ) - }).BaseName + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -Import-Module $ProjectName + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force +} + +Describe 'Test-StatementOpeningParenthsesOnSameLine' -Tag 'Private' { + Context 'When statement has an opening parentheses on the same line' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 -InModuleScope $ProjectName { - Describe 'Test-StatementOpeningParenthsesOnSameLine' { - Context 'When statement has an opening parentheses on the same line' { - It 'Should return $true' { $testStatementOpeningParenthsesOnSameLineParameters = @{ StatementBlock = ` 'param ()' @@ -26,12 +60,16 @@ InModuleScope $ProjectName { $testStatementOpeningParenthsesOnSameLineResult = ` Test-StatementOpeningParenthsesOnSameLine @testStatementOpeningParenthsesOnSameLineParameters - $testStatementOpeningParenthsesOnSameLineResult | Should -Be $true + $testStatementOpeningParenthsesOnSameLineResult | Should -BeTrue } } + } + + Context 'When statement does not have an opening parentheses on the same line' { + It 'Should return $false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When statement does not have an opening parentheses on the same line' { - It 'Should return $false' { $testStatementOpeningParenthsesOnSameLineParameters = @{ StatementBlock = ` 'param @@ -41,7 +79,7 @@ InModuleScope $ProjectName { $testStatementOpeningParenthsesOnSameLineResult = ` Test-StatementOpeningParenthsesOnSameLine @testStatementOpeningParenthsesOnSameLineParameters - $testStatementOpeningParenthsesOnSameLineResult | Should -Be $false + $testStatementOpeningParenthsesOnSameLineResult | Should -BeFalse } } } diff --git a/tests/Unit/Public/Get-TokensFromDefinition.ps1 b/tests/Unit/Public/Get-TokensFromDefinition.ps1 deleted file mode 100644 index d0ece60..0000000 --- a/tests/Unit/Public/Get-TokensFromDefinition.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -<# - .SYNOPSIS - Helper function to return tokens, - to be able to test custom rules. - - .PARAMETER ScriptDefinition - The script definition to return ast for. -#> -function Get-TokensFromDefinition -{ - [CmdletBinding()] - [OutputType([System.Management.Automation.Language.Token[]])] - param - ( - [Parameter(Mandatory = $true)] - [System.String] - $ScriptDefinition - ) - - $parseErrors = $token = $null - $null = [System.Management.Automation.Language.Parser]::ParseInput($ScriptDefinition, [ref] $token, [ref] $parseErrors) - - if ($parseErrors) - { - throw $parseErrors - } - - return $token -} diff --git a/tests/Unit/Public/Measure-CatchClause.Tests.ps1 b/tests/Unit/Public/Measure-CatchClause.Tests.ps1 index 5aa558c..338a398 100644 --- a/tests/Unit/Public/Measure-CatchClause.Tests.ps1 +++ b/tests/Unit/Public/Measure-CatchClause.Tests.ps1 @@ -1,91 +1,148 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -$ModuleUnderTest = Import-Module $ProjectName -PassThru -Force -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-CatchClause' { +Describe 'Measure-CatchClause' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.CatchClauseAst' - $ruleName = 'Measure-CatchClause' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.CatchClauseAst' + $script:ruleName = 'Measure-CatchClause' + } } Context 'When Catch-clause has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { - $value = 1 + try + { + $value = 1 + } + catch { + throw + } } - catch { - throw - } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-CatchClause -CatchClauseAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-CatchClause -CatchClauseAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Catch-clause opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { - $value = 1 - } - catch - { throw + try + { + $value = 1 + } + catch + { throw + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-CatchClause -CatchClauseAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-CatchClause -CatchClauseAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Catch-clause opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try - { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { + try + { + $value = 1 + } + catch + { - throw + throw + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-CatchClause -CatchClauseAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-CatchClause -CatchClauseAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } @@ -93,97 +150,122 @@ Describe 'Measure-CatchClause' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-CatchClause" } - $ruleName = "$($script:ModuleName)\Measure-CatchClause" } Context 'When Catch-clause has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $value = 1 + try + { + $value = 1 + } + catch { + throw + } } - catch { - throw - } - } - ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Catch-clause opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $value = 1 + try + { + $value = 1 + } + catch + { throw + } } - catch - { throw - } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Catch-clause opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try - { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + try + { + $value = 1 + } + catch + { - throw + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.CatchClauseOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Catch-clause follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try - { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - throw + try + { + $value = 1 + } + catch + { + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-DoUntilStatement.Tests.ps1 b/tests/Unit/Public/Measure-DoUntilStatement.Tests.ps1 index aa575f1..94802df 100644 --- a/tests/Unit/Public/Measure-DoUntilStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-DoUntilStatement.Tests.ps1 @@ -1,175 +1,256 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -Describe 'Measure-DoUntilStatement' { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-DoUntilStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.DoUntilStatementAst' - $ruleName = 'Measure-DoUntilStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.DoUntilStatementAst' + $script:ruleName = 'Measure-DoUntilStatement' + } } Context 'When DoUntil-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 0 - - do { - $i++ - } until ($i -eq 2) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + $i = 0 + + do { + $i++ + } until ($i -eq 2) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoUntil-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 0 - - do - { $i++ - } until ($i -eq 2) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + $i = 0 + + do + { $i++ + } until ($i -eq 2) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoUntil-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 0 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do + $definition = ' + function Get-Something { + $i = 0 + + do + { - $i++ - } until ($i -eq 2) - } - ' + $i++ + } until ($i -eq 2) + } + ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoUntilStatement -DoUntilStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-DoUntilStatement" } - $ruleName = "$($script:ModuleName)\Measure-DoUntilStatement" } Context 'When DoUntil-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 0 - - do { - $i++ - } until ($i -eq 2) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 0 + + do { + $i++ + } until ($i -eq 2) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoUntil-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 0 - - do - { $i++ - } until ($i -eq 2) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 0 + + do + { $i++ + } until ($i -eq 2) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoUntil-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 0 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $i = 0 - $i++ - } until ($i -eq 2) - } - ' + do + { - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $i++ + } until ($i -eq 2) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoUntilStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoUntil-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 0 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $i++ - } until ($i -eq 2) - } - ' + $i = 0 + + do + { + $i++ + } until ($i -eq 2) + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-DoWhileStatement.Tests.ps1 b/tests/Unit/Public/Measure-DoWhileStatement.Tests.ps1 index 1cd1101..3572863 100644 --- a/tests/Unit/Public/Measure-DoWhileStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-DoWhileStatement.Tests.ps1 @@ -1,26 +1,74 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-DoWhileStatement' { +Describe 'Measure-DoWhileStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.DoWhileStatementAst' - $ruleName = 'Measure-DoWhileStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.DoWhileStatementAst' + $script:ruleName = 'Measure-DoWhileStatement' + } } Context 'When DoWhile-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' function Get-Something { $i = 10 @@ -31,17 +79,21 @@ Describe 'Measure-DoWhileStatement' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoWhile-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' function Get-Something { $i = 10 @@ -52,17 +104,21 @@ Describe 'Measure-DoWhileStatement' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoWhile-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' function Get-Something { $i = 10 @@ -75,11 +131,12 @@ Describe 'Measure-DoWhileStatement' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-DoWhileStatement -DoWhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } @@ -87,90 +144,114 @@ Describe 'Measure-DoWhileStatement' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-DoWhileStatement" } - $ruleName = "$($script:ModuleName)\Measure-DoWhileStatement" } Context 'When DoWhile-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do { - $i-- - } while ($i -gt 0) - } - ' + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 10 + + do { + $i-- + } while ($i -gt 0) + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoWhile-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do - { $i-- - } while ($i -gt 0) - } - ' + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 10 + + do + { $i-- + } while ($i -gt 0) + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoWhile-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $i = 10 - $i-- - } while ($i -gt 0) - } - ' + do + { + + $i-- + } while ($i -gt 0) + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.DoWhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When DoWhile-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - do + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $i-- - } while ($i -gt 0) - } - ' + $i = 10 + + do + { + $i-- + } while ($i -gt 0) + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-ForEachStatement.Tests.ps1 b/tests/Unit/Public/Measure-ForEachStatement.Tests.ps1 index 32e035e..2c9dfa5 100644 --- a/tests/Unit/Public/Measure-ForEachStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-ForEachStatement.Tests.ps1 @@ -1,80 +1,138 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -. $PSScriptRoot\Get-AstFromDefinition.ps1 + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -Describe 'Measure-ForEachStatement' { + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-ForEachStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.ForEachStatementAst' - $ruleName = 'Measure-ForEachStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.ForEachStatementAst' + $script:ruleName = 'Measure-ForEachStatement' + } } Context 'When foreach-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + $myArray = @() + foreach ($stringText in $myArray) { + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When foreach-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) - { $stringText + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + $myArray = @() + foreach ($stringText in $myArray) + { $stringText + } } - } - ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When foreach-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { + $myArray = @() + foreach ($stringText in $myArray) + { - $stringText + $stringText + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForEachStatement -ForEachStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } @@ -82,84 +140,108 @@ Describe 'Measure-ForEachStatement' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-ForEachStatement" } - $ruleName = "$($script:ModuleName)\Measure-ForEachStatement" } Context 'When foreach-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $myArray = @() + foreach ($stringText in $myArray) { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When foreach-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) - { $stringText + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $myArray = @() + foreach ($stringText in $myArray) + { $stringText + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When foreach-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $myArray = @() + foreach ($stringText in $myArray) + { - $stringText + $stringText + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForEachStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When foreach-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $myArray = @() - foreach ($stringText in $myArray) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $myArray = @() + foreach ($stringText in $myArray) + { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-ForStatement.Tests.ps1 b/tests/Unit/Public/Measure-ForStatement.Tests.ps1 index d191905..f3f6957 100644 --- a/tests/Unit/Public/Measure-ForStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-ForStatement.Tests.ps1 @@ -1,79 +1,136 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -. $PSScriptRoot\Get-AstFromDefinition.ps1 + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -Describe 'Measure-ForStatement' { + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-ForStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.ForStatementAst' - $ruleName = 'Measure-ForStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.ForStatementAst' + $script:ruleName = 'Measure-ForStatement' + } } Context 'When For-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + for ($a = 1; $a -lt 2; $a++) { + $value = 1 + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForStatement -ForStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForStatement -ForStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When For-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) - { $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + for ($a = 1; $a -lt 2; $a++) + { $value = 1 + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForStatement -ForStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForStatement -ForStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When For-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { + for ($a = 1; $a -lt 2; $a++) + { - $value = 1 + $value = 1 + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ForStatement -ForStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ForStatement -ForStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } @@ -81,82 +138,106 @@ Describe 'Measure-ForStatement' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-ForStatement" } - $ruleName = "$($script:ModuleName)\Measure-ForStatement" } Context 'When For-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + for ($a = 1; $a -lt 2; $a++) { + $value = 1 + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When For-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) - { $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + for ($a = 1; $a -lt 2; $a++) + { $value = 1 + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When For-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + for ($a = 1; $a -lt 2; $a++) + { - $value = 1 + $value = 1 + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ForStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When For-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - for ($a = 1; $a -lt 2; $a++) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $value = 1 + for ($a = 1; $a -lt 2; $a++) + { + $value = 1 + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-FunctionBlockBrace.Tests.ps1 b/tests/Unit/Public/Measure-FunctionBlockBrace.Tests.ps1 index d36e6b5..af587c6 100644 --- a/tests/Unit/Public/Measure-FunctionBlockBrace.Tests.ps1 +++ b/tests/Unit/Public/Measure-FunctionBlockBrace.Tests.ps1 @@ -1,228 +1,312 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-FunctionBlockBrace' { +Describe 'Measure-FunctionBlockBrace' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.FunctionDefinitionAst' - $ruleName = 'Measure-FunctionBlockBrace' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.FunctionDefinitionAst' + $script:ruleName = 'Measure-FunctionBlockBrace' + } } Context 'When a functions opening brace is on the same line as the function keyword' { It 'Should write the correct error record' { - $definition = ' - function Get-Something { - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When function opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When function opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-FunctionBlockBrace -FunctionDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-FunctionBlockBrace" } - $ruleName = "$($script:ModuleName)\Measure-FunctionBlockBrace" } Context 'When a functions opening brace is on the same line as the function keyword' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something { - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When two functions has opening brace is on the same line as the function keyword' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something { - } - - function Get-SomethingElse { - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 2 - $record[0].Message | Should -Be $localizedData.FunctionOpeningBraceNotOnSameLine - $record[1].Message | Should -Be $localizedData.FunctionOpeningBraceNotOnSameLine + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + } + + function Get-SomethingElse { + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 2 + $record[0].Message | Should -Be $script:localizedData.FunctionOpeningBraceNotOnSameLine + $record[1].Message | Should -Be $script:localizedData.FunctionOpeningBraceNotOnSameLine + } } } Context 'When function opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When function opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.FunctionOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When function follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Variable1 - ) - - return $true - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Variable1 + ) + + return $true + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-Hashtable.Tests.ps1 b/tests/Unit/Public/Measure-Hashtable.Tests.ps1 index 5e5f611..920e12c 100644 --- a/tests/Unit/Public/Measure-Hashtable.Tests.ps1 +++ b/tests/Unit/Public/Measure-Hashtable.Tests.ps1 @@ -1,57 +1,108 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try - { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null } - catch - { $false - } ) - }).BaseName -$script:ModuleName = $ProjectName -. $PSScriptRoot\Get-AstFromDefinition.ps1 + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -Force -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -Describe 'Measure-Hashtable' { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-Hashtable' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $ruleName = 'Measure-Hashtable' - $astType = 'System.Management.Automation.Language.HashtableAst' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:ruleName = 'Measure-Hashtable' + $script:astType = 'System.Management.Automation.Language.HashtableAst' + } } Context 'When hashtable is not correctly formatted' { It 'Hashtable defined on a single line' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{Key1 = "Value1";Key2 = 2;Key3 = "3"} ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Hashtable partially correct formatted' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 Key3 = "3" } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Hashtable indentation not correct' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -59,28 +110,36 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Correctly formatted empty hashtable' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{ } $hashtableNoSpace = @{} ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When composite resource is not correctly formatted' { It 'Composite resource defined on a single line' -Skip:(!([bool]$IsWindows)) { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' configuration test { Script test { GetScript = {}; SetScript = {}; TestScript = {} @@ -88,15 +147,19 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Composite resource partially correct formatted' -Skip:(!([bool]$IsWindows)) { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' configuration test { Script test { GetScript = {} @@ -106,15 +169,19 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Composite resource indentation not correct' -Skip:(!([bool]$IsWindows)) { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' configuration test { Script test { @@ -125,18 +192,22 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When hashtable is correctly formatted' { - It "Correctly formatted non-nested hashtable" { - $definition = ' + It 'Correctly formatted non-nested hashtable' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -144,13 +215,17 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 0 + } } It 'Correctly formatted nested hashtable' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -161,26 +236,34 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 0 + } } It 'Correctly formatted empty hashtable' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' $hashtableNoSpace = @{} $hashtable = @{ } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When composite resource is correctly formatted' { - It "Correctly formatted non-nested hashtable" -Skip:(!([bool]$IsWindows)) { - $definition = ' + It 'Correctly formatted non-nested hashtable' -Skip:(!([bool]$IsWindows)) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' configuration test { Script test { @@ -191,50 +274,68 @@ Describe 'Measure-Hashtable' { } ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-Hashtable -HashtableAst $mockAst - ($record | Measure-Object).Count | Should -Be 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-Hashtable -HashtableAst $mockAst + ($record | Measure-Object).Count | Should -Be 0 + } } - } - } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-Hashtable" } - $ruleName = "$($script:ModuleName)\Measure-Hashtable" } Context 'When hashtable is not correctly formatted' { It 'Hashtable defined on a single line' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{Key1 = "Value1";Key2 = 2;Key3 = "3"} ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Hashtable partially correct formatted' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 Key3 = "3" } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Hashtable indentation not correct' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -242,28 +343,35 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } <# Commented out until PSSCriptAnalyzer fix is published. It 'Incorrectly formatted empty hashtable' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName - } - #> + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } + } #> } Context 'When composite resource is not correctly formatted' { It 'Composite resource defined on a single line' -Skip:(!([bool]$IsWindows)) { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' configuration test { Script test { GetScript = {}; SetScript = {}; TestScript = {} @@ -271,15 +379,19 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Composite resource partially correct formatted' -Skip:(!([bool]$IsWindows)) { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' configuration test { Script test { GetScript = {} @@ -289,14 +401,18 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } It 'Composite resource indentation not correct' -Skip:(!([bool]$IsWindows)) { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' configuration test { Script test { @@ -307,17 +423,20 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.HashtableShouldHaveCorrectFormat - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.HashtableShouldHaveCorrectFormat + $record.RuleName | Should -Be $ruleName + } } - } Context 'When hashtable is correctly formatted' { It 'Correctly formatted non-nested hashtable' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -325,12 +444,16 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } It 'Correctly formatted nested hashtable' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ Key1 = "Value1" Key2 = 2 @@ -341,24 +464,32 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } It 'Correctly formatted empty hashtable' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' $hashtable = @{ } $hashtableNoSpace = @{} ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When composite resource is correctly formatted' { - It "Correctly formatted non-nested hashtable" -Skip:(!([bool]$IsWindows)) { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + It 'Correctly formatted non-nested hashtable' -Skip:(!([bool]$IsWindows)) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' configuration test { Script test { @@ -369,11 +500,10 @@ Describe 'Measure-Hashtable' { } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } - } - } } diff --git a/tests/Unit/Public/Measure-IfStatement.Tests.ps1 b/tests/Unit/Public/Measure-IfStatement.Tests.ps1 index 981439a..792f0d6 100644 --- a/tests/Unit/Public/Measure-IfStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-IfStatement.Tests.ps1 @@ -1,195 +1,284 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -Describe 'Measure-IfStatement' { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-IfStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.IfStatementAst' - $ruleName = 'Measure-IfStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.IfStatementAst' + $script:ruleName = 'Measure-IfStatement' + } } Context 'When if-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - if ($true) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + if ($true) { + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-IfStatement -IfStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-IfStatement -IfStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When if-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - if ($true) - { return $true + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + if ($true) + { return $true + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-IfStatement -IfStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-IfStatement -IfStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When if-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - if ($true) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { + if ($true) + { - return $true + return $true + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-IfStatement -IfStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-IfStatement -IfStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-IfStatement" } - $ruleName = "$($script:ModuleName)\Measure-IfStatement" } Context 'When if-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if ($true) { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + if ($true) { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When two if-statements has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if ($true) { - } + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - if ($true) { + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + if ($true) { + } + + if ($true) { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 2 - $record[0].Message | Should -Be $localizedData.IfStatementOpeningBraceNotOnSameLine - $record[1].Message | Should -Be $localizedData.IfStatementOpeningBraceNotOnSameLine + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 2 + $record[0].Message | Should -Be $script:localizedData.IfStatementOpeningBraceNotOnSameLine + $record[1].Message | Should -Be $script:localizedData.IfStatementOpeningBraceNotOnSameLine + } } } Context 'When if-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if ($true) - { return $true + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + if ($true) + { return $true + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When if-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if ($true) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + if ($true) + { - return $true + return $true + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.IfStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When if-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if ($true) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + if ($true) + { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } # Regression test for issue reported in review comment for PR #180. Context 'When if-statement is using braces in the evaluation expression' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - if (Get-Command | Where-Object -FilterScript { $_.Name -eq ''Get-Help'' } ) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + if (Get-Command | Where-Object -FilterScript { $_.Name -eq ''Get-Help'' } ) + { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-Keyword.Tests.ps1 b/tests/Unit/Public/Measure-Keyword.Tests.ps1 index 2096210..fc94e9c 100644 --- a/tests/Unit/Public/Measure-Keyword.Tests.ps1 +++ b/tests/Unit/Public/Measure-Keyword.Tests.ps1 @@ -1,110 +1,178 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName - -. $PSScriptRoot\Get-AstFromDefinition.ps1 -. $PSScriptRoot\Get-TokensFromDefinition.ps1 - -$ModuleUnderTest = Import-Module $ProjectName -PassThru -Force -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path -Describe 'Measure-Keyword' { +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-Keyword' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $ruleName = 'Measure-Keyword' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:ruleName = 'Measure-Keyword' + } } Context 'When keyword contains upper case letters' { It 'Should write the correct error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' Function Test { return $true } ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be ($localizedData.StatementsContainsUpperCaseLetter -f 'function') - $record.RuleName | Should -Be $ruleName + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be ($script:localizedData.StatementsContainsUpperCaseLetter -f 'function') + $record.RuleName | Should -Be $ruleName + } } It 'Should ignore DSC keywords' -Skip:(![bool]$IsWindows) { - $definition = ' - Configuration FileDSC - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Node $AllNodes.NodeName + $definition = ' + Configuration FileDSC { - File "Fil1" + + Node $AllNodes.NodeName { - Ensure = "Absent" - DestinationPath = C:\temp\test.txt + File "Fil1" + { + Ensure = "Absent" + DestinationPath = C:\temp\test.txt + } } } - } - ' + ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 0 + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When keyword is not followed by a single space' { It 'Should write the correct error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' if("example" -eq "example" -or "magic") { Write-Verbose -Message "Example found." } ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.OneSpaceBetweenKeywordAndParenthesis - $record.RuleName | Should -Be $ruleName + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.OneSpaceBetweenKeywordAndParenthesis + $record.RuleName | Should -Be $ruleName + } } } Context 'When keyword does not contain upper case letters' { It 'Should not return an error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' function Test { return $true } ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 0 + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When keyword is followed by a single space' { It 'Should not return an error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' if ("example" -eq "example" -or "magic") { Write-Verbose -Message "Example found." } ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 0 + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When another word contains ''base'' but has other characters preceeding it' { It 'Should not return an error record' { - $definition = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' class SqlSetupBase { SqlSetupBase() : base () @@ -114,104 +182,137 @@ Describe 'Measure-Keyword' { } ' - $token = Get-TokensFromDefinition -ScriptDefinition $definition - $record = Measure-Keyword -Token $token - ($record | Measure-Object).Count | Should -Be 0 + $token = Get-TokensFromDefinition -ScriptDefinition $definition + $record = Measure-Keyword -Token $token + ($record | Measure-Object).Count | Should -Be 0 + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath - IncludeRule = 'Measure-Keyword' + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + IncludeRule = 'Measure-Keyword' + } + + $script:ruleName = "$ModuleName\Measure-Keyword" } - $ruleName = "$($script:ModuleName)\Measure-Keyword" } Context 'When measuring the keyword' { Context 'When keyword contains upper case letters' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - Function Test - { - return $true - } - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be ($localizedData.StatementsContainsUpperCaseLetter -f 'function') - $record.RuleName | Should -Be $ruleName + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + Function Test + { + return $true + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be ($script:localizedData.StatementsContainsUpperCaseLetter -f 'function') + $record.RuleName | Should -Be $ruleName + } } It 'Should ignore DSC keywords' -Skip:(![bool]$IsWindows) { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - Configuration FileDSC - { - Node $AllNodes.NodeName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + Configuration FileDSC { - File "Fil1" + Node $AllNodes.NodeName { - Ensure = "Absent" - DestinationPath = C:\temp\test.txt + File "Fil1" + { + Ensure = "Absent" + DestinationPath = C:\temp\test.txt + } } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 0 + } } } Context 'When keyword is not followed by a single space' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' if("example" -eq "example" -or "magic") { Write-Verbose -Message "Example found." } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.OneSpaceBetweenKeywordAndParenthesis - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.OneSpaceBetweenKeywordAndParenthesis + $record.RuleName | Should -Be $ruleName + } } } Context 'When keyword does not contain upper case letters' { It 'Should not return an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' function Test { return $true } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 0 + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 0 + } } } Context 'When keyword is followed by a single space' { It 'Should not return an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' if ("example" -eq "example" -or "magic") { Write-Verbose -Message "Example found." } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } } Context 'When another word contains ''base'' but has other characters preceeding it' { It 'Should not return an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' class SqlSetupBase { SqlSetupBase() : base () @@ -220,8 +321,10 @@ Describe 'Measure-Keyword' { } } ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 0 + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 0 + } } } } diff --git a/tests/Unit/Public/Measure-ParamBlock.Tests.ps1 b/tests/Unit/Public/Measure-ParamBlock.Tests.ps1 index 679607c..c192682 100644 --- a/tests/Unit/Public/Measure-ParamBlock.Tests.ps1 +++ b/tests/Unit/Public/Measure-ParamBlock.Tests.ps1 @@ -1,172 +1,265 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -Describe 'Measure-ParamBlock' { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-ParamBlock' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.ParamBlockAst' - $ruleName = 'Measure-ParamBlock' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.ParamBlockAst' + $script:ruleName = 'Measure-ParamBlock' + } } Context 'When ParamBlock is empty but parentheses have a space' { It 'Should write the correct error record' { - $definition = ' - param ( ) - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + param ( ) + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is empty but parentheses are not on the same line' { It 'Should write the correct error record' { - $definition = ' - param - () - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + param + () + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is not empty but parentheses start on the same line' { It 'Should write the correct error record' { - $definition = ' - param ( - [Parameter()] - [string]$someString - ) - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + param ( + [Parameter()] + [string]$someString + ) + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is not empty and parentheses start on the next line' { It 'Should write the correct error record' { - $definition = ' - param - ( - [Parameter()] - [string]$someString - ) - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] - ($record | Measure-Object).Count | Should -BeExactly 0 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + param + ( + [Parameter()] + [string]$someString + ) + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] + ($record | Measure-Object).Count | Should -BeExactly 0 + } } } Context 'When ParamBlock is empty and parentheses are empty' { It 'Should write the correct error record' { - $definition = ' - param () - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + param () + ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] - ($record | Measure-Object).Count | Should -BeExactly 0 + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParamBlock -ParamBlockAst $mockAst[0] + ($record | Measure-Object).Count | Should -BeExactly 0 + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-ParamBlock" } - $ruleName = "$($script:ModuleName)\Measure-ParamBlock" } Context 'When ParamBlock is empty but parentheses have a space' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - param ( ) - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + param ( ) + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockEmptyParenthesesShouldNotHaveWhitespace + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is empty but parentheses are not on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - param - () - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + param + () + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockEmptyParenthesesShouldBeOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is not empty but parentheses start on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - param ( - [Parameter()] - [string]$someString - ) - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + param ( + [Parameter()] + [string]$someString + ) + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParamBlockNotEmptyParenthesesShouldBeOnNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParamBlock is not empty and parentheses start on the next line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - param - ( - [Parameter()] - [string]$someString - ) - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + param + ( + [Parameter()] + [string]$someString + ) + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } Context 'When ParamBlock is empty and parentheses are empty' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - param () - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + param () + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-ParameterBlockMandatoryNamedArgument.Tests.ps1 b/tests/Unit/Public/Measure-ParameterBlockMandatoryNamedArgument.Tests.ps1 index 8c5aa2b..e773d6a 100644 --- a/tests/Unit/Public/Measure-ParameterBlockMandatoryNamedArgument.Tests.ps1 +++ b/tests/Unit/Public/Measure-ParameterBlockMandatoryNamedArgument.Tests.ps1 @@ -1,399 +1,520 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -. $PSScriptRoot\Get-AstFromDefinition.ps1 + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-ParameterBlockMandatoryNamedArgument' { +Describe 'Measure-ParameterBlockMandatoryNamedArgument' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.NamedAttributeArgumentAst' - $ruleName = 'Measure-ParameterBlockMandatoryNamedArgument' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.NamedAttributeArgumentAst' + $script:ruleName = 'Measure-ParameterBlockMandatoryNamedArgument' + } } Context 'When Mandatory is included and set to $false' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - [Parameter(Mandatory = $false)] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - - $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [Parameter(Mandatory = $false)] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + + $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory is lower-case' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - [Parameter(mandatory = $true)] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - - $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [Parameter(mandatory = $true)] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + + $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory does not include an explicit argument' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - [Parameter(Mandatory)] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - - $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [Parameter(Mandatory)] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + + $record = Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory is correctly written' { It 'Should not write a record' { - $definition = ' - function Get-TargetResource - { - param ( - [Parameter(Mandatory = $true)] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [Parameter(Mandatory = $true)] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + Measure-ParameterBlockMandatoryNamedArgument -NamedAttributeArgumentAst $mockAst[0] | Should -BeNullOrEmpty + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-ParameterBlockMandatoryNamedArgument" } - $ruleName = "$($script:ModuleName)\Measure-ParameterBlockMandatoryNamedArgument" } Context 'When Mandatory is included and set to $false' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $false)] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $false)] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory is lower-case' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(mandatory = $true)] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(mandatory = $true)] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory does not include an explicit argument' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory)] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory)] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory is incorrectly written and other parameters are used' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $false, ParameterSetName = "SetName")] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $false, ParameterSetName = "SetName")] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } Context 'When Mandatory is correctly written' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $true)] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $true)] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When Mandatory is not present and other parameters are' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(HelpMessage = "HelpMessage")] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(HelpMessage = "HelpMessage")] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When Mandatory is correctly written and other parameters are listed' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $true, ParameterSetName = "SetName")] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $true, ParameterSetName = "SetName")] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When Mandatory is correctly written and not placed first' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(ParameterSetName = "SetName", Mandatory = $true)] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(ParameterSetName = "SetName", Mandatory = $true)] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When Mandatory is correctly written and other attributes are listed' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $true)] - [ValidateSet("one", "two")] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet("one", "two")] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When Mandatory Attribute NamedParameter is in a class' { It 'Should not return any records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - [DscResource()] - class Resource - { - [DscProperty(Key)] - [string] $DscKeyString + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [DscProperty(Mandatory)] - [int] $DscNum - - [Resource] Get() + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + [DscResource()] + class Resource { - return $this - } + [DscProperty(Key)] + [string] $DscKeyString - [void] Set() - { - } + [DscProperty(Mandatory)] + [int] $DscNum - [bool] Test() - { - return $true + [Resource] Get() + { + return $this + } + + [void] Set() + { + } + + [bool] Test() + { + return $true + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } Context 'When Mandatory Attribute NamedParameter is in script block in a property in a class' { It 'Should return records for NameParameter in the ScriptBlock only' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - [DscResource()] - class Resource - { - [DscProperty(Key)] - [string] $DscKeyString - - [DscProperty(Mandatory)] - [int] $DscNum + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [Resource] Get() + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + [DscResource()] + class Resource { - return $this + [DscProperty(Key)] + [string] $DscKeyString + + [DscProperty(Mandatory)] + [int] $DscNum + + [Resource] Get() + { + return $this + } + + [void] Set() + { + } + + [bool] Test() + { + return $true + } + + [Func[Int,Int]] $MakeInt = { + [Parameter(Mandatory=$true)] + param + ( + [Parameter(Mandatory)] + [int] $Input + ) + $Input * 2 + } } + ' - [void] Set() - { - } + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } + } + } - [bool] Test() - { - return $true - } + Context 'When Mandatory is incorrectly set on two parameters' { + It 'Should write the correct records' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [Func[Int,Int]] $MakeInt = { - [Parameter(Mandatory=$true)] + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { param ( [Parameter(Mandatory)] - [int] $Input + $ParameterName1, + + [Parameter(Mandatory = $false)] + $ParameterName2 ) - $Input * 2 } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName - } - } - - Context 'When Mandatory is incorrectly set on two parameters' { - It 'Should write the correct records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory)] - $ParameterName1, - - [Parameter(Mandatory = $false)] - $ParameterName2 - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 2 - $record[0].Message | Should -Be $localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat - $record[1].Message | Should -Be $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 2 + $record[0].Message | Should -Be $script:localizedData.ParameterBlockParameterMandatoryAttributeWrongFormat + $record[1].Message | Should -Be $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + } } } Context 'When ParameterAttribute is set to $false and in lower-case' { It 'Should write the correct records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter(Mandatory = $true)] - $ParameterName1, - - [Parameter(mandatory = $false)] - $ParameterName2 - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter(Mandatory = $true)] + $ParameterName1, + + [Parameter(mandatory = $false)] + $ParameterName2 + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockNonMandatoryParameterMandatoryAttributeWrongFormat + $record.RuleName | Should -Be $ruleName + } } } } diff --git a/tests/Unit/Public/Measure-ParameterBlockParameterAttribute.Tests.ps1 b/tests/Unit/Public/Measure-ParameterBlockParameterAttribute.Tests.ps1 index cec9e00..8d17337 100644 --- a/tests/Unit/Public/Measure-ParameterBlockParameterAttribute.Tests.ps1 +++ b/tests/Unit/Public/Measure-ParameterBlockParameterAttribute.Tests.ps1 @@ -1,334 +1,447 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' -. $PSScriptRoot\Get-AstFromDefinition.ps1 + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-ParameterBlockParameterAttribute' { +Describe 'Measure-ParameterBlockParameterAttribute' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.ParameterAst' - $ruleName = 'Measure-ParameterBlockParameterAttribute' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.ParameterAst' + $script:ruleName = 'Measure-ParameterBlockParameterAttribute' + } } Context 'When ParameterAttribute is missing' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is not declared first' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - [ValidateSet("one", "two")] - [Parameter()] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeWrongPlace - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [ValidateSet("one", "two")] + [Parameter()] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeWrongPlace + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is in lower-case' { It 'Should write the correct record' { - $definition = ' - function Get-TargetResource - { - param ( - [parameter()] - $ParameterName - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeLowerCase - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [parameter()] + $ParameterName + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeLowerCase + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is written correctly' { It 'Should not write a record' { - $definition = ' - function Get-TargetResource - { - param ( - [Parameter()] - $ParameterName1, - - [Parameter(Mandatory = $true)] - $ParameterName2 - ) - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] | Should -BeNullOrEmpty - Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[1] | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-TargetResource + { + param ( + [Parameter()] + $ParameterName1, + + [Parameter(Mandatory = $true)] + $ParameterName2 + ) + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[0] | Should -BeNullOrEmpty + Measure-ParameterBlockParameterAttribute -ParameterAst $mockAst[1] | Should -BeNullOrEmpty + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-ParameterBlockParameterAttribute" } - $ruleName = "$($script:ModuleName)\Measure-ParameterBlockParameterAttribute" } Context 'When ParameterAttribute is missing' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is present' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter()] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter()] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When ParameterAttribute is not declared first' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [ValidateSet("one", "two")] - [Parameter()] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeWrongPlace - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [ValidateSet("one", "two")] + [Parameter()] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeWrongPlace + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is declared first' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter()] - [ValidateSet("one", "two")] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter()] + [ValidateSet("one", "two")] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When ParameterAttribute is in lower-case' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [parameter()] - $ParameterName - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeLowerCase - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [parameter()] + $ParameterName + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeLowerCase + $record.RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is written in the correct casing' { It 'Should not write a record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter()] - $ParameterName - ) - } - ' - - Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter()] + $ParameterName + ) + } + ' + + Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters | Should -BeNullOrEmpty + } } } Context 'When ParameterAttribute is missing from two parameters' { It 'Should write the correct records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - $ParameterName1, - - $ParameterName2 - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 2 - $record[0].Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record[1].Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record[0].RuleName | Should -Be $ruleName - $record[1].RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + $ParameterName1, + + $ParameterName2 + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 2 + $record[0].Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record[1].Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record[0].RuleName | Should -Be $ruleName + $record[1].RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is missing and in lower-case' { It 'Should write the correct records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - $ParameterName1, - - [parameter()] - $ParameterName2 - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 2 - $record[0].Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record[1].Message | Should -Be $localizedData.ParameterBlockParameterAttributeLowerCase - $record[0].RuleName | Should -Be $ruleName - $record[1].RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + $ParameterName1, + + [parameter()] + $ParameterName2 + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 2 + $record[0].Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record[1].Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeLowerCase + $record[0].RuleName | Should -Be $ruleName + $record[1].RuleName | Should -Be $ruleName + } } } Context 'When ParameterAttribute is missing from a second parameter' { It 'Should write the correct record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-TargetResource - { - param - ( - [Parameter()] - $ParameterName1, - - $ParameterName2 - ) - } - ' - - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-TargetResource + { + param + ( + [Parameter()] + $ParameterName1, + + $ParameterName2 + ) + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record.RuleName | Should -Be $ruleName + } } } Context 'When Parameter is part of a method in a class' { It 'Should not return any records' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - class Resource - { - [void] Get_TargetResource($ParameterName1,$ParameterName2) + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + class Resource { + [void] Get_TargetResource($ParameterName1,$ParameterName2) + { + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } Context 'When Parameter is part of a script block that is part of a property in a class' { It 'Should return records for the Parameter in the script block' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - class Resource - { - [void] Get_TargetResource($ParameterName1,$ParameterName2) - { - } + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [Func[Int,Int]] $MakeInt = { - [Parameter(Mandatory=$true)] - param - ( - [int] $Input - ) - $Input * 2 + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + class Resource + { + [void] Get_TargetResource($ParameterName1,$ParameterName2) + { + } + + [Func[Int,Int]] $MakeInt = { + [Parameter(Mandatory=$true)] + param + ( + [int] $Input + ) + $Input * 2 + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ParameterBlockParameterAttributeMissing - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ParameterBlockParameterAttributeMissing + $record.RuleName | Should -Be $ruleName + } } } } diff --git a/tests/Unit/Public/Measure-SwitchStatement.Tests.ps1 b/tests/Unit/Public/Measure-SwitchStatement.Tests.ps1 index 0d0bf57..4cef2b8 100644 --- a/tests/Unit/Public/Measure-SwitchStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-SwitchStatement.Tests.ps1 @@ -1,95 +1,151 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -. $PSScriptRoot\Get-AstFromDefinition.ps1 + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force -Describe 'Measure-SwitchStatement' { + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-SwitchStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.SwitchStatementAst' - $ruleName = 'Measure-SwitchStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.SwitchStatementAst' + $script:ruleName = 'Measure-SwitchStatement' + } } Context 'When Switch-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) { - 1 - { - ''one'' + $definition = ' + function Get-Something + { + $value = 1 + + switch ($value) { + 1 + { + ''one'' + } } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Switch-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) - { 1 - { - ''one'' + $definition = ' + function Get-Something + { + $value = 1 + + switch ($value) + { 1 + { + ''one'' + } } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Switch-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) + $definition = ' + function Get-Something { + $value = 1 - 1 + switch ($value) { - ''one'' + + 1 + { + ''one'' + } } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-SwitchStatement -SwitchStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } @@ -97,123 +153,151 @@ Describe 'Measure-SwitchStatement' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-SwitchStatement" } - $ruleName = "$($script:ModuleName)\Measure-SwitchStatement" } Context 'When Switch-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) { - 1 - { - ''one'' + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $value = 1 + + switch ($value) { + 1 + { + ''one'' + } } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } # Regression test. Context 'When Switch-statement has an opening brace on the same line, and also has a clause with an opening brace on the same line' { It 'Should write only one error record, and the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) { - 1 { ''one'' } + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $value = 1 + + switch ($value) { + 1 { ''one'' } + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Switch-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) - { 1 - { - ''one'' + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $value = 1 + + switch ($value) + { 1 + { + ''one'' + } } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Switch-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $value = 1 - 1 + switch ($value) { - ''one'' + + 1 + { + ''one'' + } } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.SwitchStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Switch-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $value = 1 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - switch ($value) + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - 1 + $value = 1 + + switch ($value) { - ''one'' + 1 + { + ''one'' + } } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-TryStatement.Tests.ps1 b/tests/Unit/Public/Measure-TryStatement.Tests.ps1 index b6ca388..abc41fd 100644 --- a/tests/Unit/Public/Measure-TryStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-TryStatement.Tests.ps1 @@ -1,190 +1,270 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-TryStatement' { +Describe 'Measure-TryStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.TryStatementAst' - $ruleName = 'Measure-TryStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.TryStatementAst' + $script:ruleName = 'Measure-TryStatement' + } } Context 'When Try-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { - throw + try { + $value = 1 + } + catch + { + throw + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TryStatement -TryStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TryStatement -TryStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Try-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try - { $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something { - throw + try + { $value = 1 + } + catch + { + throw + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TryStatement -TryStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TryStatement -TryStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Try-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - try - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $value = 1 - } - catch + $definition = ' + function Get-Something { - throw + try + { + + $value = 1 + } + catch + { + throw + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TryStatement -TryStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TryStatement -TryStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } - } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-TryStatement" } - $ruleName = "$($script:ModuleName)\Measure-TryStatement" } Context 'When Try-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - throw + try { + $value = 1 + } + catch + { + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Try-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try - { $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - throw + try + { $value = 1 + } + catch + { + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Try-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $value = 1 - } - catch + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - throw + try + { + + $value = 1 + } + catch + { + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.TryStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Try-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - try - { - $value = 1 - } - catch + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - throw + try + { + $value = 1 + } + catch + { + throw + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } } diff --git a/tests/Unit/Public/Measure-TypeDefinition.Tests.ps1 b/tests/Unit/Public/Measure-TypeDefinition.Tests.ps1 index c36e95f..b0b252a 100644 --- a/tests/Unit/Public/Measure-TypeDefinition.Tests.ps1 +++ b/tests/Unit/Public/Measure-TypeDefinition.Tests.ps1 @@ -1,74 +1,131 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} -Describe 'Measure-TypeDefinition' { +Describe 'Measure-TypeDefinition' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.TypeDefinitionAst' - $ruleName = 'Measure-TypeDefinition' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.TypeDefinitionAst' + $script:ruleName = 'Measure-TypeDefinition' + } } Context 'Enum' { Context 'When Enum has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - enum Test { - Good - Bad - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + enum Test { + Good + Bad + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Enum Opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - enum Test - { Good - Bad - } - ' - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + enum Test + { Good + Bad + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Enum opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - enum Test - { - - Good - Bad - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + enum Test + { + + Good + Bad + } + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } @@ -76,60 +133,72 @@ Describe 'Measure-TypeDefinition' { Context 'Class' { Context 'When Class has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - class Test { - [int] $Good - [Void] Bad() - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + class Test { + [int] $Good + [Void] Bad() + { + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Class Opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - class Test - { [int] $Good - [Void] Bad() - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + class Test + { [int] $Good + [Void] Bad() + { + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Class opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - class Test - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [int] $Good - [Void] Bad() + $definition = ' + class Test { + + [int] $Good + [Void] Bad() + { + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-TypeDefinition -TypeDefinitionAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } @@ -137,59 +206,80 @@ Describe 'Measure-TypeDefinition' { Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-TypeDefinition" } - $ruleName = "$($script:ModuleName)\Measure-TypeDefinition" } Context 'Enum' { Context 'When Enum has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - enum Test { - Good - Bad - } - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + enum Test { + Good + Bad + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Enum Opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - enum Test - { Good - Bad + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + enum Test + { Good + Bad + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName } - ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName } } Context 'When Enum opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - enum Test - { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Good - Bad - } - ' + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + enum Test + { - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + Good + Bad + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.EnumOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } @@ -197,57 +287,69 @@ Describe 'Measure-TypeDefinition' { Context 'Class' { Context 'When Class has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - class Test { - [int] $Good - [Void] Bad() - { - } - } - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + class Test { + [int] $Good + [Void] Bad() + { + } + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Class Opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - class Test - { [int] $Good - [Void] Bad() - { - } - } - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + class Test + { [int] $Good + [Void] Bad() + { + } + } + ' + + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When Class opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - class Test - { - - [int] $Good - [Void] Bad() - { - } - } - ' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + class Test + { + + [int] $Good + [Void] Bad() + { + } + } + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.ClassOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } diff --git a/tests/Unit/Public/Measure-WhileStatement.Tests.ps1 b/tests/Unit/Public/Measure-WhileStatement.Tests.ps1 index 1e42bca..ddd70ee 100644 --- a/tests/Unit/Public/Measure-WhileStatement.Tests.ps1 +++ b/tests/Unit/Public/Measure-WhileStatement.Tests.ps1 @@ -1,175 +1,256 @@ -$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path -$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) - }).BaseName -$script:ModuleName = $ProjectName +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () -. $PSScriptRoot\Get-AstFromDefinition.ps1 +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.AnalyzerRules' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + $ModuleUnderTest = Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -PassThru + $script:modulePath = $ModuleUnderTest.Path -$ModuleUnderTest = Import-Module $ProjectName -PassThru -$localizedData = &$ModuleUnderTest { $Script:LocalizedData } -$modulePath = $ModuleUnderTest.Path + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\..\TestHelpers\CommonTestHelper.psm1') -Describe 'Measure-WhileStatement' { + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'Measure-WhileStatement' -Tag 'Public' { Context 'When calling the function directly' { BeforeAll { - $astType = 'System.Management.Automation.Language.WhileStatementAst' - $ruleName = 'Measure-WhileStatement' + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:astType = 'System.Management.Automation.Language.WhileStatementAst' + $script:ruleName = 'Measure-WhileStatement' + } } Context 'When While-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - while ($i -gt 0) { - $i-- + $definition = ' + function Get-Something + { + $i = 10 + + while ($i -gt 0) { + $i-- + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When While-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $definition = ' + function Get-Something + { + $i = 10 - while ($i -gt 0) - { $i-- + while ($i -gt 0) + { $i-- + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When While-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $definition = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - while ($i -gt 0) + $definition = ' + function Get-Something { + $i = 10 - $i-- + while ($i -gt 0) + { + + $i-- + } } - } - ' - - $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType - $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] - ($record | Measure-Object).Count | Should -Be 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + ' + + $mockAst = Get-AstFromDefinition -ScriptDefinition $definition -AstType $astType + $record = Measure-WhileStatement -WhileStatementAst $mockAst[0] + ($record | Measure-Object).Count | Should -Be 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } } Context 'When calling PSScriptAnalyzer' { BeforeAll { - $invokeScriptAnalyzerParameters = @{ - CustomRulePath = $modulePath + InModuleScope -Parameters @{ + ModuleName = $script:moduleName + ModulePath = $modulePath + } -ScriptBlock { + Set-StrictMode -Version 1.0 + + $script:invokeScriptAnalyzerParameters = @{ + CustomRulePath = $modulePath + } + + $script:ruleName = "$ModuleName\Measure-WhileStatement" } - $ruleName = "$($script:ModuleName)\Measure-WhileStatement" } Context 'When While-statement has an opening brace on the same line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 10 - while ($i -gt 0) { - $i-- + while ($i -gt 0) { + $i-- + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceNotOnSameLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceNotOnSameLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When While-statement opening brace is not followed by a new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - while ($i -gt 0) - { $i-- + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something + { + $i = 10 + + while ($i -gt 0) + { $i-- + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When While-statement opening brace is followed by more than one new line' { It 'Should write the correct error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - while ($i -gt 0) + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { + $i = 10 - $i-- + while ($i -gt 0) + { + + $i-- + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - ($record | Measure-Object).Count | Should -BeExactly 1 - $record.Message | Should -Be $localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine - $record.RuleName | Should -Be $ruleName + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + ($record | Measure-Object).Count | Should -BeExactly 1 + $record.Message | Should -Be $script:localizedData.WhileStatementOpeningBraceShouldBeFollowedByOnlyOneNewLine + $record.RuleName | Should -Be $ruleName + } } } Context 'When While-statement follows style guideline' { It 'Should not write an error record' { - $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' - function Get-Something - { - $i = 10 + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - while ($i -gt 0) + $invokeScriptAnalyzerParameters['ScriptDefinition'] = ' + function Get-Something { - $i-- + $i = 10 + + while ($i -gt 0) + { + $i-- + } } - } - ' + ' - $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters - $record | Should -BeNullOrEmpty + $record = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters + $record | Should -BeNullOrEmpty + } } } }