From d124716196df0141d3653fc276ace9c43a56c1ac Mon Sep 17 00:00:00 2001 From: simwai <16225108+simwai@users.noreply.github.com> Date: Tue, 21 May 2024 22:32:03 +0200 Subject: [PATCH] Added unit tests --- powershell_tests/setup.Tests.ps1 | 151 +++++++++++++++++++++++++++++++ setup.ps1 | 51 +++++++---- 2 files changed, 184 insertions(+), 18 deletions(-) create mode 100644 powershell_tests/setup.Tests.ps1 diff --git a/powershell_tests/setup.Tests.ps1 b/powershell_tests/setup.Tests.ps1 new file mode 100644 index 000000000..a34facd0d --- /dev/null +++ b/powershell_tests/setup.Tests.ps1 @@ -0,0 +1,151 @@ +# Ensure the latest version of Pester is installed and imported +if (-not (Get-Module -ListAvailable -Name Pester | Where-Object { $_.Version -ge [version]"5.3.1" })) { + Install-Module -Name Pester -Force -Scope CurrentUser -SkipPublisherCheck +} + +Import-Module -Name Pester -MinimumVersion 5.3.1 + +# Describe block to contain all tests and setup +Describe "Setup and Tests" { + + BeforeAll { + # Construct the absolute path to setup.ps1 + $setupScriptPath = Join-Path -Path (Get-Location) -ChildPath "setup.ps1" + + # Check if the setup script exists + if (-Not (Test-Path -Path $setupScriptPath)) { + Write-Host "Error: setup.ps1 script not found at path: $setupScriptPath" + exit 1 + } + + # Load the script to test + . $setupScriptPath + } + + Context "Write-Log Tests" -Tag "Unit" { + It "should write INFO level log" { + $logFilePath = Join-Path $env:TEMP "script_log.txt" + Remove-Item $logFilePath -ErrorAction SilentlyContinue + + Write-Log -Message "Test Info Message" -Level "INFO" + + $logContent = Get-Content $logFilePath + $logContent | Should -Contain "INFO: Test Info Message" + } + + It "should write ERROR level log" { + $logFilePath = Join-Path $env:TEMP "script_log.txt" + Remove-Item $logFilePath -ErrorAction SilentlyContinue + + Write-Log -Message "Test Error Message" -Level "ERROR" + + $logContent = Get-Content $logFilePath + $logContent | Should -Contain "ERROR: Test Error Message" + } + } + + Context "Get-UserSelection Tests" -Tag "Unit" { + It "should handle valid input correctly" { + Mock Read-Host { return "A,B,C" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" + + $indices | Should -Be @(0, 1, 2) + } + + It "should return indices for selected options" { + Mock Read-Host { return "a,b" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options + + $indices | Should -Be @(0, 1) + } + + It "should return default choice if no input" { + Mock Read-Host { return "" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "C" + + $indices | Should -Be @(2) + } + + It "should handle mixed valid and invalid input correctly" { + Mock Read-Host { return "A,X,B,Y,C,Z" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" + + $indices | Should -Be @(0, 1, 2) + } + + It "should handle invalid input gracefully" { + Mock Read-Host { return "x,y,z" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" + + $indices | Should -Be @() + } + + It "should handle input without whitespace" { + Mock Read-Host { return "a,b,c" } + + $options = @("Option1", "Option2", "Option3") + $indices = Get-UserSelection -prompt "Select options" -options $options + + $indices | Should -Be @(0, 1, 2) + } + } + + Context "Exit-Script Tests" -Tag "Unit" { + BeforeAll { + # Set environment variables for the test + $global:OldVirtualPath = "C:\old\path" + $global:LogFilePath = "C:\path\to\logfile.log" + } + + BeforeEach { + Mock Write-Log {} + Mock Start-Process {} + Mock Read-Host { return "Y" } + + # Backup the original PATH + $global:OriginalPath = $env:PATH + } + + AfterEach { + # Restore the original PATH + $env:PATH = $OriginalPath + } + + It "should exit with the given exit code without waiting for key press" { + $exitCode = Exit-Script -exitCode 0 -isSubShell $true -waitForKeypress $false + $exitCode | Should -Be 0 + } + + It "should prompt to open log file on error" { + Exit-Script -exitCode 1 -isSubShell $true -waitForKeypress $false + Assert-MockCalled Read-Host -Exactly 1 + Assert-MockCalled Start-Process -Exactly 1 + } + + It "should restore the environment path if OldVirtualPath is set" { + # Set a different PATH to simulate the change + $env:PATH = "C:\new\path" + Exit-Script -exitCode 0 -isSubShell $true -waitForKeypress $false + $env:PATH | Should -Be "C:\old\path" + } + } + + Context "Get-PythonVersionTag Tests" -Tag "Unit" { + It "should return the correct Python version tag" { + Mock Invoke-Expression { param($cmd) return "cp39-win_amd64" } + + $tag = Get-PythonVersionTag + $tag | Should -Be "cp39-win_amd64" + } + } +} diff --git a/setup.ps1 b/setup.ps1 index 551331f3f..cc443fb20 100644 --- a/setup.ps1 +++ b/setup.ps1 @@ -14,6 +14,7 @@ function Write-Log { [string]$Message, [string]$Level = 'INFO' ) + switch ($Level) { 'INFO' { Write-Host $Message -ForegroundColor Green } 'WARNING' { Write-Host $Message -ForegroundColor Yellow } @@ -47,15 +48,20 @@ function Get-UserSelection { $_.Trim().ToUpper() } - # Convert each selection from letter to index - $indices = $selections | ForEach-Object { - if ($_ -match '^[A-Z]$') { - # Ensure the input is a single uppercase letter - [int][char]$_ - [int][char]'A' + # Convert each selection from letter to index and validate + $indices = @() + foreach ($selection in $selections) { + if ($selection -match '^[A-Z]$') { + $index = [int][char]$selection - [int][char]'A' + if ($index -ge 0 -and $index -lt $options.Length) { + $indices += $index + } + else { + Write-Log "Invalid input: $selection. Please enter letters within the valid range of options." -Level 'ERROR' + } } else { - Write-Log "Invalid input: $_. Please enter letters between A and Z." -Level 'ERROR' - continue + Write-Log "Invalid input: $selection. Please enter letters between A and Z." -Level 'ERROR' } } @@ -65,14 +71,14 @@ function Get-UserSelection { function Exit-Script { param ( [int]$exitCode, - [bool]$isSubShell = $true + [bool]$isSubShell = $true, + [bool]$waitForKeypress = $true ) if ($OldVirtualPath) { $env:PATH = $OldVirtualPath } - # Check if the script is exiting with an error and it's not a subshell if ($exitCode -ne 0 -and $isSubShell) { Write-Log "Script failed. Would you like to open the log file? (Y/N)" -Level 'PROMPT' $openLog = Read-Host @@ -81,25 +87,29 @@ function Exit-Script { } } - Write-Log "Press any key to exit..." - $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null - exit $exitCode + if ($waitForKeypress) { + Write-Log "Press any key to exit..." + $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null + } + + return $exitCode } -# Function to handle installation and conflict resolution -function Install-And-Resolve { +# Function to handle installation +function Install { param ([string]$InputPath) + if (-not $InputPath) { - Write-Log "ERROR: No input provided for installation." -Level 'ERROR' + Write-Log "No input provided for installation." -Level 'ERROR' Exit-Script -exitCode 1 } + Write-Log "Installing $InputPath..." $installCmd = if (Test-Path $InputPath) { $VenvPip + @('install', '-r', $InputPath) } else { $VenvPip + @('install', $InputPath) } $output = & $installCmd[0] $installCmd[1..$installCmd.Length] 2>&1 $output | Out-File $LogFilePath -Append if ($LASTEXITCODE -ne 0) { - Write-Log "Conflict detected, attempting to resolve..." -Level 'ERROR' - & $VenvPip[0] $VenvPip[1..$VenvPip.Length] 'check' | Out-File "conflicts.txt" + Write-Log "Conflict detected. Exiting now..." -Level 'ERROR' Exit-Script -exitCode 1 } } @@ -111,6 +121,11 @@ function Get-PythonVersionTag { return "$pythonVersion-$architecture" } +# Exit in test environment +if ($MyInvocation.InvocationName -ne $MyInvocation.MyCommand.Name) { + exit +} + # Check for admin privileges and elevate if necessary if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Log "Requesting administrative privileges..." -Level 'ERROR' @@ -179,7 +194,7 @@ foreach ($index in $selectedIndices) { $filePath = Join-Path $ProjectDir $RequirementFiles[$index] if (Test-Path $filePath) { - Install-And-Resolve $filePath + Install $filePath } else { Write-Log "Requirement file not found: $filePath" -Level 'ERROR'