1param([string]$Root, [string]$CloneHost)
2Set-StrictMode -Version Latest
3$ErrorActionPreference = 'Stop'
4$results = New-Object Collections.Generic.List[object]
5$index = 0
6function Record-Phase([string]$Phase) {
7 @{ name=$file.BaseName; phase=$Phase; utc=[DateTime]::UtcNow.ToString('o') } |
8 ConvertTo-Json -Compress | Add-Content "$Root\progress.jsonl" -Encoding UTF8
9}
10foreach ($file in @(Get-ChildItem "$Root\inputs" -Filter '*.one' | Sort-Object Name)) {
11 $output = "$Root\results\$($file.BaseName)"
12 New-Item -ItemType Directory $output -Force | Out-Null
13 Record-Phase 'cold-reset'
14 $cold = $false
15 for ($attempt = 0; $attempt -lt 5; $attempt++) {
16 $case = "C:\one-tests\runs\probe-$index-$attempt"
17 New-Item -ItemType Directory "$case\notebook" -Force | Out-Null
18 Copy-Item $file.FullName "$case\notebook\synthetic.one"
19 Get-Process ONENOTE -ErrorAction SilentlyContinue | ForEach-Object {
20 Stop-Process -InputObject $_ -Force -ErrorAction SilentlyContinue
21 if (-not $_.WaitForExit(10000)) { throw 'OneNote did not exit before the cache reset.' }
22 }
23 Start-Sleep -Milliseconds 250
24 try { & "$PSScriptRoot\cold-current.ps1" -Root $case -CloneHost $CloneHost }
25 catch {
26 if ($_.Exception.Message -ne 'Close OneNote before resetting its test cache.') { throw }
27 continue
28 }
29 if (-not (Get-Process ONENOTE -ErrorAction SilentlyContinue)) { $cold = $true; break }
30 }
31 if (-not $cold) { throw 'OneNote kept reopening during the cache reset.' }
32 Record-Phase 'create-application'
33 $app = New-Object -ComObject OneNote.Application
34 $notebook = ''; $section = ''; $hierarchy = ''; $failure = $null; $pages = @()
35 $started = [DateTime]::UtcNow
36 try {
37 Record-Phase 'open-notebook'
38 $app.OpenHierarchy("$case\notebook", '', [ref]$notebook, 0)
39 Record-Phase 'open-section'
40 $app.OpenHierarchy("$case\notebook\synthetic.one", '', [ref]$section, 0)
41 $deadline = [DateTime]::UtcNow.AddSeconds(30)
42 do {
43 Record-Phase 'get-hierarchy'
44 $app.GetHierarchy($section, 4, [ref]$hierarchy, 1)
45 [xml]$tree = $hierarchy
46 $pages = @($tree.SelectNodes('//*[local-name()="Page"]'))
47 if ($pages.Count -and $tree.DocumentElement.GetAttribute('areAllPagesAvailable') -ne 'false') { break }
48 Start-Sleep -Milliseconds 250
49 } while ([DateTime]::UtcNow -lt $deadline)
50 if (-not $pages.Count -or $tree.DocumentElement.GetAttribute('areAllPagesAvailable') -eq 'false') {
51 throw 'The section did not finish loading its pages.'
52 }
53 $n = 0
54 foreach ($page in $pages) {
55 $content = ''
56 Record-Phase "get-page-$n"
57 $app.GetPageContent($page.GetAttribute('ID'), [ref]$content, 1, 1)
58 [IO.File]::WriteAllText("$output\page-$n.xml", $content, [Text.Encoding]::UTF8)
59 $n++
60 }
61 } catch { $failure = $_ | Out-String }
62 finally {
63 [IO.File]::WriteAllText("$output\hierarchy.xml", $hierarchy, [Text.Encoding]::UTF8)
64 $results.Add(@{ name=$file.BaseName; pages=$pages.Count; error=$failure;
65 seconds=([DateTime]::UtcNow - $started).TotalSeconds;
66 source_sha256=(Get-FileHash $file.FullName).Hash.ToLowerInvariant() })
67 $results | ConvertTo-Json -Depth 5 | Set-Content "$Root\results.json" -Encoding UTF8
68 Record-Phase 'close-notebook'
69 try { if ($notebook) { $app.CloseNotebook($notebook, $false) } } catch {}
70 [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app)
71 $app = $null
72 [GC]::Collect()
73 [GC]::WaitForPendingFinalizers()
74 Record-Phase 'complete'
75 }
76 $index++
77}