Implemented the changes to pass the review, implemented consistent variable naming, adjusted unit tests

This commit is contained in:
simwai
2024-05-26 15:54:52 +02:00
parent 9c816045f1
commit 6174a49aa5
3 changed files with 148 additions and 229 deletions

View File

@@ -71,11 +71,6 @@ jobs:
run: | run: |
pytest --random-order --cov=freqtrade --cov=freqtrade_client --cov-config=.coveragerc pytest --random-order --cov=freqtrade --cov=freqtrade_client --cov-config=.coveragerc
- name: Run Pester tests with code coverage
shell: pwsh
run: |
Invoke-Pester -Path tests -EnableExit
- name: Coveralls - name: Coveralls
if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04') if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04')
env: env:
@@ -323,6 +318,15 @@ jobs:
run: | run: |
mypy freqtrade scripts tests mypy freqtrade scripts tests
- name: Run Pester tests (PowerShell)
run: |
Write-host $PSVersionTable.PSVersion.Major $PSVersionTable.PSRemotingProtocolVersion.Minor
Set-PSRepository psgallery -InstallationPolicy trusted
Install-Module -Name Pester -RequiredVersion 5.3.1 -Confirm:$false -Force
Invoke-Pester -Path "tests"
if ($Error[0].Fullyqualifiederrorid -eq 'PesterAssertionFailed') {exit 1}
shell: powershell
- name: Discord notification - name: Discord notification
uses: rjstone/discord-webhook-notify@v1 uses: rjstone/discord-webhook-notify@v1
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)

232
setup.ps1
View File

@@ -1,8 +1,7 @@
Clear-Host Clear-Host
# Set the log file path and initialize variables $Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $Global:LogFilePath = Join-Path $env:TEMP "script_log_$Timestamp.txt"
$Global:LogFilePath = Join-Path $env:TEMP "script_log_$timestamp.txt"
$RequirementFiles = @("requirements.txt", "requirements-dev.txt", "requirements-hyperopt.txt", "requirements-freqai.txt", "requirements-freqai-rl.txt", "requirements-plot.txt") $RequirementFiles = @("requirements.txt", "requirements-dev.txt", "requirements-hyperopt.txt", "requirements-freqai.txt", "requirements-freqai-rl.txt", "requirements-plot.txt")
$VenvName = ".venv" $VenvName = ".venv"
@@ -24,6 +23,7 @@ function Write-Log {
'ERROR' { Write-Host $Message -ForegroundColor Red } 'ERROR' { Write-Host $Message -ForegroundColor Red }
'PROMPT' { Write-Host $Message -ForegroundColor Cyan } 'PROMPT' { Write-Host $Message -ForegroundColor Cyan }
} }
"${Level}: $Message" | Out-File $LogFilePath -Append "${Level}: $Message" | Out-File $LogFilePath -Append
} }
@@ -36,8 +36,8 @@ function Get-UserSelection {
) )
Write-Log "$Prompt`n" -Level 'PROMPT' Write-Log "$Prompt`n" -Level 'PROMPT'
for ($i = 0; $i -lt $Options.Length; $i++) { for ($I = 0; $I -lt $Options.Length; $I++) {
Write-Log "$([char](65 + $i)). $($Options[$i])" -Level 'PROMPT' Write-Log "$([char](65 + $I)). $($Options[$I])" -Level 'PROMPT'
} }
if ($AllowMultipleSelections) { if ($AllowMultipleSelections) {
@@ -47,53 +47,53 @@ function Get-UserSelection {
Write-Log "`nSelect an option by typing the corresponding letter." -Level 'PROMPT' Write-Log "`nSelect an option by typing the corresponding letter." -Level 'PROMPT'
} }
$userInput = Read-Host [string]$UserInput = Read-Host
if ([string]::IsNullOrEmpty($userInput)) { if ([string]::IsNullOrEmpty($UserInput)) {
$userInput = $DefaultChoice $UserInput = $DefaultChoice
} }
if ($AllowMultipleSelections) { if ($AllowMultipleSelections) {
# Ensure $userInput is treated as a string and split it by commas $Selections = $UserInput.Split(',') | ForEach-Object {
$userInput = [string]$userInput
$selections = $userInput.Split(',') | ForEach-Object {
$_.Trim().ToUpper() $_.Trim().ToUpper()
} }
# Convert each selection from letter to index and validate $ErrorMessage = "Invalid input: $Selection. Please enter letters within the valid range of options."
$selectedIndices = @()
foreach ($selection in $selections) { # Convert each Selection from letter to Index and validate
if ($selection -match '^[A-Z]$') { $SelectedIndices = @()
$index = [int][char]$selection - [int][char]'A' foreach ($Selection in $Selections) {
if ($index -ge 0 -and $index -lt $Options.Length) { if ($Selection -match '^[A-Z]$') {
$selectedIndices += $index $Index = [int][char]$Selection - [int][char]'A'
if ($Index -ge 0 -and $Index -lt $Options.Length) {
$SelectedIndices += $Index
} }
else { else {
Write-Log "Invalid input: $selection. Please enter letters within the valid range of options." -Level 'ERROR' Write-Log $ErrorMessage -Level 'ERROR'
return -1 return -1
} }
} }
else { else {
Write-Log "Invalid input: $selection. Please enter letters between A and Z." -Level 'ERROR' Write-Log $ErrorMessage -Level 'ERROR'
return -1 return -1
} }
} }
return $selectedIndices return $SelectedIndices
} }
else { else {
# Convert the selection from letter to index and validate # Convert the Selection from letter to Index and validate
if ($userInput -match '^[A-Z]$') { if ($UserInput -match '^[A-Z]$') {
$selectedIndex = [int][char]$userInput - [int][char]'A' $SelectedIndex = [int][char]$UserInput - [int][char]'A'
if ($selectedIndex -ge 0 -and $selectedIndex -lt $Options.Length) { if ($SelectedIndex -ge 0 -and $SelectedIndex -lt $Options.Length) {
return $selectedIndex return $SelectedIndex
} }
else { else {
Write-Log "Invalid input: $userInput. Please enter a letter within the valid range of options." -Level 'ERROR' Write-Log "Invalid input: $UserInput. Please enter a letter within the valid range of options." -Level 'ERROR'
return -1 return -1
} }
} }
else { else {
Write-Log "Invalid input: $userInput. Please enter a letter between A and Z." -Level 'ERROR' Write-Log "Invalid input: $UserInput. Please enter a letter between A and Z." -Level 'ERROR'
return -1 return -1
} }
} }
@@ -105,9 +105,8 @@ function Exit-Script {
[bool]$WaitForKeypress = $true [bool]$WaitForKeypress = $true
) )
if ($Global:OldVirtualPath) { # Disable virtual environment
$env:PATH = $Global:OldVirtualPath deactivate
}
if ($ExitCode -ne 0) { if ($ExitCode -ne 0) {
Write-Log "Script failed. Would you like to open the log file? (Y/N)" -Level 'PROMPT' Write-Log "Script failed. Would you like to open the log file? (Y/N)" -Level 'PROMPT'
@@ -124,37 +123,18 @@ function Exit-Script {
return $ExitCode return $ExitCode
} }
# Function to install requirements
function Install-Requirements {
param ([string]$RequirementsPath)
if (-not $RequirementsPath) {
Write-Log "No requirements path provided for installation." -Level 'ERROR'
Exit-Script -ExitCode 1
}
Write-Log "Installing requirements from $RequirementsPath..."
$installCmd = if (Test-Path $RequirementsPath) { & $VenvPip install -r $RequirementsPath } else { & $VenvPip install $RequirementsPath }
$output = & $installCmd[0] $installCmd[1..$installCmd.Length] 2>&1
$output | Out-File $LogFilePath -Append
if ($LASTEXITCODE -ne 0) {
Write-Log "Conflict detected. Exiting now..." -Level 'ERROR'
Exit-Script -ExitCode 1
}
}
function Test-PythonExecutable { function Test-PythonExecutable {
param( param(
[string]$PythonExecutable [string]$PythonExecutable
) )
$pythonCmd = Get-Command $PythonExecutable -ErrorAction SilentlyContinue $PythonCmd = Get-Command $PythonExecutable -ErrorAction SilentlyContinue
if ($pythonCmd) { if ($PythonCmd) {
$command = "$($pythonCmd.Source) --version 2>&1" $Command = "$($PythonCmd.Source) --version 2>&1"
$versionOutput = Invoke-Expression $command $VersionOutput = Invoke-Expression $Command
if ($LASTEXITCODE -eq 0) { if ($LASTEXITCODE -eq 0) {
$version = $versionOutput | Select-String -Pattern "Python (\d+\.\d+\.\d+)" | ForEach-Object { $_.Matches.Groups[1].Value } $Version = $VersionOutput | Select-String -Pattern "Python (\d+\.\d+\.\d+)" | ForEach-Object { $_.Matches.Groups[1].Value }
Write-Log "Python version $version found using executable '$PythonExecutable'." Write-Log "Python version $Version found using executable '$PythonExecutable'."
return $true return $true
} }
else { else {
@@ -169,58 +149,35 @@ function Test-PythonExecutable {
} }
function Find-PythonExecutable { function Find-PythonExecutable {
$PythonExecutables = @("python", "python3.12", "python3.11", "python3.10", "python3.9", "python3", "C:\Users\$env:USERNAME\AppData\Local\Programs\Python\Python312\python.exe", "C:\Users\$env:USERNAME\AppData\Local\Programs\Python\Python311\python.exe", "C:\Users\$env:USERNAME\AppData\Local\Programs\Python\Python310\python.exe", "C:\Users\$env:USERNAME\AppData\Local\Programs\Python\Python39\python.exe", "C:\Python311\python.exe", "C:\Python310\python.exe", "C:\Python39\python.exe")
$pythonExecutables = @("python", "python3", "python3.9", "python3.10", "python3.11", "C:\Python39\python.exe", "C:\Python310\python.exe", "C:\Python311\python.exe")
foreach ($executable in $pythonExecutables) { foreach ($Executable in $PythonExecutables) {
if (Test-PythonExecutable -PythonExecutable $executable) { if (Test-PythonExecutable -PythonExecutable $Executable) {
return $executable return $Executable
} }
} }
return $null return $null
} }
# Function to get the list of requirements from a file
function Get-Requirements($file) {
$requirements = @()
$lines = Get-Content $file
foreach ($line in $lines) {
if ($line.StartsWith("-r ")) {
$nestedFile = $line.Substring(3).Trim()
$nestedFilePath = Join-Path (Split-Path $file -Parent) $nestedFile
if (Test-Path $nestedFilePath) {
$requirements += Get-Requirements $nestedFilePath
}
}
elseif (-not $line.StartsWith("#")) {
$requirements += $line
}
}
return $requirements
}
function Main { function Main {
"Starting the operations..." | Out-File $LogFilePath -Append
"Current directory: $(Get-Location)" | Out-File $LogFilePath -Append
# Exit on lower versions than Python 3.9 or when Python executable not found # Exit on lower versions than Python 3.9 or when Python executable not found
$pythonExecutable = Find-PythonExecutable $PythonExecutable = Find-PythonExecutable
if ($null -eq $pythonExecutable) { if ($null -eq $PythonExecutable) {
Write-Host "Error: No suitable Python executable found. Please ensure that Python 3.9 or higher is installed and available in the system PATH." Write-Host "Error: No suitable Python executable found. Please ensure that Python 3.9 or higher is installed and available in the system PATH."
Exit 1 Exit 1
} }
"Starting the < operations..." | Out-File $LogFilePath -Append
# Navigate to the project directory
Set-Location -Path $PSScriptRoot
"Current directory: $(Get-Location)" | Out-File $LogFilePath -Append
# Define the path to the Python executable in the virtual environment # Define the path to the Python executable in the virtual environment
$VenvPython = "$VenvDir\Scripts\python.exe" $VenvPython = "$VenvDir\Scripts\Activate.ps1"
# Check if the virtual environment exists, if not, create it # Check if the virtual environment exists, if not, create it
if (-Not (Test-Path $VenvPython)) { if (-Not (Test-Path $VenvPython)) {
Write-Log "Virtual environment not found. Creating virtual environment..." -Level 'ERROR' Write-Log "Virtual environment not found. Creating virtual environment..." -Level 'ERROR'
& $pythonExecutable -m venv "$VenvName" & $PythonExecutable -m venv $VenvName
if (-Not (Test-Path $VenvPython)) { if (-Not (Test-Path $VenvPython)) {
Write-Log "Failed to create virtual environment." -Level 'ERROR' Write-Log "Failed to create virtual environment." -Level 'ERROR'
Exit-Script -exitCode 1 Exit-Script -exitCode 1
@@ -228,106 +185,79 @@ function Main {
Write-Log "Virtual environment created successfully." Write-Log "Virtual environment created successfully."
} }
# Activate the virtual environment # Pull latest updates only if the repository state is not dirty
$Global:OldVirtualPath = $env:PATH Write-Log "Checking if the repository is clean..."
$env:PATH = "$VenvDir\Scripts;$env:PATH" $status = & "C:\Program Files\Git\cmd\git.exe" status --porcelain
if ($status) {
# Pull latest updates Write-Log "Repository is dirty. Skipping pull."
Write-Log "Pulling latest updates..."
& "C:\Program Files\Git\cmd\git.exe" pull | Out-File $LogFilePath -Append 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to pull updates from Git." -Level 'ERROR'
Exit-Script -exitCode 1
} }
else {
Write-Log "Pulling latest updates..."
& "C:\Program Files\Git\cmd\git.exe" pull | Out-File $LogFilePath -Append 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to pull updates from Git." -Level 'ERROR'
Exit-Script -exitCode 1
}
}
if (-not (Test-Path "$VenvDir\Lib\site-packages\talib")) { if (-not (Test-Path "$VenvDir\Lib\site-packages\talib")) {
# Install TA-Lib using the virtual environment's pip # Install TA-Lib using the virtual environment's pip
Write-Log "Installing TA-Lib using virtual environment's pip..." Write-Log "Installing TA-Lib using virtual environment's pip..."
& $VenvPython -m pip install --find-links=build_helpers\ --prefer-binary TA-Lib | Out-File $LogFilePath -Append 2>&1 python -m pip install --find-links=build_helpers\ --prefer-binary TA-Lib | Out-File $LogFilePath -Append 2>&1
} }
# Present options for requirement files # Present options for requirement files
$selectedIndices = Get-UserSelection -prompt "Select which requirement files to install:" -options $RequirementFiles -defaultChoice 'A' $SelectedIndices = Get-UserSelection -prompt "Select which requirement files to install:" -options $RequirementFiles -defaultChoice 'A'
# Cache the selected requirement files # Cache the selected requirement files
$selectedRequirementFiles = @() $SelectedRequirementFiles = @()
foreach ($index in $selectedIndices) { $PipInstallArguments = ""
if ($index -lt 0 -or $index -ge $RequirementFiles.Length) { foreach ($Index in $SelectedIndices) {
Write-Log "Invalid selection. Please try again using the allowed letters." -Level 'ERROR' $FilePath = Join-Path $PSScriptRoot $RequirementFiles[$Index]
continue if (Test-Path $FilePath) {
} $SelectedRequirementFiles += $FilePath
$PipInstallArguments += " -r $FilePath"
$filePath = Join-Path $PSScriptRoot $RequirementFiles[$index]
if (Test-Path $filePath) {
$selectedRequirementFiles += $filePath
} }
else { else {
Write-Log "Requirement file not found: $filePath" -Level 'ERROR' Write-Log "Requirement file not found: $FilePath" -Level 'ERROR'
Exit-Script -exitCode 1 Exit-Script -exitCode 1
} }
} }
if ($PipInstallArguments -ne "") {
# Merge the contents of the selected requirement files python -m pip install $PipInstallArguments
if ($selectedRequirementFiles.Count -gt 0) {
Write-Log "Merging selected requirement files..."
$mergedDependencies = @()
foreach ($file in $selectedRequirementFiles) {
$mergedDependencies += Get-Requirements $file
}
# Avoid duplicate dependencies
$mergedDependencies = $mergedDependencies | Select-Object -Unique
# Create a temporary directory
$tempDir = Join-Path $env:TEMP "freqtrade_requirements"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
# Create a temporary file with the merged dependencies
$tempFile = Join-Path $tempDir "requirements.txt"
$mergedDependencies | Out-File $tempFile
# Install the merged dependencies
Write-Log "Installing merged dependencies..."
& $VenvPython -m pip install -r $tempFile
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to install merged dependencies. Exiting now..." -Level 'ERROR'
Exit-Script -exitCode 1
}
# Remove the temporary directory
Remove-Item $tempDir -Recurse -Force
} }
# Install freqtrade from setup using the virtual environment's Python # Install freqtrade from setup using the virtual environment's Python
Write-Log "Installing freqtrade from setup..." Write-Log "Installing freqtrade from setup..."
$setupInstallCommand = "$VenvPython -m pip install -e ." python -m pip install -e . | Out-File $LogFilePath -Append 2>&1
Invoke-Expression $setupInstallCommand | Out-File $LogFilePath -Append 2>&1
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to install freqtrade." -Level 'ERROR' Write-Log "Failed to install freqtrade." -Level 'ERROR'
Exit-Script -exitCode 1 Exit-Script -exitCode 1
} }
$uiOptions = @("Yes", "No") $UiOptions = @("Yes", "No")
$installUI = Get-UserSelection -prompt "Do you want to install the freqtrade UI?" -options $uiOptions -defaultChoice 'B' -allowMultipleSelections $false $InstallUi = Get-UserSelection -prompt "Do you want to install the freqtrade UI?" -options $UiOptions -defaultChoice 'B' -allowMultipleSelections $false
if ($installUI -eq 0) { if ($InstallUi -eq 0) {
# User selected "Yes" # User selected "Yes"
# Install freqtrade UI using the virtual environment's install-ui command # Install freqtrade UI using the virtual environment's install-ui command
Write-Log "Installing freqtrade UI..." Write-Log "Installing freqtrade UI..."
& $VenvPython 'freqtrade', 'install-ui' | Out-File $LogFilePath -Append 2>&1 python 'freqtrade', 'install-ui' | Out-File $LogFilePath -Append 2>&1
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to install freqtrade UI." -Level 'ERROR' Write-Log "Failed to install freqtrade UI." -Level 'ERROR'
Exit-Script -exitCode 1 Exit-Script -exitCode 1
} }
} }
elseif ($installUI -eq 1) { elseif ($InstallUi -eq 1) {
# User selected "No" # User selected "No"
# Skip installing freqtrade UI # Skip installing freqtrade UI
Write-Log "Skipping freqtrade UI installation." Write-Log "Skipping freqtrade UI installation."
} }
else { else {
# Invalid selection # Invalid Selection
# Handle the error case # Handle the error case
Write-Log "Invalid selection for freqtrade UI installation." -Level 'ERROR' Write-Log "Invalid Selection for freqtrade UI installation." -Level 'ERROR'
Exit-Script -exitCode 1 Exit-Script -exitCode 1
} }

View File

@@ -1,8 +1,8 @@
# Ensure the specific version 5.3.1 of Pester is installed and imported # Ensure the specific version 5.3.1 of Pester is installed and imported
$requiredVersion = [version]"5.3.1" $RequiredVersion = [version]"5.3.1"
$installedModule = Get-Module -ListAvailable -Name Pester $InstalledModule = Get-Module -ListAvailable -Name Pester
if (-not ($installedModule) -or ($installedModule.Version -lt $requiredVersion)) { if (-not ($InstalledModule) -or ($InstalledModule.Version -lt $RequiredVersion)) {
Install-Module -Name Pester -RequiredVersion $requiredVersion -Force -Scope CurrentUser -SkipPublisherCheck Install-Module -Name Pester -RequiredVersion $RequiredVersion -Force -Scope CurrentUser -SkipPublisherCheck
} }
Import-Module -Name Pester -MinimumVersion 5.3.1 Import-Module -Name Pester -MinimumVersion 5.3.1
@@ -10,19 +10,20 @@ Import-Module -Name Pester -MinimumVersion 5.3.1
# Describe block to contain all tests and setup # Describe block to contain all tests and setup
Describe "Setup and Tests" { Describe "Setup and Tests" {
BeforeAll { BeforeAll {
# Construct the absolute path to setup.ps1 # Setup variables
$setupScriptPath = Join-Path $PSScriptRoot "..\setup.ps1" $SetupScriptPath = Join-Path $PSScriptRoot "..\setup.ps1"
$Global:LogFilePath = Join-Path $env:TEMP "script_log.txt"
# Check if the setup script exists # Check if the setup script exists
if (-Not (Test-Path -Path $setupScriptPath)) { if (-Not (Test-Path -Path $SetupScriptPath)) {
Write-Host "Error: setup.ps1 script not found at path: $setupScriptPath" Write-Host "Error: setup.ps1 script not found at path: $SetupScriptPath"
exit 1 exit 1
} }
# Mock main to prevent it from running # Mock main to prevent it from running
Mock Main {} Mock Main {}
. $setupScriptPath . $SetupScriptPath
} }
Context "Write-Log Tests" -Tag "Unit" { Context "Write-Log Tests" -Tag "Unit" {
@@ -30,104 +31,104 @@ Describe "Setup and Tests" {
Remove-Item $Global:LogFilePath -ErrorAction SilentlyContinue Remove-Item $Global:LogFilePath -ErrorAction SilentlyContinue
Write-Log -Message "Test Info Message" -Level "INFO" Write-Log -Message "Test Info Message" -Level "INFO"
$Global:LogFilePath | Should -Exist $Global:LogFilePath | Should -Exist
$logContent = Get-Content $Global:LogFilePath
$logContent | Should -Contain "INFO: Test Info Message" $LogContent = Get-Content $Global:LogFilePath
} $LogContent | Should -Contain "INFO: Test Info Message"
}
It "should write ERROR level log" { It "should write ERROR level log" {
$Global:LogFilePath = Join-Path $env:TEMP "script_log.txt"
Remove-Item $Global:LogFilePath -ErrorAction SilentlyContinue Remove-Item $Global:LogFilePath -ErrorAction SilentlyContinue
Write-Log -Message "Test Error Message" -Level "ERROR" Write-Log -Message "Test Error Message" -Level "ERROR"
$Global:LogFilePath | Should -Exist
$logContent = Get-Content $Global:LogFilePath $LogContent = Get-Content $Global:LogFilePath
$logContent | Should -Contain "ERROR: Test Error Message" $LogContent | Should -Contain "ERROR: Test Error Message"
} }
} }
Describe "Get-UserSelection Tests" { Describe "Get-UserSelection Tests" {
Context "Valid input" { Context "Valid input" {
It "Should return the correct index for a valid single selection" { It "Should return the correct index for a valid single selection" {
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
Mock Read-Host { return "B" } Mock Read-Host { return "B" }
$result = Get-UserSelection -prompt "Select an option" -options $options $Result = Get-UserSelection -prompt "Select an option" -options $Options
$result | Should -Be 1 $Result | Should -Be 1
} }
It "Should return the default choice when no input is provided" { It "Should return the default choice when no input is provided" {
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
Mock Read-Host { return "" } Mock Read-Host { return "" }
$result = Get-UserSelection -prompt "Select an option" -options $options -defaultChoice "C" $Result = Get-UserSelection -prompt "Select an option" -options $Options -defaultChoice "C"
$result | Should -Be 2 $Result | Should -Be 2
} }
} }
Context "Invalid input" { Context "Invalid input" {
It "Should return -1 for an invalid letter selection" { It "Should return -1 for an invalid letter selection" {
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
Mock Read-Host { return "X" } Mock Read-Host { return "X" }
$result = Get-UserSelection -prompt "Select an option" -options $options $Result = Get-UserSelection -prompt "Select an option" -options $Options
$result | Should -Be -1 $Result | Should -Be -1
} }
It "Should return -1 for a selection outside the valid range" { It "Should return -1 for a selection outside the valid range" {
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
Mock Read-Host { return "D" } Mock Read-Host { return "D" }
$result = Get-UserSelection -prompt "Select an option" -options $options $Result = Get-UserSelection -prompt "Select an option" -options $Options
$result | Should -Be -1 $Result | Should -Be -1
} }
It "Should return -1 for a non-letter input" { It "Should return -1 for a non-letter input" {
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
Mock Read-Host { return "1" } Mock Read-Host { return "1" }
$result = Get-UserSelection -prompt "Select an option" -options $options $Result = Get-UserSelection -prompt "Select an option" -options $Options
$result | Should -Be -1 $Result | Should -Be -1
} }
It "Should return -1 for mixed valid and invalid input" { It "Should return -1 for mixed valid and invalid input" {
Mock Read-Host { return "A,X,B,Y,C,Z" } Mock Read-Host { return "A,X,B,Y,C,Z" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" $Indices = Get-UserSelection -prompt "Select options" -options $Options -defaultChoice "A"
$indices | Should -Be -1 $Indices | Should -Be -1
} }
} }
Context "Multiple selections" { Context "Multiple selections" {
It "Should handle valid input correctly" { It "Should handle valid input correctly" {
Mock Read-Host { return "A,B,C" } Mock Read-Host { return "A,B,C" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" $Indices = Get-UserSelection -prompt "Select options" -options $Options -defaultChoice "A"
$indices | Should -Be @(0, 1, 2) $Indices | Should -Be @(0, 1, 2)
} }
It "Should return indices for selected options" { It "Should return indices for selected options" {
Mock Read-Host { return "a,b" } Mock Read-Host { return "a,b" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options $Indices = Get-UserSelection -prompt "Select options" -options $Options
$indices | Should -Be @(0, 1) $Indices | Should -Be @(0, 1)
} }
It "Should return default choice if no input" { It "Should return default choice if no input" {
Mock Read-Host { return "" } Mock Read-Host { return "" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "C" $Indices = Get-UserSelection -prompt "Select options" -options $Options -defaultChoice "C"
$indices | Should -Be @(2) $Indices | Should -Be @(2)
} }
It "Should handle invalid input gracefully" { It "Should handle invalid input gracefully" {
Mock Read-Host { return "x,y,z" } Mock Read-Host { return "x,y,z" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options -defaultChoice "A" $Indices = Get-UserSelection -prompt "Select options" -options $Options -defaultChoice "A"
$indices | Should -Be -1 $Indices | Should -Be -1
} }
It "Should handle input without whitespace" { It "Should handle input without whitespace" {
Mock Read-Host { return "a,b,c" } Mock Read-Host { return "a,b,c" }
$options = @("Option1", "Option2", "Option3") $Options = @("Option1", "Option2", "Option3")
$indices = Get-UserSelection -prompt "Select options" -options $options $Indices = Get-UserSelection -prompt "Select options" -options $Options
$indices | Should -Be @(0, 1, 2) $Indices | Should -Be @(0, 1, 2)
} }
} }
} }
@@ -137,47 +138,31 @@ Describe "Setup and Tests" {
Mock Write-Log {} Mock Write-Log {}
Mock Start-Process {} Mock Start-Process {}
Mock Read-Host { return "Y" } 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" { It "should exit with the given exit code without waiting for key press" {
$exitCode = Exit-Script -exitCode 0 -isSubShell $true -waitForKeypress $false $ExitCode = Exit-Script -ExitCode 0 -isSubShell $true -waitForKeypress $false
$exitCode | Should -Be 0 $ExitCode | Should -Be 0
} }
It "should prompt to open log file on error" { It "should prompt to open log file on error" {
Exit-Script -exitCode 1 -isSubShell $true -waitForKeypress $false Exit-Script -ExitCode 1 -isSubShell $true -waitForKeypress $false
Assert-MockCalled Read-Host -Exactly 1 Assert-MockCalled Read-Host -Exactly 1
Assert-MockCalled Start-Process -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"
$Global:OldVirtualPath = $env:PATH
Exit-Script -exitCode 0 -isSubShell $true -waitForKeypress $false
$env:PATH | Should -Be "C:\new\path"
}
} }
Context 'Find-PythonExecutable' { Context 'Find-PythonExecutable' {
It 'Returns the first valid Python executable' { It 'Returns the first valid Python executable' {
Mock Test-PythonExecutable { $true } -ParameterFilter { $PythonExecutable -eq 'python' } Mock Test-PythonExecutable { $true } -ParameterFilter { $PythonExecutable -eq 'python' }
$result = Find-PythonExecutable $Result = Find-PythonExecutable
$result | Should -Be 'python' $Result | Should -Be 'python'
} }
It 'Returns null if no valid Python executable is found' { It 'Returns null if no valid Python executable is found' {
Mock Test-PythonExecutable { $false } Mock Test-PythonExecutable { $false }
$result = Find-PythonExecutable $Result = Find-PythonExecutable
$result | Should -Be $null $Result | Should -Be $null
} }
} }
} }