using System.Text.Json; using System.Text.Json.Nodes; using XFEEDToolBox.Core.Galaxy; using XFEEDToolBox.Core.Navigation; using XFEExtension.NetCore.XUnit.Attributes; namespace XFEEDToolBox.Test; [TestFixture] public sealed class GalaxyCurrentRouteChoicesTests { private static readonly int[] Ids=[2,3,4,6,7,8,10]; private static JsonObject Wire(bool known=true) { var categories=new JsonArray(); foreach(var id in Ids)categories.Add(new JsonObject{["categoryId"]=id,["affectsRoutePlotting"]=known?JsonValue.Create(false):null, ["choices"]=known?new JsonArray(new JsonObject{["index"]=1,["settingsName"]="Lawless",["key"]="lawless",["selected"]=false}, new JsonObject{["index"]=0,["settingsName"]="Anarchy",["key"]="anarchy",["selected"]=true}):null}); return new(){["scope"]="current-original-route-filter-choices",["capturedAtTick"]="9007199254740995",["contextSystemAddress"]="9007199254740993",["categories"]=categories}; } private static GalaxyCurrentRouteChoices Parse(JsonObject value)=>GalaxyCurrentRouteChoices.FromWire(Check.Json(value.ToJsonString()))!; [Test] public void ActualIndicesNamesSelectionsAndFalseRouteFlagRemainIndependentForAllSevenCategories() { var choices=Parse(Wire());Check.Equal(9007199254740995UL,choices.CapturedAtTick);Check.Equal(9007199254740993L,choices.ContextSystemAddress); Check.That(choices.Categories.Select(c=>c.CategoryId).SequenceEqual(Ids)); foreach(var category in choices.Categories) { Check.That(category.AffectsRoutePlotting==false&&category.Choices is{Count:2}); Check.Equal("Anarchy",category.Choices![0].SettingsName);Check.Equal("anarchy",category.Choices[0].Key); Check.That(category.Choices[0].Selected&&!category.Choices[1].Selected);Check.Equal(1,category.Choices[1].Index); } } [Test] public void MergingLiveNamesDoesNotEditOrdinaryValuesSavedValuesOrUnrelatedStarRouteSettings() { IReadOnlySet values=new HashSet{"anarchy"};var saved=new Dictionary?>{{GalaxyFilterCategory.Economy,new HashSet{"industrial"}}}; var filter=new GalaxyMapFilter{Category=GalaxyFilterCategory.Security,Values=values,SavedValues=saved, OriginalRouteFilters=new Dictionary{{GalaxyFilterCategory.StarClass,true}}}; var merged=Parse(Wire()).MergeInto(filter); Check.That(ReferenceEquals(values,merged.Values)&&ReferenceEquals(saved,merged.SavedValues)&&merged.OriginalRouteFilters[GalaxyFilterCategory.StarClass]); Check.That(merged.OriginalRouteOptionKeys[GalaxyFilterCategory.Security].SetEquals(["anarchy","lawless"])); Check.That(merged.OriginalRouteSelectedKeys[GalaxyFilterCategory.Security].SetEquals(["anarchy"])); Check.That(GameRouteMapFilter.TryFromFilter(merged,true,out var route,out _));Check.That(!route!.AffectsRoutePlotting&&route.SelectedKeys.SequenceEqual(["anarchy"])); } [Test] public void StructurallyIdenticalFreshSnapshotsReturnTheSameFilterRecord() { var choices=Parse(Wire());var filter=choices.MergeInto(new GalaxyMapFilter()); var fresh=Parse(Wire()) with{CapturedAtTick=choices.CapturedAtTick+1}; Check.That(ReferenceEquals(filter,fresh.MergeInto(filter))); Check.That(new GalaxyRouteChoicesSourceKey(42,10,100)!=new GalaxyRouteChoicesSourceKey(42,11,100)); Check.That(new GalaxyRouteChoicesSourceKey(42,10,100)!=new GalaxyRouteChoicesSourceKey(43,10,100)); Check.Equal("42|10|100",new GalaxyRouteChoicesSourceKey(42,10,100).ToString()); } [Test] public void ExplicitUnknownClearsOnlyLiveManagedCategoriesAndCannotInventAnEmptyProvider() { var known=Parse(Wire()).MergeInto(new(){Values=new HashSet{"government"}});var oldValues=known.Values; var cleared=Parse(Wire(false)).MergeInto(known); Check.That(cleared.OriginalRouteOptionKeys.Count==0&&cleared.OriginalRouteSelectedKeys.Count==0&&cleared.OriginalRouteFilters.Count==0&&ReferenceEquals(oldValues,cleared.Values)); Check.That(ReferenceEquals(cleared,GalaxyCurrentRouteChoices.ClearLive(cleared))&&GalaxyCurrentRouteChoices.FromWire(Check.Json("null")) is null); var empty=Wire();empty["categories"]![0]!["choices"]=new JsonArray(); Check.Throws(()=>Parse(empty)); } [Test] public void MalformedSourcesNamesIndicesFlagsAndCategoryCoverageAreRejected() { foreach(var mutate in new Action[] { j=>j["contextSystemAddress"]=9007199254740993L,j=>j["contextSystemAddress"]="0",j=>j["categories"]!.AsArray().RemoveAt(0), j=>j["categories"]![0]!["categoryId"]=5,j=>j["categories"]![1]!["categoryId"]=2, j=>j["categories"]![0]!["affectsRoutePlotting"]=null,j=>j["categories"]![0]!["choices"]![0]!["index"]=0, j=>j["categories"]![0]!["choices"]![0]!["index"]=2,j=>j["categories"]![0]!["choices"]![0]!["key"]="anarchy", j=>j["categories"]![0]!["choices"]![0]!["selected"]=1 }){var input=Wire();mutate(input);Check.Throws(()=>Parse(input));} } [Test] public void CatalogueFieldAndSeparateCapabilityRemainOptionalForLegacyProfiles() { var catalog=new NativeGalaxyCatalog(42);catalog.ApplyProtocolDescription(Check.Json("{\"processId\":42,\"galaxyCatalogueProfile\":true}"));Check.That(!catalog.SupportsRouteFilterChoices); catalog.ApplyProtocolDescription(Check.Json("{\"processId\":42,\"routeFilterChoices\":true}"));Check.That(catalog.SupportsRouteFilterChoices); var profile=new JsonObject{["origin"]=new JsonArray(0,0,0),["referenceKind"]="camera-eye",["routeFilterChoices"]=Wire()}; Check.That(NativeGalaxyCatalog.ReadCatalogueProfile(Check.Json(profile.ToJsonString())).CurrentRouteChoices is{Categories.Count:7}); profile.Remove("routeFilterChoices");Check.That(NativeGalaxyCatalog.ReadCatalogueProfile(Check.Json(profile.ToJsonString())).CurrentRouteChoices is null); } }