using Ehwrj.App.Models; using Ehwrj.Core.Geometry; using Ehwrj.Core.Models; using Ehwrj.Core.Services; namespace Ehwrj.Tests; internal static class Program { private static int Main() { try { ParsesMapInfoGridSize(); ParsesMapInfoBoundsAndStringNumbers(); ParsesObjectsAndClassifiesAircraft(); ParsesObjectCoordinateAndDirectionArrays(); ClassifiesTeamsAndObjectives(); ParsesHeadingInDegrees(); ParsesFlightState(); ParsesBattleMessages(); AnalyzesCaptureFixtureQuality(); EnforcesLoopbackNetworkScope(); LocalizesUiTextAndStatus(); ParsesWrappedObjectList(); ProjectsNormalizedCoordinates(); ProjectsBoundedCoordinates(); Console.WriteLine("All tests passed."); return 0; } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return 1; } } private static void ParsesMapInfoGridSize() { var info = MapInfo.FromJson("""{"grid_size":[10,20],"grid_steps":[1,2]}"""); AssertEqual(0, info.MinX, "MinX"); AssertEqual(10, info.MaxX, "MaxX"); AssertEqual(0, info.MinY, "MinY"); AssertEqual(20, info.MaxY, "MaxY"); AssertEqual(1, info.GridStepX, "GridStepX"); AssertEqual(2, info.GridStepY, "GridStepY"); } private static void ParsesMapInfoBoundsAndStringNumbers() { var info = MapInfo.FromJson( """ { "bounds": [["-1,5","-2.25"],["3,5","4.25"]], "grid_steps": ["0,5","1.25"] } """); AssertEqual(-1.5, info.MinX, "bounds MinX"); AssertEqual(3.5, info.MaxX, "bounds MaxX"); AssertEqual(-2.25, info.MinY, "bounds MinY"); AssertEqual(4.25, info.MaxY, "bounds MaxY"); AssertEqual(0.5, info.GridStepX, "string GridStepX"); AssertEqual(1.25, info.GridStepY, "string GridStepY"); } private static void ParsesObjectsAndClassifiesAircraft() { var tracker = new ObjectTracker(); var objects = MapObject.FromJson( """ [ {"id":"self","type":"player_aircraft","x":0.5,"y":0.5}, {"id":"bandit","type":"aircraft","x":0.6,"y":0.6}, {"id":"zone","type":"capture_zone","x":0.2,"y":0.3} ] """, tracker); AssertEqual(3, objects.Count, "object count"); AssertTrue(objects[0].IsPlayer, "player classification"); AssertTrue(objects[1].IsAircraft, "aircraft classification"); AssertTrue(!objects[2].IsAircraft, "zone classification"); } private static void ParsesObjectCoordinateAndDirectionArrays() { var tracker = new ObjectTracker(); var objects = MapObject.FromJson( """ [ { "id":"array-bandit", "icon":"fighter", "team":"enemy", "pos":["0,25","0.75"], "direction":["1","0"], "heading":"180" } ] """, tracker); AssertEqual(0.25, objects[0].X, "array x"); AssertEqual(0.75, objects[0].Y, "array y"); AssertEqual(1, objects[0].DirectionX, "array direction x"); AssertEqual(0, objects[0].DirectionY, "array direction y"); AssertEqual(Math.PI, objects[0].HeadingRadians.GetValueOrDefault(), "string heading radians"); AssertEqual((int)MapObjectKind.Enemy, (int)objects[0].Kind, "array enemy kind"); } private static void ClassifiesTeamsAndObjectives() { var tracker = new ObjectTracker(); var objects = MapObject.FromJson( """ [ {"id":"ally","type":"aircraft","team":"ally","x":0.1,"y":0.2}, {"id":"enemy","type":"aircraft","team":"enemy","x":0.2,"y":0.3}, {"id":"squad","type":"aircraft","team":"squad","x":0.3,"y":0.4}, {"id":"target","type":"bombing_point","team":"enemy","x":0.4,"y":0.5} ] """, tracker); AssertEqual((int)MapObjectKind.Ally, (int)objects[0].Kind, "ally kind"); AssertEqual((int)MapObjectKind.Enemy, (int)objects[1].Kind, "enemy kind"); AssertEqual((int)MapObjectKind.Squad, (int)objects[2].Kind, "squad kind"); AssertTrue(objects[3].IsEnemyBombingPoint, "enemy bombing point"); } private static void ParsesHeadingInDegrees() { var tracker = new ObjectTracker(); var objects = MapObject.FromJson("""[{"id":"p","type":"player_aircraft","heading":90,"x":0.5,"y":0.5}]""", tracker); AssertTrue(objects[0].HeadingRadians.HasValue, "heading exists"); AssertEqual(Math.PI / 2, objects[0].HeadingRadians.GetValueOrDefault(), "heading radians"); } private static void ParsesFlightState() { var state = FlightState.FromJson("""{"TAS, km/h":720,"IAS, km/h":"650","Vy, m/s":36,"H, m":2500}"""); AssertEqual(720, state.TrueAirspeedKmh, "tas"); AssertEqual(650, state.IndicatedAirspeedKmh, "ias"); AssertTrue(state.Mach.HasValue, "mach"); AssertTrue(state.ClimbAngleDegrees.HasValue, "climb angle"); } private static void ParsesBattleMessages() { var messages = BattleMessage.FromJson( """ { "events": [ {"text":"Enemy spotted","enemy":true}, {"message":"Ally captured A","enemy":false} ] } """); AssertEqual(2, messages.Count, "message count"); AssertEqual("Enemy spotted", messages[0].Text, "cleaned message"); AssertTrue(messages[0].Enemy == true, "enemy flag"); AssertTrue(messages[1].Enemy == false, "ally flag"); } private static void AnalyzesCaptureFixtureQuality() { var directory = Path.Combine(Path.GetTempPath(), $"ehwrj-capture-test-{Guid.NewGuid():N}"); Directory.CreateDirectory(directory); try { File.WriteAllText(Path.Combine(directory, "map_info.json"), """{"grid_size":[10,20],"grid_steps":[1,2]}"""); File.WriteAllText( Path.Combine(directory, "map_obj.json"), """ [ {"id":"self","type":"player_aircraft","team":"ally","x":0.5,"y":0.5}, {"id":"wing","type":"aircraft","team":"ally","x":0.4,"y":0.5}, {"id":"bandit","type":"aircraft","team":"enemy","x":0.6,"y":0.5}, {"id":"target","type":"bombing_point","team":"enemy","x":0.7,"y":0.5}, {"id":"mystery","type":"supply_marker","x":0.2,"y":0.8,"custom_flag":"sample"} ] """); File.WriteAllBytes(Path.Combine(directory, "map.img"), [1, 2, 3, 4]); File.WriteAllText(Path.Combine(directory, "state.json"), """{"TAS, km/h":720,"H, m":2500}"""); File.WriteAllText(Path.Combine(directory, "hudmsg.json"), """{"events":[{"text":"Enemy spotted","enemy":true}]}"""); File.WriteAllText(Path.Combine(directory, "gamechat.json"), """["Good luck"]"""); var report = CaptureFixtureAnalyzer.AnalyzeDirectory(directory); AssertTrue(report.IsUsableForReplay, "capture replay usable"); AssertEqual(5, report.ObjectCount, "capture object count"); AssertEqual(1, report.PlayerCount, "capture player count"); AssertEqual(2, report.AlliedAircraftCount, "capture allied aircraft count"); AssertEqual(1, report.EnemyAircraftCount, "capture enemy aircraft count"); AssertEqual(1, report.ObjectiveCount, "capture objective count"); AssertEqual(1, report.UnknownObjectCount, "capture unknown object count"); AssertTrue(report.ObjectFields.Any(static f => f.Name == "custom_flag" && f.Count == 1), "capture object field coverage"); AssertTrue(report.UnknownObjectSamples.Any(static s => s.Contains("supply_marker", StringComparison.Ordinal)), "capture unknown sample"); AssertTrue(report.StateFieldNames.Contains("TAS, km/h", StringComparer.Ordinal), "capture state field names"); AssertTrue(report.HasSpeedTelemetry, "capture speed telemetry"); AssertTrue(report.HasAltitudeTelemetry, "capture altitude telemetry"); AssertEqual(1, report.HudMessageCount, "capture hud messages"); AssertEqual(1, report.ChatMessageCount, "capture chat messages"); AssertTrue(report.ToText().Contains("Replay usable: yes", StringComparison.Ordinal), "capture report text"); AssertTrue(report.ToText().Contains("Object field coverage:", StringComparison.Ordinal), "capture field report text"); } finally { Directory.Delete(directory, recursive: true); } } private static void EnforcesLoopbackNetworkScope() { AssertTrue(LoopbackGuard.IsLoopbackHttp(new Uri("http://127.0.0.1:8111/")), "127 loopback allowed"); AssertTrue(LoopbackGuard.IsLoopbackHttp(new Uri("http://localhost:8111/")), "localhost allowed"); AssertTrue(LoopbackGuard.IsLoopbackHost("127.0.0.1"), "127 host allowed"); AssertTrue(LoopbackGuard.IsLoopbackHost("localhost"), "localhost host allowed"); AssertTrue(!LoopbackGuard.IsLoopbackHttp(new Uri("https://127.0.0.1:8111/")), "https rejected"); AssertTrue(!LoopbackGuard.IsLoopbackHttp(new Uri("http://example.com:8111/")), "external host rejected"); AssertTrue(!LoopbackGuard.IsLoopbackHost("0.0.0.0"), "wildcard host rejected"); } private static void LocalizesUiTextAndStatus() { var english = UiText.For("en-US"); var korean = UiText.For("ko-KR"); AssertEqual("Language", english.Language, "english language label"); AssertEqual("언어", korean.Language, "korean language label"); AssertEqual("127.0.0.1:8111 연결됨", korean.FormatStatus("Connected to 127.0.0.1:8111"), "localized connected status"); AssertTrue(UiText.LanguageOptions.Any(static o => o.Code == "ko-KR"), "korean language option"); } private static void ProjectsNormalizedCoordinates() { var point = CoordinateProjector.Project( new MapObject { Id = "p", X = 0.25, Y = 0.75 }, MapInfo.Empty, new MapViewport(0, 0, 400, 200)); AssertTrue(point.HasValue, "projection exists"); var projected = point.GetValueOrDefault(); AssertEqual(100, projected.X, "projected x"); AssertEqual(150, projected.Y, "projected y"); } private static void ParsesWrappedObjectList() { var tracker = new ObjectTracker(); var objects = MapObject.FromJson( """ { "objects": [ {"id":"a","icon":"fighter","x":"0.1","y":"0.9"} ] } """, tracker); AssertEqual(1, objects.Count, "wrapped object count"); AssertTrue(objects[0].IsAircraft, "wrapped aircraft classification"); AssertEqual(0.1, objects[0].X, "wrapped x"); AssertEqual(0.9, objects[0].Y, "wrapped y"); } private static void ProjectsBoundedCoordinates() { var info = new MapInfo(-100, 100, -50, 50, null, null, null); var point = CoordinateProjector.Project( new MapObject { Id = "p", X = 0, Y = 25 }, info, new MapViewport(10, 20, 200, 100)); AssertTrue(point.HasValue, "bounded projection exists"); var projected = point.GetValueOrDefault(); AssertEqual(110, projected.X, "bounded x"); AssertEqual(95, projected.Y, "bounded y"); } private static void AssertTrue(bool condition, string name) { if (!condition) { throw new InvalidOperationException($"Assertion failed: {name}"); } } private static void AssertEqual(double expected, double? actual, string name) { if (!actual.HasValue || Math.Abs(expected - actual.Value) > 0.0001) { throw new InvalidOperationException($"Assertion failed: {name}; expected {expected}, got {actual}"); } } private static void AssertEqual(double expected, double actual, string name) { if (Math.Abs(expected - actual) > 0.0001) { throw new InvalidOperationException($"Assertion failed: {name}; expected {expected}, got {actual}"); } } private static void AssertEqual(int expected, int actual, string name) { if (expected != actual) { throw new InvalidOperationException($"Assertion failed: {name}; expected {expected}, got {actual}"); } } private static void AssertEqual(string expected, string actual, string name) { if (!string.Equals(expected, actual, StringComparison.Ordinal)) { throw new InvalidOperationException($"Assertion failed: {name}; expected {expected}, got {actual}"); } } }