Skip to content
Closed

Test #37

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions run-ui-tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
[CmdletBinding()]
param(
[string]$ExecutablePath,
[string]$Filter = 'TestCategory=UI',
[string]$Logger = 'console;verbosity=normal',
[switch]$NoBuild,
[switch]$ListTests,
[switch]$ConfirmIsolatedProfile,
[string[]]$AdditionalDotNetArguments = @()
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$repositoryRoot = $PSScriptRoot
$testProject = Join-Path $repositoryRoot 'tests\FileManager.UiTests\FileManager.UiTests.csproj'

function Resolve-FileManagerExecutable {
param([string]$RequestedPath)

$candidates = [System.Collections.Generic.List[string]]::new()
if (-not [string]::IsNullOrWhiteSpace($RequestedPath)) {
# An explicit path is authoritative so a typo cannot silently test a different checkout build.
if (-not (Test-Path -LiteralPath $RequestedPath -PathType Leaf)) {
throw "The requested FileManager executable was not found: $RequestedPath"
}
return (Resolve-Path -LiteralPath $RequestedPath).Path
}
if (-not [string]::IsNullOrWhiteSpace($env:FILEMANAGER_UI_EXE)) {
# Preserve an explicit caller selection before trying checkout-relative or installed locations.
$candidates.Add($env:FILEMANAGER_UI_EXE)
}

# Repository-relative candidates make the runner portable across drive letters and checkout directories.
foreach ($relativePath in @(
'src\vcxproj\salamander\Debug_x64\salamand.exe',
'src\vcxproj\salamander\Release_x64\salamand.exe',
'src\vcxproj\salamander\Debug_x86\salamand.exe',
'src\vcxproj\salamander\Release_x86\salamand.exe'
)) {
$candidates.Add((Join-Path $repositoryRoot $relativePath))
}

foreach ($appPathKey in @(
'HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\salamand.exe',
'HKLM:\Software\Microsoft\Windows\CurrentVersion\App Paths\salamand.exe',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths\salamand.exe'
)) {
if (Test-Path -LiteralPath $appPathKey) {
# App Paths is the authoritative Windows registration when Salamander was installed outside this checkout.
$registeredPath = (Get-Item -LiteralPath $appPathKey).GetValue('')
if (-not [string]::IsNullOrWhiteSpace($registeredPath)) {
$candidates.Add($registeredPath)
}
}
}

foreach ($candidate in $candidates) {
if (-not [string]::IsNullOrWhiteSpace($candidate) -and
(Test-Path -LiteralPath $candidate -PathType Leaf)) {
return (Resolve-Path -LiteralPath $candidate).Path
}
}

throw 'salamand.exe was not found. Build Debug x64 or pass -ExecutablePath with the installed application path.'
}

if (-not $ConfirmIsolatedProfile) {
# The application writes HKCU configuration, so require an explicit acknowledgement before enabling the test gate.
throw 'UI tests modify the current Windows profile. Re-run with -ConfirmIsolatedProfile under a dedicated disposable test account.'
}
if (-not (Test-Path -LiteralPath $testProject -PathType Leaf)) {
throw "The UI test project was not found: $testProject"
}
if ($null -eq (Get-Command dotnet -ErrorAction SilentlyContinue)) {
throw 'dotnet was not found on PATH.'
}

$resolvedExecutable = Resolve-FileManagerExecutable $ExecutablePath
$previousIsolated = $env:FILEMANAGER_UI_ISOLATED
$previousExecutable = $env:FILEMANAGER_UI_EXE
$testExitCode = 1

try {
$env:FILEMANAGER_UI_ISOLATED = '1'
$env:FILEMANAGER_UI_EXE = $resolvedExecutable

$arguments = [System.Collections.Generic.List[string]]::new()
$arguments.Add('test')
$arguments.Add($testProject)
if ($NoBuild) {
# A no-build rerun must also avoid restore, which would regenerate ignored NuGet obj metadata unnecessarily.
$arguments.Add('--no-build')
$arguments.Add('--no-restore')
}
if ($ListTests) {
$arguments.Add('--list-tests')
}
if (-not [string]::IsNullOrWhiteSpace($Filter)) {
$arguments.Add('--filter')
$arguments.Add($Filter)
}
if (-not [string]::IsNullOrWhiteSpace($Logger)) {
$arguments.Add('--logger')
$arguments.Add($Logger)
}
foreach ($argument in $AdditionalDotNetArguments) {
$arguments.Add($argument)
}

Write-Host "Running FileManager UI tests"
Write-Host " Project: $testProject"
Write-Host " Executable: $resolvedExecutable"
Write-Host " Filter: $Filter"

Push-Location $repositoryRoot
try {
& dotnet @arguments
$testExitCode = $LASTEXITCODE
}
finally {
Pop-Location
}
}
finally {
# Restore the caller's process environment so focused reruns do not affect later shell commands.
$env:FILEMANAGER_UI_ISOLATED = $previousIsolated
$env:FILEMANAGER_UI_EXE = $previousExecutable
}

exit $testExitCode
1 change: 1 addition & 0 deletions src/async_copy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6273,6 +6273,7 @@ BOOL DoDeleteFile(HWND hProgressDlg, COperation* operation, const CQuadWord& siz
DeleteFileWithVerifiedIdentity(name, operation->SourceIdentity, &err);
}
DELETE_READY:
; // A label must own a statement even when identity rejection only skips deletion.
}
else
{
Expand Down
18 changes: 15 additions & 3 deletions tests/FileManager.UiTests/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# FileManager UI tests

This project contains seven primary parameterized FlaUI/UIA3 lifecycle cases plus focused file-operation characterization cases for the native FileManager UI. Repetition belongs to the separately scheduled lock-stress soak. The cases cover application launch, accessibility-tree discovery, Configuration dialog cancel/commit/restart flows, a committed setting verified after restart, FTP bookmark creation plus edit verified after restart, and native disk create/copy/rename/move/delete/find/view/edit commands.
This project contains a seven-case parameterized FlaUI/UIA3 lifecycle group, together with focused file-operation, recovery, plug-in, toolbar, TLS, and native-safety characterization tests. The cases cover application launch, accessibility-tree discovery, Configuration dialog cancel/commit/restart flows, a committed setting verified after restart, FTP bookmark creation plus edit verified after restart, and native disk create/copy/rename/move/delete/find/view/edit commands.

The tests intentionally refuse to run unless `FILEMANAGER_UI_ISOLATED=1` is set. The application persists configuration under the current user registry hive, so run them under a dedicated Windows test account or another isolated user profile.

Set these environment variables before running:

The `run-ui-tests.ps1` entry point described below sets `FILEMANAGER_UI_ISOLATED` and `FILEMANAGER_UI_EXE` for its child test process. Configure the remaining variables only when their optional test lanes are required. When calling `dotnet test` directly, set the first two variables manually.

- `FILEMANAGER_UI_ISOLATED=1` — confirms that the current Windows profile is disposable.
- `FILEMANAGER_UI_EXE` — absolute path to `salamand.exe` or a debug build of the executable.
- `FILEMANAGER_UI_ARGUMENTS` — optional command-line arguments, for example a test-only `-c` configuration file.
Expand All @@ -18,12 +20,22 @@ Set these environment variables before running:
- `FILEMANAGER_UI_HELP_SEARCH_TERM` — a search term known to exist in the language-specific deployed `salamand.chm`.
- `FILEMANAGER_UI_HELP_EXPECTED_RESULT` — text expected in the Help Search result for that term.

Run the suite on an interactive Windows desktop session:
Run the interactive UI category on an interactive Windows desktop session. This is the runner default and currently selects approximately 60 cases:

```powershell
dotnet test tests/FileManager.UiTests/FileManager.UiTests.csproj --filter TestCategory=UI
.\run-ui-tests.ps1 -ConfirmIsolatedProfile
```

Run the entire test project, currently 125 discovered cases, by explicitly clearing the default category filter:

```powershell
.\run-ui-tests.ps1 -ConfirmIsolatedProfile -Filter ''
```

The complete run includes UI, native-safety, TLS, toolbar-contract, and other non-UI tests. Tests whose optional prerequisites are unavailable—such as the ZIP plug-in, deployed Help content, a second volume, fault injection, or Recycle Bin configuration—are reported as skipped rather than omitted from discovery.

The runner derives paths from its repository location, prefers an existing checkout build, and otherwise checks the Windows `App Paths` registration for an installed `salamand.exe`. Use `-ExecutablePath 'C:\Program Files\Open Salamander\salamand.exe'` to select another installation, `-Filter 'Name~Copy_file'` for a focused run, or `-NoBuild` after the managed test project is already built. The confirmation switch is intentionally required because the application writes configuration under the current user profile. File-operation tests create their own disposable source and target directories; callers do not need to configure shared test folders.

The configuration dialog is opened through its stable native command ID only to avoid locale-dependent menu text. All window discovery, control inspection, focus, dialog lifecycle, and restart assertions use FlaUI/UIA3.

File-operation cases create a fresh disposable directory tree under the system temporary directory for every test, start the left and right panels with `-l`/`-r`, and use the host's stable native command IDs. They verify files and nested directory trees after normal operations, copy and move overwrite/skip conflict choices, rename overwrite-decline and case-only behavior, mixed-selection deletion, continuation after a skipped delete error, file search, internal viewing, configured-editor launch, metadata preservation, cancellation after the worker has started, and destination/name failures. ADS cases create named, empty, large, and edge-named streams; exercise overwrite and retry after a temporarily denied stream; and verify cross-volume preservation or explicit source retention when an ADS-unsupported target reports metadata loss. The recovery fixture seeds an incomplete durable journal with a ready transactional sibling file before launch, then verifies the real startup reconciliation flow. The tests never use a caller-supplied directory as their mutation target; cross-volume cases use only a GUID child under the explicitly configured disposable root.
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading