tests/Client/CrossPlatform.Tests.ps1
|
<# Integration Test: Linux and macOS support (2.0.0.69) Checked from Windows, without Dataverse call: - the module folder does not depend on APPDATA, which Linux and macOS lack (a child pwsh without APPDATA); - src reads neither $env:TEMP nor $env:APPDATA (except Get-XrmAppDataPathInternal), and writes no "$variable\path" outside the Windows-only commands: .NET does not read "\" as a separator on Linux and macOS; - the Windows-only commands raise an error naming the feature. The display check of the interactive sign-in is in Client\Connection.Tests.ps1, the platform builds of Assemblies\Core in Client\ModuleLoad.Tests.ps1. #> . "$PSScriptRoot\..\_TestConfig.ps1"; $moduleScope = Get-Module PowerDataOps; $modulePath = (Resolve-Path "$PSScriptRoot\..\..\PowerDataOps.psd1").Path; $srcPath = Join-Path (Split-Path $modulePath) "src"; # ============================================================ # Module folder without APPDATA # ============================================================ Write-Section "Module folder without APPDATA (Linux, macOS)"; $command = "Import-Module '$modulePath' -DisableNameChecking 6>`$null | Out-Null; 'PDO-RESULT:' + (@{ ModuleFolder = `$Global:PowerDataOpsModuleFolderPath; LogFolder = `$Global:LogFolderPath; ApplicationData = [System.Environment]::GetFolderPath('ApplicationData') } | ConvertTo-Json -Compress)"; $previousAppData = $env:APPDATA; try { $env:APPDATA = $null; $output = & pwsh -NoProfile -Command $command 2>&1; } finally { $env:APPDATA = $previousAppData; } $resultLine = @($output | Where-Object { "$_" -like "PDO-RESULT:*" }) | Select-Object -Last 1; $probe = if ($resultLine) { "$resultLine".Substring("PDO-RESULT:".Length) | ConvertFrom-Json } else { $null }; if (-not $probe) { Write-Host ($output | Out-String) -ForegroundColor DarkGray; } Assert-Test "Module folder in the user's application data folder, not a relative path ($($probe.ModuleFolder))" { $null -ne $probe -and [System.IO.Path]::IsPathRooted($probe.ModuleFolder) -and $probe.ModuleFolder -eq [System.IO.Path]::Combine($probe.ApplicationData, "PowerDataOps"); }; Assert-Test "Log folder created there" { $null -ne $probe -and (Test-Path -LiteralPath $probe.LogFolder) }; Assert-Test "With APPDATA: APPDATA, as before" { (& $moduleScope { Get-XrmAppDataPathInternal }) -eq $env:APPDATA }; # ============================================================ # Static checks # ============================================================ Write-Section "Static checks on src"; # Windows-only commands, guarded by Assert-XrmWindowsInternal: their Windows paths stay $windowsOnlyFiles = @("Export-XrmConnectionToBrowser.ps1", "BrowserManager.ps1"); $environmentReads = [System.Collections.Generic.List[string]]::new(); $backslashPaths = [System.Collections.Generic.List[string]]::new(); foreach ($file in Get-ChildItem -LiteralPath $srcPath -Recurse -Filter "*.ps1") { $ast = [System.Management.Automation.Language.Parser]::ParseFile($file.FullName, [ref]$null, [ref]$null); foreach ($variable in $ast.FindAll({ param($node) $node -is [System.Management.Automation.Language.VariableExpressionAst] }, $true)) { if ($variable.VariablePath.UserPath -match '^env:(TEMP|TMP|APPDATA)$' -and $file.Name -ne "Get-XrmAppDataPathInternal.ps1") { $environmentReads.Add("$($file.Name):$($variable.Extent.StartLineNumber) $($variable.Extent.Text)"); } } if ($windowsOnlyFiles -contains $file.Name) { continue; } foreach ($string in $ast.FindAll({ param($node) $node -is [System.Management.Automation.Language.ExpandableStringExpressionAst] }, $true)) { if ($string.Value -match '\$(\w+|\{[^}]+\}|env:\w+|\([^)]*\))\\[\w.$]') { $backslashPaths.Add("$($file.Name):$($string.Extent.StartLineNumber) $($string.Extent.Text)"); } } } Assert-Test "No `$env:TEMP / `$env:APPDATA read (use [System.IO.Path]::GetTempPath() and Get-XrmAppDataPathInternal)" { $environmentReads.Count -eq 0 }; $environmentReads | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }; Assert-Test "No path written as `"`$variable\...`" (use [System.IO.Path]::Combine or Join-Path)" { $backslashPaths.Count -eq 0 }; $backslashPaths | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }; # ============================================================ # Windows-only commands # ============================================================ Write-Section "Windows-only commands"; Assert-Test "Windows: no error" { $null -eq (& $moduleScope { Assert-XrmWindowsInternal -Feature "Excel automation (COM)" }) }; $errorMessage = $null; try { & $moduleScope { Assert-XrmWindowsInternal -Feature "SolutionPackager.exe (.NET Framework)" -Alternative "Use pac solution unpack." -Platform Unix }; } catch { $errorMessage = $_.Exception.Message; } Assert-Test "Linux, macOS: error naming the feature and the alternative" { $errorMessage -eq "SolutionPackager.exe (.NET Framework) is only available on Windows. Use pac solution unpack." }; $guardedCommands = @("Read-XrmExcelSheet", "Write-XrmExcelSheet", "Export-XrmConnectionToBrowser", "Invoke-XrmSolutionPackager"); Assert-Test "Guarded: $($guardedCommands -join ', ')" { @($guardedCommands | Where-Object { (Get-Command -Name $_ -Module PowerDataOps).ScriptBlock.ToString() -match 'Assert-XrmWindowsInternal' }).Count -eq $guardedCommands.Count; }; Write-TestSummary; |