Files
kua-agent 6610acfa44 feat: rebrand to MMD PDF, single corporate theme, and remove original text under an edit
- Services/PdfRedactText.cs: strip text whose origin falls inside a CoverAnnotation
  from the page content stream at save time, hooked into PdfBurn.DrawAnnotationsIntoDoc.
  Fixes edited values staying recoverable by text extraction.
- Themes/MMD.xaml replaces all thirteen themes; picker and accent strip removed; no dark mode.
- Rename KillerPDF -> MMD PDF across code, resources, packaging and locale strings; new icon.
- Remove the upstream author credit and the in-app install button.
2026-08-27 07:37:09 +02:00

110 lines
4.3 KiB
C#

using System;
using System.IO;
using System.Linq;
using MmdPdf.Services;
using Xunit;
namespace MmdPdf.Tests;
// The rule this file exists to enforce: OCR LANGUAGES TRACK INTERFACE LANGUAGES.
// If MmdPdf's UI is offered in a language, OCR is offered in it too. There is no such thing as
// an interface language whose text the app cannot read.
//
// Nothing enforced it before, so it drifted: the UI shipped hu-HU while the catalog stayed at
// eleven entries, and baobab-ts.com went on telling people OCR covered ten languages and that
// Polish and Hungarian "do not require OCR models".
//
// These read the real Strings folder instead of a second hardcoded list, so adding a locale fails
// the build until its model is registered. release.ps1 runs the suite, so it cannot ship broken.
public sealed class OcrCatalogTests
{
// The test binary sits at MmdPdf.Tests\bin\<cfg>\net48; the repo root is the ancestor that
// holds Strings\. Walking up beats a pile of ..\..\.. that breaks whenever the layout moves.
private static string StringsDir()
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null && !Directory.Exists(Path.Combine(dir.FullName, "Strings")))
dir = dir.Parent;
Assert.True(dir != null, "could not locate the repo's Strings folder from " + AppContext.BaseDirectory);
return Path.Combine(dir!.FullName, "Strings");
}
private static string[] ShippedLocales() =>
Directory.GetFiles(StringsDir(), "*.xaml")
.Select(f => Path.GetFileNameWithoutExtension(f)!)
.OrderBy(n => n, StringComparer.OrdinalIgnoreCase)
.ToArray();
[Fact]
public void TheStringsFolderIsActuallyFound()
{
// Guards the guard: if the walk-up ever failed silently, every other test here would
// compare against an empty list and pass while checking nothing.
Assert.NotEmpty(ShippedLocales());
}
[Fact]
public void EveryShippedLocaleHasAnOcrModel()
{
var mapped = OcrCatalog.LocaleToCode.Select(x => x.Locale).ToArray();
var missing = ShippedLocales()
.Where(l => !mapped.Contains(l, StringComparer.OrdinalIgnoreCase))
.ToArray();
Assert.True(missing.Length == 0,
"These locales ship an interface but have no OCR model in OcrCatalog.LocaleToCode: " +
string.Join(", ", missing));
}
[Fact]
public void NoModelIsRegisteredForALocaleThatIsNotShipped()
{
var locales = ShippedLocales();
var stale = OcrCatalog.LocaleToCode
.Where(x => !locales.Contains(x.Locale, StringComparer.OrdinalIgnoreCase))
.Select(x => x.Locale + " -> " + x.Code)
.ToArray();
Assert.True(stale.Length == 0,
"These OCR entries point at locales no longer in Strings\\: " + string.Join(", ", stale));
}
[Fact]
public void CatalogAndLocaleMapAgree()
{
var catalog = OcrCatalog.Languages.Select(x => x.Code).OrderBy(c => c, StringComparer.Ordinal).ToArray();
var mapped = OcrCatalog.LocaleToCode.Select(x => x.Code).OrderBy(c => c, StringComparer.Ordinal).ToArray();
Assert.Equal(mapped, catalog);
}
[Fact]
public void CatalogHasNoDuplicatesAndNoBlanks()
{
var codes = OcrCatalog.Languages.Select(x => x.Code).ToArray();
Assert.Equal(codes.Length, codes.Distinct(StringComparer.Ordinal).Count());
Assert.All(OcrCatalog.Languages, e =>
{
Assert.False(string.IsNullOrWhiteSpace(e.Code));
Assert.False(string.IsNullOrWhiteSpace(e.Name));
});
}
[Fact]
public void OcrLanguageCountEqualsInterfaceLanguageCount()
{
// The number baobab-ts.com quotes in prose. Pinning it here is what stops the site and
// the app from disagreeing again.
Assert.Equal(ShippedLocales().Length, OcrCatalog.Languages.Length);
}
[Theory]
[InlineData("hu-HU", "hun")]
[InlineData("pl-PL", "pol")]
public void TheOnesThatWereMissingAreRegistered(string locale, string code)
{
Assert.Contains(OcrCatalog.LocaleToCode, x =>
string.Equals(x.Locale, locale, StringComparison.OrdinalIgnoreCase) && x.Code == code);
Assert.Contains(OcrCatalog.Languages, x => x.Code == code);
}
}