Files
Operation-Blue-Laminate-v2/BlueLaminate/BlueLaminate.Tests/Tui/TradeupBrowserTests.cs
2026-06-02 13:31:27 -05:00

114 lines
4.4 KiB
C#

using BlueLaminate.Cli.Tui;
using BlueLaminate.Core.Tradeups;
using Spectre.Console;
using Spectre.Console.Testing;
using Xunit;
namespace BlueLaminate.Tests.Tui;
/// <summary>
/// Render-path smoke tests for the TUI: the navigation loop needs a live terminal, but the
/// rendering (and its Spectre markup) is exercised against a recording console so a stray
/// markup tag or unescaped name fails the build instead of crashing on first launch.
/// </summary>
public class TradeupBrowserTests
{
private static InputListing Input(string name, string market, string? inspect, decimal price)
=> new(SkinId: 1, MarketHashName: name, Marketplace: market,
InspectLink: inspect, ExternalId: "999", FloatValue: 0.1234m, Price: price);
private static TradeupCandidate Candidate(
string collection = "The Sample Collection",
bool statTrak = false,
bool guaranteed = true,
decimal worstNet = 120m,
IReadOnlyList<TradeupOutcome>? outcomes = null,
IReadOnlyList<InputListing>? inputs = null)
{
outcomes ??= new[]
{
new TradeupOutcome(10, "Output Alpha", 0.0672m, WearBand.FactoryNew, 0.5m, 175.75m, 26),
new TradeupOutcome(11, "Output Beta", 0.0695m, WearBand.FactoryNew, 0.5m, null, 0),
};
inputs ??= new[]
{
Input("AK-47 | Sample (Field-Tested)", "csfloat",
"steam://rungame/730/0/+csgo_econ_action_preview%20ABC123", 1.94m),
Input("MP9 | Sample (Minimal Wear)", "csmoney", null, 6.52m),
};
return new TradeupCandidate(
CollectionId: 1,
CollectionName: collection,
InputRarity: WeaponRarity.Classified,
OutputRarity: WeaponRarity.Covert,
StatTrak: statTrak,
AverageFraction: 0.0695m,
InputCost: 33.16m,
ExpectedNet: 120.53m,
WorstCaseNet: worstNet,
Guaranteed: guaranteed,
Inputs: inputs,
Outcomes: outcomes,
Composition: new[] { new TradeupContribution(1, collection, WeaponRarity.Covert, 10) });
}
[Fact]
public void RenderDetail_emits_the_key_sections_without_markup_errors()
{
var console = new TestConsole();
TradeupBrowser.RenderDetail(console, Candidate(), index: 0);
var output = console.Output;
Assert.Contains("The Sample Collection", output);
Assert.Contains("Possible outputs", output);
Assert.Contains("Buy list", output);
Assert.Contains("Output Alpha", output);
Assert.Contains("unpriced", output); // the null-priced output is shown, not dropped
}
[Theory]
[InlineData(false, true, 120)] // guaranteed, positive worst-case (green)
[InlineData(true, true, 120)] // StatTrak variant
[InlineData(false, false, -40)] // not guaranteed, negative worst-case (red)
public void SummaryLine_is_always_valid_markup(bool statTrak, bool guaranteed, int worstNet)
{
var line = TradeupBrowser.SummaryLine(
Candidate(statTrak: statTrak, guaranteed: guaranteed, worstNet: worstNet), index: 3);
// The Markup ctor parses the string and throws on a malformed tag.
_ = new Markup(line);
}
[Fact]
public void Settings_screen_renders_and_runs_on_enter()
{
var console = new TestConsole().Interactive();
console.Input.PushKey(ConsoleKey.Enter); // first choice is "Run search"
var options = new BlueLaminate.Core.Options.TradeupOptions();
var top = 20;
var action = TradeupBrowser.PromptSettings(console, options, ref top);
Assert.Equal(SettingsAction.RunSearch, action);
Assert.Contains("StatTrak universe", console.Output);
Assert.Contains("Run search", console.Output);
}
[Fact]
public void Names_and_links_with_markup_characters_are_escaped()
{
var console = new TestConsole();
var hostile = Candidate(
collection: "Danger [Collection]",
outcomes: new[] { new TradeupOutcome(10, "Skin [X]", 0.1m, WearBand.MinimalWear, 1m, 5m, 3) },
inputs: new[] { Input("Weapon [Y] (FT)", "market", inspect: null, price: 1m) });
// Would throw a markup-parse exception if any bracketed field reached Spectre unescaped.
TradeupBrowser.RenderDetail(console, hostile, index: 0);
Assert.Contains("Danger", console.Output);
}
}