Files
card_game/tests/Game.Core.Tests/RunTests.cs
T
chenmoranzhiandCursor ae13f1d06a 落地无头规则引擎与局内内容,便于命令行复现对战。
规则、卡包与测试放在同一套核心里,避免表现层自行结算。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 02:06:23 +08:00

89 lines
3.4 KiB
C#

using CardGame.Core;
using Xunit;
namespace Game.Core.Tests;
public sealed class RunTests
{
[Fact]
public void Start_builds_starting_package_with_holders()
{
var run = RunProgress.Start(42, Cards.Catalog);
Assert.Equal(16, run.Owned.Count);
Assert.Contains(run.Owned, c => c.DefinitionId == "card.guard.patrol" && c.HolderId == Factions.Guard);
Assert.Contains(run.Owned, c => c.DefinitionId == "card.cult.believer" && c.HolderId == Factions.Cult);
}
[Fact]
public void CreateFromRun_applies_owned_stat_overrides()
{
var run = RunProgress.Start(7, Cards.Catalog);
var patrol = run.Owned.First(c => c.DefinitionId == "card.guard.patrol");
patrol.Cost = 0;
patrol.Attack = 9;
var state = MatchSetup.CreateFromRun(run, Cards.Catalog, shuffle: false);
var inDeckOrHand = state.Players[0].Deck.Concat(state.Players[0].Hand)
.First(e => e.Definition.Id == "card.guard.patrol" && e.Attack == 9);
Assert.Equal(0, inDeckOrHand.Cost);
Assert.Equal(9, inDeckOrHand.Attack);
Assert.Equal(Factions.Guard, inDeckOrHand.HolderId);
Assert.Equal(run.Stats.HealReceived, state.Players[0].Run.HealReceived);
}
[Fact]
public void Reward_pool_includes_base_pack_cards()
{
var run = RunProgress.Start(1, Cards.Catalog);
var state = MatchSetup.CreateFromRun(run, Cards.Catalog, shuffle: false);
var packs = PackJson.LoadDirectory(Path.Combine(AppContext.BaseDirectory, "content", "packs"));
var pool = RunRewards.ActivePool(state, 0, packs);
Assert.Contains("card.example.spark", pool);
Assert.Contains("card.example.wisp", pool);
}
[Fact]
public void Adding_reward_with_holder_grows_owned_and_survives_next_fight_setup()
{
var run = RunProgress.Start(3, Cards.Catalog);
var before = run.Owned.Count;
RunRewards.AddCard(run, Cards.Spark, Factions.Guard);
Assert.Equal(before + 1, run.Owned.Count);
var upgraded = run.Owned[^1];
Assert.True(RunRewards.ApplyUpgrade(upgraded, Cards.Spark, SimpleUpgrade.ReduceCost));
Assert.Equal(Cards.Spark.Cost - 1, upgraded.Cost);
var state = MatchSetup.CreateFromRun(run, Cards.Catalog, shuffle: false);
var spark = state.Players[0].Deck.Concat(state.Players[0].Hand)
.First(e => e.Definition.Id == Cards.Spark.Id);
Assert.Equal(Cards.Spark.Cost - 1, spark.Cost);
Assert.Equal(Factions.Guard, spark.HolderId);
}
[Fact]
public void SyncStatsFrom_carries_pack_progress_into_next_fight()
{
var run = RunProgress.Start(9, Cards.Catalog);
var state = MatchSetup.CreateFromRun(run, Cards.Catalog, shuffle: false);
state.Players[0].Run.HealReceived = 4;
state.Players[0].Run.AttacksDeclared = 2;
run.SyncStatsFrom(state, 0);
var next = MatchSetup.CreateFromRun(run, Cards.Catalog, shuffle: false);
Assert.Equal(4, next.Players[0].Run.HealReceived);
Assert.Equal(2, next.Players[0].Run.AttacksDeclared);
}
[Fact]
public void RollOffer_is_deterministic_for_same_rng_stream()
{
var pool = new[] { "a", "b", "c", "d" };
var a = RunRewards.RollOffer(new GameRng(99), pool, 3);
var b = RunRewards.RollOffer(new GameRng(99), pool, 3);
Assert.Equal(a, b);
Assert.Equal(3, a.Count);
Assert.Equal(a.Distinct().Count(), a.Count);
}
}