Remove the demo text-parsing domain
The scaffolding domain existed to prove the shell end to end before there was
anything real to put in it. There is now, so it goes - as CLAUDE.md promised it
would.
Gone: the two sample parsers, ITextParser, ParsedRecord, the parser catalog,
ParseViewModel and ParseView, their tests, and the settings key that remembered
which parser was last used. ParseError.LineNumber becomes Index, since for a
listing "line 42" was simply untrue, and the error keys move from Parse.Error.*
to Collect.Error.* now that parsing is not a concept here.
Kept: IParser<,>, ParseOutcome, ParseProgress and ParseError. The streaming
contract was always the general part - it was only ever the text-shaped closure
of it that was scaffolding.
Rendering the dashboard caught two keys that were referenced but never added
during the rename: the XAML was repointed and the resources were not. The parity
test could not see it, because it compares the two files against each other and
a key absent from both is consistent. That gap now has its own test, which reads
every {l:Loc} in the XAML and checks it resolves - a screenshot is too late and
too manual a way to find a missing string.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fe62bcf53f
commit
f8744c930a
@@ -0,0 +1,65 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Text.RegularExpressions;
|
||||
using AvParser.UI.Localization;
|
||||
|
||||
namespace AvParser.UI.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Every key the XAML asks for must actually exist.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The parity test compares the two resource files against each other, so a key missing from
|
||||
/// <b>both</b> passes it happily and then renders as <c>!Some.Key!</c> in the running app. That
|
||||
/// happened during a rename: the XAML was repointed at new key names and the keys themselves were
|
||||
/// never added. Only a screenshot caught it, which is too late and too manual.
|
||||
/// </remarks>
|
||||
public sealed partial class LocalizationCoverageTests
|
||||
{
|
||||
[GeneratedRegex(@"\{l:Loc\s+([A-Za-z0-9_.\-]+)\s*\}", RegexOptions.Compiled)]
|
||||
private static partial Regex LocMarkup();
|
||||
|
||||
private static readonly ResourceManager Resources = new(
|
||||
"AvParser.UI.Localization.Strings",
|
||||
typeof(Localizer).GetTypeInfo().Assembly
|
||||
);
|
||||
|
||||
/// <summary>Walks up to the repository root, which the test binary sits several levels below.</summary>
|
||||
private static DirectoryInfo RepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AvParser.slnx")))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
return directory ?? throw new InvalidOperationException("Could not find the repository root.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_key_used_in_xaml_exists()
|
||||
{
|
||||
var views = Path.Combine(RepositoryRoot().FullName, "src", "AvParser.UI");
|
||||
var files = Directory.GetFiles(views, "*.axaml", SearchOption.AllDirectories);
|
||||
|
||||
files.ShouldNotBeEmpty();
|
||||
|
||||
var missing = new SortedSet<string>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
foreach (Match match in LocMarkup().Matches(File.ReadAllText(file)))
|
||||
{
|
||||
var key = match.Groups[1].Value;
|
||||
|
||||
if (Resources.GetString(key, Localizer.Instance.Culture) is null)
|
||||
{
|
||||
missing.Add($"{key} ({Path.GetFileName(file)})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
missing.ShouldBeEmpty();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user