diff --git a/TestTools/README.md b/TestTools/README.md
index 797736312..93a0f18ca 100644
--- a/TestTools/README.md
+++ b/TestTools/README.md
@@ -72,10 +72,11 @@ download itself is `nugetfuzz --download-only`, so package selection, TFM matchi
dependency walk behave exactly as they do in a sweep - only the decompiling is skipped.
The corpus is written as a list of directories rather than one root, because a package already
-restored on this machine is used from the machine-wide NuGet cache instead of being copied:
+restored on this machine is used from the machine-wide NuGet cache instead of being copied. Pass the
+list with `@`, which both tools understand and which needs no help from the shell:
```pwsh
-dotnet run decompdiff.cs -- --old master --new my-branch -o report $(cat crawl/top-200.corpus.txt)
+dotnet run decompdiff.cs -- --old master --new my-branch -o report @crawl/top-200.corpus.txt
```
## decompdiff
@@ -92,6 +93,9 @@ dotnet run decompdiff.cs -- --old ../../ILSpy-master --new . -o report ~/.cache/
dotnet run decompdiff.cs -- --old v9.1.dll --new v11.dll --refs
corpus.dll
```
+A corpus argument is a dll, a directory scanned recursively for dlls, or `@file` listing either one
+per line (`#` comments allowed).
+
An `--old`/`--new` argument is a path to `ICSharpCode.Decompiler.dll`, an ILSpy checkout, or a
commit-ish. A checkout is restored and built in Release on demand. **Watch the timestamp in the
header line**: an existing Release build is reused as-is; pass `--build` to force a rebuild.
diff --git a/TestTools/decompdiff.cs b/TestTools/decompdiff.cs
index a653d64b3..01352087a 100644
--- a/TestTools/decompdiff.cs
+++ b/TestTools/decompdiff.cs
@@ -25,7 +25,7 @@
// round-trip tests, which verify correctness but not output quality.
//
// usage: dotnet run decompdiff.cs -- --old --new <...>
-// [-o ] [--build] [--refs ]... ...
+// [-o ] [--build] [--refs ]... ...
//
// - checkout args are built on demand (Release; restore keeps packages.lock.json
// whole via -p:RestoreEnablePackagePruning=false); pass --build to force rebuild.
@@ -33,7 +33,8 @@
// the tool is run from and checked out into a worktree under
// ~/.cache/decompdiff//, kept and reused so a rerun keeps the
// Release build it already contains.
-// - corpus dirs are scanned recursively for *.dll (e.g. ~/.cache/nugetfuzz).
+// - corpus dirs are scanned recursively for *.dll (e.g. ~/.cache/nugetfuzz); @list reads
+// the entries from a file, one per line, as nugetfuzz does with its package list.
// - changed/errored types are written to /{old,new}/...; inspect with
// `git diff --no-index /old /new`, or open the generated
// /index.html, which carries the same data with inline diffs.
@@ -97,13 +98,24 @@ for (int i = 0; i < args.Length; i++)
refDirs.Add(args[++i]);
break;
default:
- corpus.Add(args[i]);
+ // @file lists corpus entries one per line, the same spelling nugetfuzz uses. Shells
+ // differ on how (or whether) a file expands into arguments, so the tool reads it.
+ if (args[i].StartsWith('@'))
+ {
+ corpus.AddRange(File.ReadAllLines(args[i][1..])
+ .Select(l => l.Trim())
+ .Where(l => l.Length > 0 && !l.StartsWith('#')));
+ }
+ else
+ {
+ corpus.Add(args[i]);
+ }
break;
}
}
if (oldSpec == null || newSpec == null || corpus.Count == 0)
{
- Console.Error.WriteLine("usage: decompdiff --old --new <...> [-o report-dir] [--build] [--refs ]... ...");
+ Console.Error.WriteLine("usage: decompdiff --old --new <...> [-o report-dir] [--build] [--refs ]... ...");
return 1;
}
reportDir ??= "decompdiff-report";
diff --git a/TestTools/nuget-top.ps1 b/TestTools/nuget-top.ps1
index 028ca4aef..718291cff 100644
--- a/TestTools/nuget-top.ps1
+++ b/TestTools/nuget-top.ps1
@@ -70,4 +70,4 @@ $dirs = $log | ForEach-Object { if ($_ -match '^\s*cached:\s*(.+)$') { $Matches[
Set-Content -Path $corpusFile -Value $dirs
Write-Host ""
Write-Host "$($dirs.Count) lib directories -> $corpusFile"
-Write-Host "decompdiff --old [ --new ][ -o report `$(cat $corpusFile)"
+Write-Host "dotnet run decompdiff.cs -- --old ][ --new ][ -o report `@$corpusFile"
]