fix(tapes): a scenery named with letters outside ASCII matches its black box on Linux too, where each byte of them is a '_'

This commit is contained in:
maj00r
2026-11-11 18:14:44 +01:00
parent cf5cea26ad
commit ef551a4ee7
2 changed files with 26 additions and 3 deletions

View File

@@ -144,4 +144,13 @@ public class BlackBoxListingTests
[InlineData("Bałtyk zima.scn", "Ba_tyk_zima")] [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) => 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)); 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));
} }

View File

@@ -328,9 +328,23 @@ public sealed class HaslerTapes
if (NamedBy(box.Path) is not { } named) if (NamedBy(box.Path) is not { } named)
return launches.LastOrDefault(l => l.Covers(box.LastWriteUtc)); return launches.LastOrDefault(l => l.Covers(box.LastWriteUtc));
var launch = launches.LastOrDefault(l => l.Covers(named.StartedUtc)); var launch = launches.LastOrDefault(l => l.Covers(named.StartedUtc));
return launch is not null && string.Equals(SceneryStem(launch.Scenery), named.Scenery, StringComparison.OrdinalIgnoreCase) return launch is not null && SameStem(SceneryStem(launch.Scenery), named.Scenery) ? launch : null;
? launch }
: null;
/// <summary>
/// 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.
/// </summary>
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"; private const string BlackBoxStamp = "yyyy-MM-dd_HH-mm-ss";