using System.Text.Json; using XFEExtension.NetCore.XUnit.Attributes; using XFEEDToolBox.Core.Data; using XFEEDToolBox.Core.Models; namespace XFEEDToolBox.Test; [TestFixture] public class ObservedFixtureTests { [Test] public void ParsesCapturedListAndTradeResponseFields() { using var doc = JsonDocument.Parse(File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "Fixtures", "captured-commodities.json"))); var samples = doc.RootElement.EnumerateArray().ToArray(); Check.Equal(2, samples.Length); foreach (var sample in samples) { var time = sample.Time("observedAt")!.Value; var quotes = sample.Get("commodities").Items().Select(x => MarketParser.ParseQuote(x, 3224123392, time, DataSource.Capture)).ToArray(); Check.Equal("platinum", quotes[0].Commodity); Check.Equal(223785L, quotes[0].SellPrice); Check.Equal(time, quotes[0].CollectedAt); Check.That(quotes.All(q => q.Source == DataSource.Capture)); } } } [TestFixture, Explicit("Reads user supplied evidence / external public data; opt in manually.")] public class LiveIntegrationTests { private static void Save(string file, object result) { var folder = Path.GetFullPath(Path.Combine("artifacts", "integration")); Directory.CreateDirectory(folder); File.WriteAllText(Path.Combine(folder, file), JsonSerializer.Serialize(result, ToolboxSettings.JsonOptions)); } [Test] public async Task ImportsActualCaptureArchive() { var path = Environment.GetEnvironmentVariable("XFE_ED_CAPTURE") ?? throw new InvalidOperationException("Set XFE_ED_CAPTURE to the provided capture archive."); using var temp = new TemporaryDirectory(); var repo = temp.Repository(); var count = await CaptureImporter.ImportAsync(path, repo); var rows = repo.Search("", 3224123392, 0, 1000); Save("capture-import.json", new { count.Stations, count.Quotes, storedQuotes = rows.Count, onlyHistorical = rows.All(x => x.Quote.Source == DataSource.Capture), importedInventory = false }); Check.Equal(1, count.Stations); Check.Equal(404, rows.Count); Check.That(rows.All(x => x.Quote.Source == DataSource.Capture)); } [Test] public async Task ReadsActualLocalJournal() { await using var monitor = new JournalMonitor(new ToolboxSettings().JournalDirectory); var quoteCount = 0; monitor.MarketChanged += m => quoteCount = m.Quotes.Count; await monitor.StartAsync(); var p = monitor.State; var active = p.Ships.FirstOrDefault(x => x.ShipId == p.CurrentShipId); JsonElement expectedLoadout = default; foreach (var path in Directory.EnumerateFiles(monitor.DirectoryPath, "Journal.*.log").Order(StringComparer.Ordinal)) { using var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); using var reader = new StreamReader(file); while (await reader.ReadLineAsync() is { } line) { try { using var doc = JsonDocument.Parse(line); var e = doc.RootElement; if (e.Text("event") == "Loadout" && e.Long("ShipID", -1) == p.CurrentShipId && e.Time() <= p.UpdatedAt) expectedLoadout = e.Clone(); } catch (JsonException) { } } } var expectedModules = expectedLoadout.Get("Modules").EnumerateArray().ToArray(); Check.Equal(expectedModules.Length, active!.Modules.Count); for (var i = 0; i < expectedModules.Length; i++) { var raw = expectedModules[i]; var parsed = active.Modules[i]; Check.Equal(raw.GetProperty("Slot").GetString(), parsed.Slot); Check.Equal(raw.GetProperty("Item").GetString(), parsed.Item); Check.Equal(raw.GetProperty("On").GetBoolean(), parsed.Enabled); Check.Equal(raw.GetProperty("Priority").GetInt32(), parsed.Priority); if (raw.TryGetProperty("Engineering", out var engineering)) { var modifiers = engineering.GetProperty("Modifiers").EnumerateArray().ToArray(); Check.Equal(modifiers.Length, parsed.Engineering!.Modifiers.Count); for (var m = 0; m < modifiers.Length; m++) { Check.Equal(modifiers[m].GetProperty("Label").GetString(), parsed.Engineering.Modifiers[m].Label); if (modifiers[m].TryGetProperty("Value", out var value) && value.ValueKind == JsonValueKind.Number) Check.Equal(value.GetDouble(), parsed.Engineering.Modifiers[m].Value!.Value); } } } Save("local-journal.json", new { balanceAvailable = p.Credits != null, p.CreditsReliable, capacityAvailable = p.CargoCapacity > 0, cargoItems = p.Inventory.Count, materialItems = p.Materials.Count, ships = p.Ships.Count, configuredShips = p.Ships.Count(x => x.ConfigurationAt != null), activeShipType = active?.Type, activeModules = active?.Modules.Count, engineeredModules = active?.Modules.Count(x => x.Engineering != null), engineeringParameters = active?.Modules.Sum(x => x.Engineering?.Modifiers.Count ?? 0), storedModules = p.StoredModules.Count, quoteCount, eventsRead = monitor.EventsRead, independentlyComparedModules = expectedModules.Length, checks = ReadAcceptance.Build(p, monitor.LocalMarket), updatedAt = p.UpdatedAt, gameBuild = p.GameBuild }); Check.That(monitor.State.Credits != null); Check.That(quoteCount > 0); Check.That(active?.Modules.Count > 0, "Current ship Loadout was not read."); } [Test] public async Task ReadsActualSpanshSystem() { using var temp = new TemporaryDirectory(); var repo = temp.Repository(); using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(25) }; using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(40)); var result = await new SpanshImporter(repo, http).ImportSystemAsync("Vaka", token: timeout.Token); var origin = repo.GetStation(3224123392); Save("spansh.json", new { result.Systems, result.Stations, result.Quotes, originCoordinates = origin?.Position, originSecurity = origin?.Security, originDistanceLs = origin?.DistanceToArrivalLs }); Check.That(result.Quotes > 0 && origin?.Position != null && origin.Security != SecurityLevel.Unknown); } [Test] public async Task ReceivesActualEddnStream() { using var temp = new TemporaryDirectory(); var repo = temp.Repository(); await using var feed = new EddnSubscriber(repo); feed.Start("tcp://eddn.edcd.io:9500"); var until = DateTimeOffset.UtcNow.AddSeconds(45); while (feed.MarketsAccepted == 0 && DateTimeOffset.UtcNow < until) await Task.Delay(250); Save("eddn.json", new { feed.MessagesReceived, feed.MarketsAccepted, feed.Status, feed.LastMessageAt, actualStreamValidated = feed.MessagesReceived > 0, commodityValidated = feed.MarketsAccepted > 0, storedQuotes = repo.Statistics().Quotes }); Check.That(feed.MarketsAccepted > 0, "No live commodity snapshot was accepted during the 45 second observation window."); } }