test/Invoke-DTWBeautifyScriptTests.ps1
<#
.SYNOPSIS Runs PowerShell beautifier testing process .DESCRIPTION Runs PowerShell beautifier testing process: - takes all script files in 1_Input_Bad, - processes each file with beautifier, outputting to 2_Output_Test - compares files in 2_Output_Test with correct result file in 3_Output_Correct - if files aren't the same, displays diff results in shell or user diff viewer. To use a diff utility besides Compare-Object, specify a valid diff utility EXE path in the variable $DTW_PS_Beautifier_DiffViewer. You could specify this in your $profile (if you run this a lot) or specify it once in the shell before running the test script. There are a lot more details; see script source and documentation on Github for more information. .PARAMETER SkipModuleReload Skips reloading the PowerShell-Beautifier module. If you aren't making beautifier code changes but have made changes to the input bad and/or output correct files and want to quickly retest without reloading module, specify this. .PARAMETER Quiet If specified: - only output text if errors are found - when terminating script, return $true if all tests passed else $false #> #region Script parameters param( [Parameter(Mandatory = $false)] [switch]$SkipModuleReload, [Parameter(Mandatory = $false)] [switch]$Quiet ) #endregion Set-StrictMode -Version 2 <# Some additional notes: First off - if you are reading this: THANK YOU for your interest in this project! There are 3 folders to know about: 1_Input_Bad - in the repo. Has example of files with bad formatting to be fixed. 2_Output_Test - NOT in repo, created by test process. Stores files from 1_Input_Bad that have been processed by beautifier. 3_Output_Correct - in the repo. Contains the files found in 1_Input_Bad that have the correct formatting (hand-edited). Here is how this test script works: 1. Find every file under 1_Input_Bad (except Whitespace\Indentation.ps1*) 2. For each file, run the beautifier on the input/bad file and output the result to the 2_Output_Test folder using the sub-folder name and test script name. 3. For the newly created file in 2_Output_Test, compare it with file under 3_Output_Correct with the sub-folder name and test script name. - processes each file with beautifier, outputting to 2_Output_Test - compares files in 2_Output_Test with correct result file in 3_Output_Correct - if files aren't the same, displays diff results in shell or user diff viewer. Whitespace\Indentation.ps1 is processed differently. It is run three times, each time specifying a different indent step: 2 spaces, 4 spaces and tabs. For each of these different indentation tests, the output test result files are compared with these existing output correct files in folder 3_Output_Correct\Whitespace: - Indentation_2space.ps1 - Indentation_4space.ps1 - Indentation_tab.ps1. ONE OTHER THING TO KNOW: If a result file in 2_Output_Test does not match the corresponding file in folder 3_Output_Correct, a diff is launched to show the difference to the user. If you don't make any changes, the test script will use the PowerShell cmdlet Compare-Object and output the results in the console. However, if you want to use a different diff utility, especially a visual diff tool like ExamDiff, you can enable this by setting a variable named $DTW_PS_Beautifier_DiffViewer to the path of the utility, i.e. $DTW_PS_Beautifier_DiffViewer = 'C:\Program Files\ExamDiff Pro\ExamDiff.exe' PLEASE DON'T set this value directly within your copy of the test script in the event you ever want to push changes back to the project. (I'm sure others will have different utilities they prefer.) So instead you can set that variable $DTW_PS_Beautifier_DiffViewer in your $profile or in your shell right before running the test script. #> #region Function: Invoke-FileDiff <# .SYNOPSIS Launches diff for 2 files. Either uses Compare-Object or diff editor if variable defined and valid. .DESCRIPTION Launches diff for 2 files. If the user has specified a file system path for the variable DTW_PS_Beautifier_DiffViewer, this is assumed to be an EXE and that is used. If that hasn't been defined, diffs with Compare-Object. Rather than edit this file to fill in a path for variable $DTW_PS_Beautifier_DiffViewer that is specific to your machine (it will be different for different users), this can be specified in your profile or in the shell right before running this test script. .PARAMETER Path1 Path to first file. .PARAMETER Path2 Path to second file. #> function Invoke-FileDiff { #region Function parameters [CmdletBinding()] param( [Parameter(Mandatory = $true,ValueFromPipeline = $false)] [ValidateNotNullOrEmpty()] [string]$Path1, [Parameter(Mandatory = $true,ValueFromPipeline = $false)] [ValidateNotNullOrEmpty()] [string]$Path2 ) #endregion process { #region Parameter validation #region $Path1 must exist if ($false -eq (Test-Path -Path $Path1)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: file not found: $Path1" return } #endregion # make sure we have the full path $Path1 = (Resolve-Path -Path $Path1).Path #region $Path1 must be a file, not a folder if ($true -eq ((Get-Item -Path $Path1).PSIsContainer)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: this is a folder, not a file: $Path1" return } #endregion #region $Path2 must exist if ($false -eq (Test-Path -Path $Path2)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: file not found: $Path2" return } #endregion # make sure we have the full path $Path2 = (Resolve-Path -Path $Path2).Path #region $Path2 must be a file, not a folder if ($true -eq ((Get-Item -Path $Path2).PSIsContainer)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: this is a folder, not a file: $Path2" return } #endregion #endregion # if user has defined the path of a diff viewer in $DTW_PS_Beautifier_DiffViewer # then use that utility otherwise use Compare-Object if ((Get-ChildItem -Path variable: | Where-Object { $_.Name -eq 'DTW_PS_Beautifier_DiffViewer' }) -and ($null -ne $DTW_PS_Beautifier_DiffViewer) -and ($true -eq (Test-Path -Path $DTW_PS_Beautifier_DiffViewer))) { [string]$Cmd = $DTW_PS_Beautifier_DiffViewer [string[]]$Params = $Path1,$Path2 & $Cmd $Params } else { $File1Content = Get-Content -Path $Path1 -Encoding (Get-FileEncodingSystemProviderNameFromTypeName -Name ((Get-FileEncoding $Path1).EncodingName)) $File2Content = Get-Content -Path $Path2 -Encoding (Get-FileEncodingSystemProviderNameFromTypeName -Name ((Get-FileEncoding $Path2).EncodingName)) Compare-Object $File1Content $File2Content -CaseSensitive | ForEach-Object { Write-Output " $($_.InputObject + ' ' + $_.SideIndicator)" } } } } #endregion #region Function: Test-ProcessFileCompareOutputTestCorrect <# .SYNOPSIS Runs a full beautify test for a single file. .DESCRIPTION Runs a full beautify test for a single file. Takes the file $InputBadPath, runs through Invoke-PrettifyScript saving result to $OutputTestPath. Then compares files contents at $OutputTestPath and $OutputCorrectPath; if not the same, launches diff. .PARAMETER InputBadPath Path to source bad file. .PARAMETER OutputTestPath Path to output result file - result of InputBadPath run through beautifier. .PARAMETER OutputCorrectPath Path to output correct file - file with correct results. #> function Test-ProcessFileCompareOutputTestCorrect { #region Function parameters [CmdletBinding()] param( [Parameter(Mandatory = $true,ValueFromPipeline = $false)] [ValidateNotNullOrEmpty()] [string]$InputBadPath, [Parameter(Mandatory = $true,ValueFromPipeline = $false)] [ValidateNotNullOrEmpty()] [string]$OutputTestPath, [Parameter(Mandatory = $true,ValueFromPipeline = $false)] [ValidateNotNullOrEmpty()] [string]$OutputCorrectPath, [Parameter(Mandatory = $false)] $IndentText ) #endregion process { #region Parameter validation # only $InputBadPath and $OutputCorrectPath must exist beforehand #region $InputBadPath must exist if ($false -eq (Test-Path -Path $InputBadPath)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: file not found: $InputBadPath" return } #endregion # make sure we have the full path $InputBadPath = (Resolve-Path -Path $InputBadPath).Path #region $InputBadPath must be a file, not a folder if ($true -eq ((Get-Item -Path $InputBadPath).PSIsContainer)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: this is a folder, not a file: $InputBadPath" return } #endregion #region $OutputCorrectPath must exist if ($false -eq (Test-Path -Path $OutputCorrectPath)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: file not found: $OutputCorrectPath" return } #endregion # make sure we have the full path $OutputCorrectPath = (Resolve-Path -Path $OutputCorrectPath).Path #region $OutputCorrectPath must be a file, not a folder if ($true -eq ((Get-Item -Path $OutputCorrectPath).PSIsContainer)) { Write-Error -Message "$($MyInvocation.MyCommand.Name):: this is a folder, not a file: $OutputCorrectPath" return } #endregion #endregion # if output test path file exists (test has been run before), remove it first if (Test-Path -Path $OutputTestPath) { Remove-Item -Path $OutputTestPath -Force } try { #region Specify parameters for Invoke-PrettifyScript call # note: we are specifying Unix standard LF as newline; for any machine pulling the test files # from git, the line endings will most likely be LF and not Windows CRLF # regardless, the file comparison functionality will ignore the LF / CRLF difference [hashtable]$Params = @{ SourcePath = $InputBadPath DestinationPath = $OutputTestPath NewLine = "LF" } # if $IndentText passed, add that to params if ($null -ne $IndentText) { $Params.IndentType = $IndentText } # finally: take the source file, run through beautifier and output in test folder if (!$Quiet) { Write-Output (' File: ' + (Split-Path -Path $InputBadPath -Leaf)) } #endregion Invoke-PrettifyScript @Params # compare result in test folder with correct folder if ($false -eq (Compare-FilesIncludingBOM -Path1 $OutputTestPath -Path2 $OutputCorrectPath)) { $script:AllTestsPassed = $false Write-Output ' Files do not match. Opening diff of these files:' Write-Output " $OutputTestPath" Write-Output " $OutputCorrectPath" Invoke-FileDiff -Path1 $OutputTestPath -Path2 $OutputCorrectPath } } catch { Write-Output 'An error occurred during processing files' Write-Output $_ } } } #endregion #region Get current script name and parent folder # path of current script parent folder [string]$ScriptFolder = Split-Path $MyInvocation.MyCommand.Path -Parent #endregion #region Re/load beautifier module # name of this module $ModuleName = 'PowerShell-Beautifier' # module is located one folder up [string]$ModulePath = Join-Path -Path (Split-Path $ScriptFolder -Parent) -ChildPath ($ModuleName + '.psd1') # make sure it's actually there if ($false -eq (Test-Path -Path $ModulePath)) { Write-Error "Beautifier module not found at path: $ModulePath" exit } # if module not loaded at all, load now if ($null -eq (Get-Module -Name $ModuleName)) { if (!$Quiet) { Write-Output "Importing beautifier module: $ModuleName" } Import-Module $ModulePath } else { # if doing development on the module, it is safest to force a reload of the module # each time the test script is run; by default we will do this unless the user # specified -SkipModuleReload - which makes sense if a user is only modified test files if ($SkipModuleReload) { if (!$Quiet) { Write-Output 'Skipping beautifier module reload' } } else { if (!$Quiet) { Write-Output 'Reloading beautifier module' } # use -Force to make sure reloaded if already in memory Import-Module $ModulePath -Force } } #endregion #region Get full paths to various testing folders [string]$InputBadFolderName = '1_Input_Bad' [string]$OutputTestFolderName = '2_Output_Test' [string]$CorrectFolderName = '3_Output_Correct' # this root path contains the before/bad files - the files with issues [string]$RootInputBadFolderPath = Join-Path -Path $ScriptFolder -ChildPath $InputBadFolderName # this root path contains the files produced by the cleanup tests; the files that need to be tested [string]$RootOutputTestFolderPath = Join-Path -Path $ScriptFolder -ChildPath $OutputTestFolderName # this root path contains the correct files - the files to compare with After_Test [string]$RootOutputCorrectFolderPath = Join-Path -Path $ScriptFolder -ChildPath $CorrectFolderName #create After_Test root folder if it does not exist; this folder should NOT exist in the repo if ($false -eq (Test-Path -Path $RootOutputTestFolderPath)) { $Results = New-Item -Path $RootOutputTestFolderPath -ItemType 'Directory' 2>&1 if ($? -eq $false) { Write-Error -Message "Error occurred attempting to create root test result folder: $RootOutputTestFolderPath" Write-Error -Message ($Results.ToString()) exit } } #endregion # assume all tests passed, set to false (in Test-ProcessFileCompareOutputTestCorrect) if one fails [bool]$AllTestsPassed = $true #region Main folder processing # $IndentationTestFileName is the name of the test file specifically used for # testing different indentation i.e. spaces vs. tabs; it will be processed # differently than the normal tests - which will use the default indentation # of 2 spaces - so identifying test file here in order to skip it in normal processing # FYI, this file is located in the Whitespace folder $IndentationTestFileName = 'Indentation.ps1' # test folders to process - list all of them here [string[]]$TestFolders = 'Case','CompleteFiles','FileEncoding','Rename','Whitespace' # this structure was originally designed to test just one or two folders at a time # (via script parameters); turns out running all scripts in all test folders is pretty # darn fast so there's no real need for the granularity; let's just run them all # however, if you really want you can easily override which folders by uncommenting # and modifying the following line with just a subset of the folders # [string[]]$TestFolders = 'Case','Rename' # loop through all specified test folders $TestFolders | ForEach-Object { $FolderName = $_ if (!$Quiet) { Write-Output ("Processing folder: $FolderName") } # process a single source folder $InputBadFolderPath = Join-Path -Path $RootInputBadFolderPath -ChildPath $FolderName $OutputTestFolderPath = Join-Path -Path $RootOutputTestFolderPath -ChildPath $FolderName $OutputCorrectFolderPath = Join-Path -Path $RootOutputCorrectFolderPath -ChildPath $FolderName # create individual test folder if does not exist; may not if first time running or test results purged if ($false -eq (Test-Path -Path $OutputTestFolderPath)) { $Results = New-Item -Path $OutputTestFolderPath -ItemType 'Directory' 2>&1 if ($? -eq $false) { Write-Error -Message "Error occurred attempting to create indvidual test result folder: $OutputTestFolderPath" Write-Error -Message ($Results.ToString()) exit } } # loop through all files in folder EXCEPT file named $IndentationTestFileName # skip that file, we will processing that file later with different indentation values Get-ChildItem -LiteralPath $InputBadFolderPath | Where-Object { $_.Name -ne $IndentationTestFileName } | ForEach-Object { $SourceFile = $_ $SourceFileName = $SourceFile.Name # paths to process $InputBadPath = $SourceFile.FullName $OutputTestPath = Join-Path -Path $OutputTestFolderPath -ChildPath $SourceFileName $OutputCorrectPath = Join-Path -Path $OutputCorrectFolderPath -ChildPath $SourceFileName Test-ProcessFileCompareOutputTestCorrect -InputBadPath $InputBadPath -OutputTestPath $OutputTestPath -OutputCorrectPath $OutputCorrectPath } } #endregion #region Process spaces/tabs indentation tests #only do spaces/tabs indentation tests if processing Whitespace folder tests if ($TestFolders -contains 'Whitespace') { # get source file $InputBadIndentationFile = Join-Path -Path $RootInputBadFolderPath -ChildPath ('Whitespace\' + $IndentationTestFileName) # this code could be a lot more elegant; in a rush to get this done # get destination test file paths for different cases $OutputTestIndentationFileTwoSpace = Join-Path -Path $RootOutputTestFolderPath -ChildPath 'Whitespace\Indentation_2space.ps1' $OutputTestIndentationFileFourspace = Join-Path -Path $RootOutputTestFolderPath -ChildPath 'Whitespace\Indentation_4space.ps1' $OutputTestIndentationFileTab = Join-Path -Path $RootOutputTestFolderPath -ChildPath 'Whitespace\Indentation_tab.ps1' # get correct file paths for different cases; same as OutputTest names but OutputCorrect folder $CorrectIndentationFileTwoSpace = $OutputTestIndentationFileTwoSpace.Replace($OutputTestFolderName,$CorrectFolderName) $CorrectIndentationFileFourspace = $OutputTestIndentationFileFourspace.Replace($OutputTestFolderName,$CorrectFolderName) $CorrectIndentationFileTab = $OutputTestIndentationFileTab.Replace($OutputTestFolderName,$CorrectFolderName) Test-ProcessFileCompareOutputTestCorrect -InputBadPath $InputBadIndentationFile -OutputTestPath $OutputTestIndentationFileTwoSpace -OutputCorrectPath $CorrectIndentationFileTwoSpace -IndentText TwoSpaces Test-ProcessFileCompareOutputTestCorrect -InputBadPath $InputBadIndentationFile -OutputTestPath $OutputTestIndentationFileFourspace -OutputCorrectPath $CorrectIndentationFileFourspace -IndentText FourSpaces Test-ProcessFileCompareOutputTestCorrect -InputBadPath $InputBadIndentationFile -OutputTestPath $OutputTestIndentationFileTab -OutputCorrectPath $CorrectIndentationFileTab -IndentText Tabs } #endregion #region Output success/failure message or, if Quiet, return $true if all passed else $false if ($Quiet) { # return $true if all tests passed, false otherwise $AllTestsPassed } else { if ($true -eq $AllTestsPassed) { Write-Output "`nAll tests passed - woo-hoo!`n" } else { Write-Output "`nTest failed!`n" } } #endregion |