Skip to content

Commit 000b934

Browse files
committed
perf: speed up Views rendering and add render verification
Avoid redundant Views reconstruct/layout work, cache native render resources, and reduce repeated text normalization in hot paths. Add render snapshot verification, timing scenarios, trace parsing, baseline assets, and helper entry points so render behavior and performance can be checked repeatably.
1 parent d4fd1ec commit 000b934

129 files changed

Lines changed: 15955 additions & 327 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ Src/LexText/ParserCore/ParserCoreTests/**/*.txt -whitespace
3434
Src/Utilities/pcpatrflex/DisambiguateInFLExDB/DisambiguateInFLExDBTests/TestData/*.* -whitespace
3535
Src/Utilities/pcpatrflex/PcPatrBrowserDll/Transforms/*.* -whitespace
3636
Src/Utilities/HCSynthByGloss/HCSynthByGloss/TestData/*.txt -whitespace
37+
38+
# Verify snapshot testing
39+
*.verified.png binary
40+
*.received.png binary

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ _UpgradeReport_Files/
100100
/Release/
101101
Output/
102102
Output
103+
Output/RenderBenchmarks/
104+
Output/RenderBenchmarks/**
103105
Output_i686/
104106
Output_x86_64/
105107
__pycache__/
@@ -186,6 +188,7 @@ CrashLog.txt
186188
# VSTest Artifacts
187189
TestResults/
188190
*.trx
191+
TestResult.xml
189192

190193
# WPF markup compilation temp projects
191194
*_wpftmp.csproj
@@ -201,3 +204,8 @@ FLExInstaller/wix6/cabcache/*
201204

202205
# Claude Code worktrees
203206
.claude/worktrees/*
207+
208+
# Verify snapshot testing - received files are transient
209+
*.received.png
210+
*.diff.png
211+
DataTreeTimingBaselines.json

.vscode/tasks.json

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,29 @@
8585
}
8686
],
8787
"tasks": [
88+
{
89+
"label": "Test: RenderBaselineTests",
90+
"type": "shell",
91+
"command": ".\\test.ps1 -TestProject \"RootSiteTests\" -TestFilter \"FullyQualifiedName~RenderBaselineTests\"",
92+
"options": {
93+
"shell": {
94+
"executable": "powershell.exe",
95+
"args": ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"]
96+
}
97+
},
98+
"problemMatcher": [],
99+
"group": "test",
100+
"presentation": {
101+
"reveal": "always",
102+
"panel": "shared"
103+
}
104+
},
88105
// ==================== Setup Tasks ====================
89106
{
90107
"label": "Setup: Colorize Worktree",
91108
"type": "shell",
92109
"command": "./scripts/Setup-WorktreeColor.ps1 -VSCodeWorkspaceFile \"${workspaceFile}\"",
93-
"detail": "Sets a unique window color from a deterministic palette slot",
94-
"runOptions": {
95-
"runOn": "folderOpen"
96-
},
110+
"detail": "Windows only: sets a unique window color from a deterministic palette slot",
97111
"options": {
98112
"shell": {
99113
"executable": "powershell.exe",
@@ -216,7 +230,7 @@
216230
"kind": "build",
217231
"isDefault": true
218232
},
219-
"detail": "Build FieldWorks (auto-detects worktree)",
233+
"detail": "Windows only: build FieldWorks (auto-detects worktree)",
220234
"options": {
221235
"shell": {
222236
"executable": "powershell.exe",
@@ -230,7 +244,21 @@
230244
"type": "shell",
231245
"command": "./build.ps1 -Configuration Release",
232246
"group": "build",
233-
"detail": "Build FieldWorks in Release configuration",
247+
"detail": "Windows only: build FieldWorks in Release configuration",
248+
"options": {
249+
"shell": {
250+
"executable": "powershell.exe",
251+
"args": ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"]
252+
}
253+
},
254+
"problemMatcher": "$msCompile"
255+
},
256+
{
257+
"label": "Build Tests",
258+
"type": "shell",
259+
"command": "./build.ps1 -BuildTests",
260+
"group": "build",
261+
"detail": "Windows only: build FieldWorks including test projects (required for ReSharper Test Explorer)",
234262
"options": {
235263
"shell": {
236264
"executable": "powershell.exe",
@@ -249,7 +277,7 @@
249277
"kind": "test",
250278
"isDefault": true
251279
},
252-
"detail": "Run all tests (auto-detects worktree). See specs/007-test-modernization-vstest/IGNORED_TESTS.md for the tracked skip/ignore inventory.",
280+
"detail": "Windows only execution. On Linux/macOS this exits with a not-supported message. See specs/007-test-modernization-vstest/IGNORED_TESTS.md for the tracked skip/ignore inventory.",
253281
"options": {
254282
"shell": {
255283
"executable": "powershell.exe",
@@ -263,7 +291,7 @@
263291
"type": "shell",
264292
"command": "./test.ps1 -ListTests -NoBuild -Configuration ${input:testConfiguration} -Verbosity ${input:testVerbosity}",
265293
"group": "test",
266-
"detail": "List tests via test.ps1 (requires existing built test assemblies). For known skips/ignores see specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
294+
"detail": "Windows only execution. On Linux/macOS this exits with a not-supported message. For known skips/ignores see specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
267295
"options": {
268296
"shell": {
269297
"executable": "powershell.exe",
@@ -277,7 +305,7 @@
277305
"type": "shell",
278306
"command": "./test.ps1 -TestFilter '${input:testFilter}' -Configuration ${input:testConfiguration} -Verbosity ${input:testVerbosity}",
279307
"group": "test",
280-
"detail": "Run tests with a filter expression. If failures correspond to known ignores/skips, see specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
308+
"detail": "Windows only execution. On Linux/macOS this exits with a not-supported message. If failures correspond to known ignores/skips, see specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
281309
"options": {
282310
"shell": {
283311
"executable": "powershell.exe",
@@ -291,7 +319,7 @@
291319
"type": "shell",
292320
"command": "./test.ps1 -TestProject '${input:testProject}' -Configuration ${input:testConfiguration} -Verbosity ${input:testVerbosity}",
293321
"group": "test",
294-
"detail": "Run tests from a specific project. Track known skips/ignores in specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
322+
"detail": "Windows only execution. On Linux/macOS this exits with a not-supported message. Track known skips/ignores in specs/007-test-modernization-vstest/IGNORED_TESTS.md.",
295323
"options": {
296324
"shell": {
297325
"executable": "powershell.exe",

Build/Agent/Run-AllRenders.ps1

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<#
2+
.SYNOPSIS
3+
Runs the render-focused test suites for FieldWorks.
4+
5+
.DESCRIPTION
6+
Executes the DetailControls render tests and the RootSite render tests sequentially.
7+
This script is intentionally outside the product project graph so developers can use a
8+
single entrypoint without introducing a meta test project into the repository architecture.
9+
10+
.PARAMETER Scope
11+
Which render suites to run. Default is All.
12+
13+
.PARAMETER Configuration
14+
The build configuration to test. Default is Debug.
15+
16+
.PARAMETER NoBuild
17+
Skip building before running tests.
18+
19+
.PARAMETER Verbosity
20+
Test output verbosity: quiet, minimal, normal, detailed.
21+
22+
.PARAMETER SkipDependencyCheck
23+
Skip dependency preflight checks inside test.ps1.
24+
#>
25+
[CmdletBinding()]
26+
param(
27+
[ValidateSet('All', 'DetailControls', 'RootSite')]
28+
[string]$Scope = 'All',
29+
[string]$Configuration = 'Debug',
30+
[switch]$NoBuild,
31+
[ValidateSet('quiet', 'minimal', 'normal', 'detailed', 'q', 'm', 'n', 'd')]
32+
[string]$Verbosity = 'normal',
33+
[switch]$SkipDependencyCheck
34+
)
35+
36+
Set-StrictMode -Version Latest
37+
$ErrorActionPreference = 'Stop'
38+
39+
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..'))
40+
$buildScript = Join-Path $repoRoot 'build.ps1'
41+
$testScript = Join-Path $repoRoot 'test.ps1'
42+
43+
if (-not (Test-Path $buildScript)) {
44+
throw "build.ps1 not found at $buildScript"
45+
}
46+
47+
if (-not (Test-Path $testScript)) {
48+
throw "test.ps1 not found at $testScript"
49+
}
50+
51+
$requestedScopes = switch ($Scope) {
52+
'All' { @('DetailControls', 'RootSite') }
53+
default { @($Scope) }
54+
}
55+
56+
function Invoke-RenderSuite {
57+
param(
58+
[Parameter(Mandatory = $true)]
59+
[string]$Name,
60+
[Parameter(Mandatory = $true)]
61+
[string]$BuildProject,
62+
[Parameter(Mandatory = $true)]
63+
[string]$TestProject,
64+
[Parameter(Mandatory = $true)]
65+
[string[]]$TestFilters
66+
)
67+
68+
if (-not $NoBuild) {
69+
Write-Output "Building $Name render tests..."
70+
71+
$buildArgs = @{
72+
Configuration = $Configuration
73+
Project = $BuildProject
74+
Verbosity = $Verbosity
75+
}
76+
77+
if ($SkipDependencyCheck) {
78+
$buildArgs['SkipDependencyCheck'] = $true
79+
}
80+
81+
& $buildScript @buildArgs
82+
if ($LASTEXITCODE -ne 0) {
83+
throw "$Name render build failed with exit code $LASTEXITCODE."
84+
}
85+
}
86+
87+
foreach ($testFilter in $TestFilters) {
88+
Write-Output "Running $Name render tests with filter '$testFilter'..."
89+
90+
$testArgs = @{
91+
Configuration = $Configuration
92+
TestProject = $TestProject
93+
TestFilter = $testFilter
94+
Verbosity = $Verbosity
95+
NoBuild = $true
96+
SkipDependencyCheck = $true
97+
}
98+
99+
& $testScript @testArgs
100+
if ($LASTEXITCODE -ne 0) {
101+
throw "$Name render tests failed with exit code $LASTEXITCODE for filter '$testFilter'."
102+
}
103+
}
104+
105+
Write-Output "[OK] $Name render tests passed."
106+
}
107+
108+
foreach ($requestedScope in $requestedScopes) {
109+
switch ($requestedScope) {
110+
'DetailControls' {
111+
Invoke-RenderSuite `
112+
-Name 'DetailControls' `
113+
-BuildProject 'Src/Common/Controls/DetailControls/DetailControlsTests/DetailControlsTests.csproj' `
114+
-TestProject 'Src/Common/Controls/DetailControls/DetailControlsTests' `
115+
-TestFilters 'FullyQualifiedName~DataTreeRenderTests'
116+
}
117+
'RootSite' {
118+
Invoke-RenderSuite `
119+
-Name 'RootSite' `
120+
-BuildProject 'Src/Common/RootSite/RootSiteTests/RootSiteTests.csproj' `
121+
-TestProject 'Src/Common/RootSite/RootSiteTests' `
122+
-TestFilters @(
123+
'FullyQualifiedName~RenderBaselineTests',
124+
'FullyQualifiedName~RenderTimingSuiteTests',
125+
'FullyQualifiedName~RenderVerifyTests'
126+
)
127+
}
128+
}
129+
}
130+
131+
Write-Output 'All requested render suites passed.'

Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,7 @@
153153
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
154154
<PackageVersion Include="NUnitForms" Version="1.3.1" />
155155
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
156+
<!-- Can be changed to NUnit.Verify when NUnit is updated to v4 -->
157+
<PackageVersion Include="Verify" Version="31.11.0" />
156158
</ItemGroup>
157159
</Project>

FieldWorks.sln

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DetailControls", "Src\Commo
1818
EndProject
1919
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DetailControlsTests", "Src\Common\Controls\DetailControls\DetailControlsTests\DetailControlsTests.csproj", "{36F2A7A6-C7F9-5D3D-87D7-B4C0D5C51C0E}"
2020
EndProject
21+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderTestInfrastructure", "Src\Common\RenderTestInfrastructure\RenderTestInfrastructure.csproj", "{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}"
22+
EndProject
23+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderVerification", "Src\Common\RenderVerification\RenderVerification.csproj", "{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}"
24+
EndProject
2125
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discourse", "Src\LexText\Discourse\Discourse.csproj", "{A51BAFC3-1649-584D-8D25-101884EE9EAA}"
2226
EndProject
2327
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscourseTests", "Src\LexText\Discourse\DiscourseTests\DiscourseTests.csproj", "{1CE6483D-5D10-51AD-B2A7-FD7F82CCBAB2}"
@@ -335,6 +339,18 @@ Global
335339
{36F2A7A6-C7F9-5D3D-87D7-B4C0D5C51C0E}.Debug|x64.Build.0 = Debug|x64
336340
{36F2A7A6-C7F9-5D3D-87D7-B4C0D5C51C0E}.Release|x64.ActiveCfg = Release|x64
337341
{36F2A7A6-C7F9-5D3D-87D7-B4C0D5C51C0E}.Release|x64.Build.0 = Release|x64
342+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Bounds|x64.ActiveCfg = Release|x64
343+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Bounds|x64.Build.0 = Release|x64
344+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Debug|x64.ActiveCfg = Debug|x64
345+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Debug|x64.Build.0 = Debug|x64
346+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Release|x64.ActiveCfg = Release|x64
347+
{B53C715F-2F97-4E2B-9C10-5BFF1C04A446}.Release|x64.Build.0 = Release|x64
348+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Bounds|x64.ActiveCfg = Release|x64
349+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Bounds|x64.Build.0 = Release|x64
350+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Debug|x64.ActiveCfg = Debug|x64
351+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Debug|x64.Build.0 = Debug|x64
352+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Release|x64.ActiveCfg = Release|x64
353+
{6F7A4D9C-5B44-4D0E-ABAA-8D6F38F30C6A}.Release|x64.Build.0 = Release|x64
338354
{A51BAFC3-1649-584D-8D25-101884EE9EAA}.Bounds|x64.ActiveCfg = Release|x64
339355
{A51BAFC3-1649-584D-8D25-101884EE9EAA}.Bounds|x64.Build.0 = Release|x64
340356
{A51BAFC3-1649-584D-8D25-101884EE9EAA}.Debug|x64.ActiveCfg = Debug|x64

0 commit comments

Comments
 (0)