using System.IO;
using System.Text;
using AcDream.App.UI.Layout;
using AcDream.Content;
using DatReaderWriter.Options;
using StringTable = DatReaderWriter.DBObjs.StringTable;
namespace AcDream.App.Tests.UI.Layout;
///
/// 2026-08-17 systemic escape round: installed-DAT sweep of EVERY string
/// table for literal escape content, plus the source-normalization contract
/// ( resolutions must equal
/// of the raw stored text —
/// retail's StringInfo::InqString @ 0x0042E490 placement). This is
/// the measurement companion to the per-consumer normalize retirement: it
/// proves the escape class genuinely exists in shipping data and prints
/// which tables carry it.
///
public sealed class DatStringEscapeSweepTests
{
[InstalledDatFact]
public void EveryInstalledStringResolvesSourceDecoded()
{
string datDirectory = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
?? Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Documents",
"Asheron's Call");
using var dats = new DatCollection(datDirectory, DatAccessType.Read);
var resolver = new DatStringResolver(dats);
int tables = 0;
int strings = 0;
int withNewlineEscape = 0;
int withTabEscape = 0;
int withCrEscape = 0;
int withQuoteEscape = 0;
int withMetaSelfEscape = 0;
int withUnknownPair = 0;
int withRealCr = 0;
var perTableNewlines = new SortedDictionary();
var examples = new List();
string? userReportedExitText = null;
foreach (uint tableId in dats.GetAllIdsOfType().Order())
{
StringTable? table = dats.Get(tableId);
if (table is null)
continue;
tables++;
foreach ((uint stringId, var entry) in table.Strings)
{
for (int token = 0; token < entry.Strings.Count; token++)
{
string raw = entry.Strings[token].Value;
strings++;
bool newline = false, unknown = false, meta = false;
for (int i = 0; i < raw.Length - 1; i++)
{
if (raw[i] != '\\')
continue;
char next = raw[i + 1];
char decoded = RetailStringEscapes.GetUnEscapedChar(next);
switch (decoded)
{
case '\n': newline = true; break;
case '\t': withTabEscape++; break;
case '\r': withCrEscape++; break;
case '"': withQuoteEscape++; break;
case '\0': unknown = true; break;
default: meta = true; break;
}
i++; // the pair is consumed either way it decodes
}
if (newline)
{
withNewlineEscape++;
perTableNewlines[tableId] =
perTableNewlines.GetValueOrDefault(tableId) + 1;
if (examples.Count < 12)
examples.Add(
$"0x{tableId:X8}/0x{stringId:X8}: \"{Truncate(raw)}\"");
}
if (meta) withMetaSelfEscape++;
if (unknown) withUnknownPair++;
if (raw.Contains('\r')) withRealCr++;
// The source contract: what consumers receive from the
// resolver is EXACTLY the retail unescape of the stored
// text — nothing more (no consumer re-decode is owed),
// nothing less (no escape survives to render literally).
Assert.Equal(
RetailStringEscapes.Unescape(raw),
resolver.Resolve(tableId, stringId, token));
if (raw.Contains("exit your character", StringComparison.OrdinalIgnoreCase))
userReportedExitText =
$"0x{tableId:X8}/0x{stringId:X8}: \"{raw}\"";
}
}
}
var summary = new StringBuilder()
.AppendLine("[escape-sweep] installed-DAT string-table inventory:")
.AppendLine($" tables={tables} strings={strings}")
.AppendLine($" strings with literal \\n escape: {withNewlineEscape}")
.AppendLine($" \\t pairs: {withTabEscape}; \\r pairs: {withCrEscape}; \\q pairs: {withQuoteEscape}")
.AppendLine($" strings with metalanguage self-escapes: {withMetaSelfEscape}")
.AppendLine($" strings with unrecognized backslash pairs (kept verbatim): {withUnknownPair}")
.AppendLine($" strings containing a REAL CR character: {withRealCr}")
.AppendLine(" \\n-escape counts per table: "
+ string.Join(", ", perTableNewlines.Select(
static pair => $"0x{pair.Key:X8}={pair.Value}")))
.AppendLine(" examples:");
foreach (string example in examples)
summary.AppendLine($" {example}");
summary.AppendLine(userReportedExitText is null
? " user-reported exit-world text: NOT found by content scan"
: $" user-reported exit-world text: {userReportedExitText}");
Console.WriteLine(summary.ToString());
// The escape class must genuinely exist in shipping data — if this
// ever goes to zero the sweep (and the source decode) is measuring
// nothing and needs re-examination, not silent success.
Assert.True(
withNewlineEscape > 0,
"expected at least one installed string carrying the literal \\n escape");
}
private static string Truncate(string value) =>
(value.Length <= 90 ? value : value[..90] + "…")
.Replace("\r", "").Replace("\n", "");
}