diff --git a/StarterNG.Tests/BlackBox/BlackBoxListingTests.cs b/StarterNG.Tests/BlackBox/BlackBoxListingTests.cs index 420be18..afff660 100644 --- a/StarterNG.Tests/BlackBox/BlackBoxListingTests.cs +++ b/StarterNG.Tests/BlackBox/BlackBoxListingTests.cs @@ -144,4 +144,13 @@ public class BlackBoxListingTests [InlineData("Bałtyk zima.scn", "Ba_tyk_zima")] public void The_scenery_is_named_as_the_simulator_names_the_black_box(string scenery, string stem) => Assert.Equal(stem, StarterNG.Application.HaslerTapes.SceneryStem(scenery)); + + [Theory] + [InlineData("Ba_tyk_zima", true)] // Windows: 'ł' is one byte of its code page + [InlineData("Ba__tyk_zima", true)] // Linux: two bytes of UTF-8 + [InlineData("BA__TYK_ZIMA", true)] + [InlineData("Baltyk_zima", false)] + public void A_letter_outside_ascii_matches_however_many_bytes_it_was(string named, bool same) => + Assert.Equal(same, StarterNG.Application.HaslerTapes.SameStem( + StarterNG.Application.HaslerTapes.SceneryStem("Bałtyk zima.scn"), named)); } diff --git a/StarterNG/Application/HaslerTapes.cs b/StarterNG/Application/HaslerTapes.cs index 4a8e38a..34e55f0 100644 --- a/StarterNG/Application/HaslerTapes.cs +++ b/StarterNG/Application/HaslerTapes.cs @@ -328,9 +328,23 @@ public sealed class HaslerTapes if (NamedBy(box.Path) is not { } named) return launches.LastOrDefault(l => l.Covers(box.LastWriteUtc)); var launch = launches.LastOrDefault(l => l.Covers(named.StartedUtc)); - return launch is not null && string.Equals(SceneryStem(launch.Scenery), named.Scenery, StringComparison.OrdinalIgnoreCase) - ? launch - : null; + return launch is not null && SameStem(SceneryStem(launch.Scenery), named.Scenery) ? launch : null; + } + + /// + /// Two stems of one scenery. The simulator turns each byte of a letter outside ASCII into '_': one for 'ł' + /// on Windows, two where the name comes as UTF-8. Runs of '_' are taken as one, and the case doesn't count. + /// + public static bool SameStem(string a, string b) => + string.Equals(Squeezed(a), Squeezed(b), StringComparison.OrdinalIgnoreCase); + + private static string Squeezed(string stem) + { + var text = new StringBuilder(stem.Length); + foreach (char c in stem) + if (c != '_' || text.Length == 0 || text[^1] != '_') + text.Append(c); + return text.ToString(); } private const string BlackBoxStamp = "yyyy-MM-dd_HH-mm-ss";