From 0e490e1f1a44df499c74c100a5bc2b3596284058 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Mon, 31 Aug 2026 19:33:26 +0200 Subject: [PATCH 1/4] fix: damage calculator used wrong formula + added tests to cover it --- OpenPolytopia.Common/DamageCalculator.cs | 6 +- .../test/src/DamageCalculatorTest.cs | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 OpenPolytopia/test/src/DamageCalculatorTest.cs diff --git a/OpenPolytopia.Common/DamageCalculator.cs b/OpenPolytopia.Common/DamageCalculator.cs index 09ab3f86..14ad2c50 100644 --- a/OpenPolytopia.Common/DamageCalculator.cs +++ b/OpenPolytopia.Common/DamageCalculator.cs @@ -23,8 +23,10 @@ public static void ComputeMeleeDamage(uint attack, uint hp, uint maxHp, uint ene var attackForce = attack * ((float)hp / maxHp); var defenseForce = enemyDefense * ((float)enemyHp / enemyMaxHp) * enemyDefenseBonus; var totalDamage = attackForce + defenseForce; - attackDamage = (uint)MathF.Round((attackForce / totalDamage) * attack * 4.5f); - defenseDamage = (uint)MathF.Round((defenseForce / totalDamage) * defenseForce * 4.5f); + // Polytopia rounds halves up, while MathF.Round defaults to banker's rounding + attackDamage = (uint)MathF.Round((attackForce / totalDamage) * attack * 4.5f, MidpointRounding.AwayFromZero); + defenseDamage = + (uint)MathF.Round((defenseForce / totalDamage) * enemyDefense * 4.5f, MidpointRounding.AwayFromZero); } /// diff --git a/OpenPolytopia/test/src/DamageCalculatorTest.cs b/OpenPolytopia/test/src/DamageCalculatorTest.cs new file mode 100644 index 00000000..246599c5 --- /dev/null +++ b/OpenPolytopia/test/src/DamageCalculatorTest.cs @@ -0,0 +1,84 @@ +namespace OpenPolytopia; + +using Chickensoft.GoDotTest; +using Common; +using Godot; +using Shouldly; + +public class DamageCalculatorTest(Node testScene) : TestClass(testScene) { + [Test] + public void TestEvenMatch() { + // two full health warriors trade 5 damage each way + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); + attackDamage.ShouldBe(5u); + defenseDamage.ShouldBe(5u); + } + + [Test] + public void TestWoundedAttacker() { + // a wounded attacker hits for less and takes more in return + DamageCalculator.ComputeMeleeDamage(2, 5, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); + attackDamage.ShouldBe(3u); + defenseDamage.ShouldBe(6u); + } + + [Test] + public void TestWoundedDefender() { + // a wounded defender takes more and retaliates for less + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 5, 10, out var attackDamage, out var defenseDamage); + attackDamage.ShouldBe(6u); + defenseDamage.ShouldBe(3u); + } + + [Test] + public void TestDefenseBonus() { + // the retaliation scales linearly with the defense, not with the bonus applied to it + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage, 1.5f); + attackDamage.ShouldBe(4u); + defenseDamage.ShouldBe(5u); + + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out attackDamage, out defenseDamage, 4.0f); + attackDamage.ShouldBe(2u); + defenseDamage.ShouldBe(7u); + } + + [Test] + public void TestUnevenStats() { + // a stronger attacker against a full health warrior + DamageCalculator.ComputeMeleeDamage(3, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); + attackDamage.ShouldBe(8u); + defenseDamage.ShouldBe(4u); + + // more health doesn't change the outcome as long as both are undamaged + DamageCalculator.ComputeMeleeDamage(3, 15, 15, 2, 10, 10, out attackDamage, out defenseDamage); + attackDamage.ShouldBe(8u); + defenseDamage.ShouldBe(4u); + + DamageCalculator.ComputeMeleeDamage(5, 40, 40, 2, 10, 10, out attackDamage, out defenseDamage); + attackDamage.ShouldBe(16u); + defenseDamage.ShouldBe(3u); + } + + [Test] + public void TestRoundsHalvesUp() { + // 5 * (2 / 4) * 4.5 rounds up to 5, banker's rounding would give 4 + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out _); + attackDamage.ShouldBe(5u); + } + + [Test] + public void TestRangedDamage() { + // ranged attacks deal the melee attack damage without taking any retaliation + DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 5, 10, out var attackDamage, out _); + DamageCalculator.ComputeRangedDamage(2, 10, 10, 2, 5, 10).ShouldBe(attackDamage); + DamageCalculator.ComputeRangedDamage(2, 10, 10, 2, 10, 10, 1.5f).ShouldBe(4u); + } + + [Test] + public void TestSplashDamage() { + // splash is half the ranged damage, rounded down + DamageCalculator.ComputeSplashDamage(2, 10, 10, 2, 10, 10).ShouldBe(2u); + DamageCalculator.ComputeSplashDamage(3, 10, 10, 2, 10, 10).ShouldBe(4u); + DamageCalculator.ComputeSplashDamage(2, 10, 10, 2, 10, 10, 1.5f).ShouldBe(2u); + } +} From 76cc1283466c547e4b7540dee3df92ae4e670323 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Mon, 31 Aug 2026 19:36:01 +0200 Subject: [PATCH 2/4] fix: wrong direction computation + added tests --- OpenPolytopia.Common/Directions.cs | 11 ++-- OpenPolytopia/test/src/DirectionsTest.cs | 71 ++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 OpenPolytopia/test/src/DirectionsTest.cs diff --git a/OpenPolytopia.Common/Directions.cs b/OpenPolytopia.Common/Directions.cs index f6092cdf..428c396b 100644 --- a/OpenPolytopia.Common/Directions.cs +++ b/OpenPolytopia.Common/Directions.cs @@ -28,16 +28,15 @@ public static class WrapperDirection { new(1, 0), new(-1, -1), new(1, -1), - new(-1, -1), + new(-1, 1), new(1, 1) ]; /// - /// Cast all movement vectors for full 8-directional movement + /// Movement vector of a single direction /// - /// - /// Precomputed array of Vector2I values extracted from Directions. - /// + /// the direction to convert + /// the matching entry of public static Vector2I ToVector2I(this Direction direction) => Directions[(int)direction]; /// @@ -55,7 +54,7 @@ public static class WrapperDirection { /// Up and down movement vectors for vertical constraints /// /// - /// Contains vectors: (0, 1) and (0, -1) + /// Contains vectors: (0, -1) and (0, 1) /// public static readonly Vector2I[] Vertical = [ Direction.Up.ToVector2I(), diff --git a/OpenPolytopia/test/src/DirectionsTest.cs b/OpenPolytopia/test/src/DirectionsTest.cs new file mode 100644 index 00000000..c8029698 --- /dev/null +++ b/OpenPolytopia/test/src/DirectionsTest.cs @@ -0,0 +1,71 @@ +namespace OpenPolytopia; + +using System.Linq; +using Chickensoft.GoDotTest; +using Common; +using Godot; +using Shouldly; + +public class DirectionsTest(Node testScene) : TestClass(testScene) { + [Test] + public void TestCardinalVectors() { + Direction.Up.ToVector2I().ShouldBe(new Vector2I(0, -1)); + Direction.Down.ToVector2I().ShouldBe(new Vector2I(0, 1)); + Direction.Left.ToVector2I().ShouldBe(new Vector2I(-1, 0)); + Direction.Right.ToVector2I().ShouldBe(new Vector2I(1, 0)); + } + + [Test] + public void TestDiagonalVectors() { + Direction.UpLeft.ToVector2I().ShouldBe(new Vector2I(-1, -1)); + Direction.UpRight.ToVector2I().ShouldBe(new Vector2I(1, -1)); + Direction.DownLeft.ToVector2I().ShouldBe(new Vector2I(-1, 1)); + Direction.DownRight.ToVector2I().ShouldBe(new Vector2I(1, 1)); + } + + [Test] + public void TestDiagonalsAreCardinalSums() { + Direction.UpLeft.ToVector2I().ShouldBe(Direction.Up.ToVector2I() + Direction.Left.ToVector2I()); + Direction.UpRight.ToVector2I().ShouldBe(Direction.Up.ToVector2I() + Direction.Right.ToVector2I()); + Direction.DownLeft.ToVector2I().ShouldBe(Direction.Down.ToVector2I() + Direction.Left.ToVector2I()); + Direction.DownRight.ToVector2I().ShouldBe(Direction.Down.ToVector2I() + Direction.Right.ToVector2I()); + } + + [Test] + public void TestAllDirectionsAreDistinct() { + // a duplicated vector means a whole direction is unreachable when pathfinding + WrapperDirection.Directions.Length.ShouldBe(8); + WrapperDirection.Directions.Distinct().Count().ShouldBe(8); + } + + [Test] + public void TestOppositeDirectionsCancelOut() { + (Direction.Up.ToVector2I() + Direction.Down.ToVector2I()).ShouldBe(Vector2I.Zero); + (Direction.Left.ToVector2I() + Direction.Right.ToVector2I()).ShouldBe(Vector2I.Zero); + (Direction.UpLeft.ToVector2I() + Direction.DownRight.ToVector2I()).ShouldBe(Vector2I.Zero); + (Direction.UpRight.ToVector2I() + Direction.DownLeft.ToVector2I()).ShouldBe(Vector2I.Zero); + } + + [Test] + public void TestHorizontalAndVertical() { + WrapperDirection.Horizontal.ShouldBe(new[] { new Vector2I(-1, 0), new Vector2I(1, 0) }); + WrapperDirection.Vertical.ShouldBe(new[] { new Vector2I(0, -1), new Vector2I(0, 1) }); + + // the two sets must not overlap, bridges rely on them being mutually exclusive + WrapperDirection.Horizontal.Intersect(WrapperDirection.Vertical).ShouldBeEmpty(); + } + + [Test] + public void TestEveryNeighborIsReachable() { + // every tile around the origin must be covered exactly once + var origin = new Vector2I(0, 0); + var neighbors = WrapperDirection.Directions.Select(direction => origin + direction).ToList(); + + for (var x = -1; x <= 1; x++) { + for (var y = -1; y <= 1; y++) { + var expected = new Vector2I(x, y); + neighbors.Count(neighbor => neighbor == expected).ShouldBe(expected == origin ? 0 : 1); + } + } + } +} From 0a01368e103f0a4e00687ffe5d3705758ecc3134 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Mon, 31 Aug 2026 19:49:12 +0200 Subject: [PATCH 3/4] feat: separated unit tests from visual tests --- .github/workflows/unit_tests.yaml | 42 +++++++++ .../CityDataTest.cs | 27 +++--- .../DamageCalculatorTest.cs | 19 ++-- .../DirectionsTest.cs | 17 ++-- .../GridTest.cs | 9 +- .../OpenPolytopia.UnitTest.csproj | 26 ++++++ .../PacketTest.cs | 53 ++++++----- .../ScoreTest.cs | 15 ++- .../TechTreeTest.cs | 11 +-- .../TerrainGenerationTest.cs | 19 ++-- .../TileTest.cs | 21 ++--- .../TroopManagerTest.cs | 18 ++-- .../TroopMovementTest.cs | 12 +-- .../TroopTest.cs | 23 +++-- OpenPolytopia.sln | 92 +++++++++++++++++++ OpenPolytopia/test/src/CityDataTest.cs.uid | 1 - OpenPolytopia/test/src/GridTest.cs.uid | 1 - OpenPolytopia/test/src/PacketTest.cs.uid | 1 - OpenPolytopia/test/src/ScoreTest.cs.uid | 1 - OpenPolytopia/test/src/TechTreeTest.cs.uid | 1 - .../test/src/TerrainGenerationTest.cs.uid | 1 - OpenPolytopia/test/src/TileTest.cs.uid | 1 - .../test/src/TroopManagerTest.cs.uid | 1 - .../test/src/TroopMovementTest.cs.uid | 1 - OpenPolytopia/test/src/TroopTest.cs.uid | 1 - 25 files changed, 275 insertions(+), 139 deletions(-) create mode 100644 .github/workflows/unit_tests.yaml rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/CityDataTest.cs (93%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/DamageCalculatorTest.cs (94%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/DirectionsTest.cs (94%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/GridTest.cs (80%) create mode 100644 OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/PacketTest.cs (96%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/ScoreTest.cs (92%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TechTreeTest.cs (90%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TerrainGenerationTest.cs (97%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TileTest.cs (91%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TroopManagerTest.cs (89%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TroopMovementTest.cs (90%) rename {OpenPolytopia/test/src => OpenPolytopia.UnitTest}/TroopTest.cs (90%) delete mode 100644 OpenPolytopia/test/src/CityDataTest.cs.uid delete mode 100644 OpenPolytopia/test/src/GridTest.cs.uid delete mode 100644 OpenPolytopia/test/src/PacketTest.cs.uid delete mode 100644 OpenPolytopia/test/src/ScoreTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TechTreeTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TerrainGenerationTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TileTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TroopManagerTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TroopMovementTest.cs.uid delete mode 100644 OpenPolytopia/test/src/TroopTest.cs.uid diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml new file mode 100644 index 00000000..1a97a85b --- /dev/null +++ b/.github/workflows/unit_tests.yaml @@ -0,0 +1,42 @@ +name: 🧪 Unit Tests +permissions: + contents: read +on: + push: + pull_request: + +jobs: + unit_tests: + name: 🧪 Unit Tests + runs-on: ubuntu-latest + # Only run the workflow if it's not a PR or if it's a PR from a fork. + # This prevents duplicate workflows from running on PR's that originate + # from the repository itself. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + env: + DOTNET_CLI_TELEMETRY_OPTOUT: true + DOTNET_NOLOGO: true + defaults: + run: + # Use bash shells on all platforms. + shell: bash + steps: + - name: 🧾 Checkout + uses: actions/checkout@v7 + with: + lfs: true + submodules: 'recursive' + + - name: 💽 Setup .NET SDK + uses: actions/setup-dotnet@v6 + with: + # Use the .NET SDK from global.json in the root of the repository. + global-json-file: global.json + + # Only the test project is restored and built: it depends on + # OpenPolytopia.Common, so Godot is never needed to run these tests. + - name: 📦 Restore Dependencies + run: dotnet restore OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj + + - name: 🧪 Run Unit Tests + run: dotnet test OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj --no-restore diff --git a/OpenPolytopia/test/src/CityDataTest.cs b/OpenPolytopia.UnitTest/CityDataTest.cs similarity index 93% rename from OpenPolytopia/test/src/CityDataTest.cs rename to OpenPolytopia.UnitTest/CityDataTest.cs index bb656e02..d5a41b61 100644 --- a/OpenPolytopia/test/src/CityDataTest.cs +++ b/OpenPolytopia.UnitTest/CityDataTest.cs @@ -1,12 +1,11 @@ namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class CityDataTest(Node testScene) : TestClass(testScene) { - [Test] +public class CityDataTest { + [Fact] public void TestOwner() { const int owner = 2; var cityData = new CityData(); @@ -15,7 +14,7 @@ public void TestOwner() { cityData.Owner.ShouldBe(owner); } - [Test] + [Fact] public void TestLevel() { const int level = 2; var cityData = new CityData(); @@ -24,7 +23,7 @@ public void TestLevel() { cityData.Level.ShouldBe(level); } - [Test] + [Fact] public void TestMaxPopulation() { const int level = 2; var cityData = new CityData(); @@ -33,7 +32,7 @@ public void TestMaxPopulation() { cityData.MaxPopulation.ShouldBe(level + 1); } - [Test] + [Fact] public void TestPopulation() { const int population = 2; var cityData = new CityData(); @@ -42,7 +41,7 @@ public void TestPopulation() { cityData.Population.ShouldBe(population); } - [Test] + [Fact] public void TestTroops() { const int troops = 2; var cityData = new CityData(); @@ -51,7 +50,7 @@ public void TestTroops() { cityData.Troops.ShouldBe(troops); } - [Test] + [Fact] public void TestParks() { const int parks = 2; var cityData = new CityData(); @@ -60,7 +59,7 @@ public void TestParks() { cityData.Parks.ShouldBe(parks); } - [Test] + [Fact] public void TestWall() { const bool wall = true; var cityData = new CityData(); @@ -69,7 +68,7 @@ public void TestWall() { cityData.Wall.ShouldBe(wall); } - [Test] + [Fact] public void TestForge() { const bool forge = true; var cityData = new CityData(); @@ -78,7 +77,7 @@ public void TestForge() { cityData.Forge.ShouldBe(forge); } - [Test] + [Fact] public void TestCapital() { const bool capital = true; var cityData = new CityData(); @@ -87,7 +86,7 @@ public void TestCapital() { cityData.Capital.ShouldBe(capital); } - [Test] + [Fact] public void TestConnected() { const bool connected = true; var cityData = new CityData(); @@ -96,7 +95,7 @@ public void TestConnected() { cityData.Connected.ShouldBe(connected); } - [Test] + [Fact] public void TestStars() { const int level = 2; var cityData = new CityData(); @@ -111,7 +110,7 @@ public void TestStars() { cityData.Stars.ShouldBe(7); } - [Test] + [Fact] public void TestLevelUp() { var cityData = new CityData(); var result = cityData.LevelUp(); diff --git a/OpenPolytopia/test/src/DamageCalculatorTest.cs b/OpenPolytopia.UnitTest/DamageCalculatorTest.cs similarity index 94% rename from OpenPolytopia/test/src/DamageCalculatorTest.cs rename to OpenPolytopia.UnitTest/DamageCalculatorTest.cs index 246599c5..62d2b6f6 100644 --- a/OpenPolytopia/test/src/DamageCalculatorTest.cs +++ b/OpenPolytopia.UnitTest/DamageCalculatorTest.cs @@ -1,12 +1,11 @@ namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class DamageCalculatorTest(Node testScene) : TestClass(testScene) { - [Test] +public class DamageCalculatorTest { + [Fact] public void TestEvenMatch() { // two full health warriors trade 5 damage each way DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); @@ -14,7 +13,7 @@ public void TestEvenMatch() { defenseDamage.ShouldBe(5u); } - [Test] + [Fact] public void TestWoundedAttacker() { // a wounded attacker hits for less and takes more in return DamageCalculator.ComputeMeleeDamage(2, 5, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); @@ -22,7 +21,7 @@ public void TestWoundedAttacker() { defenseDamage.ShouldBe(6u); } - [Test] + [Fact] public void TestWoundedDefender() { // a wounded defender takes more and retaliates for less DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 5, 10, out var attackDamage, out var defenseDamage); @@ -30,7 +29,7 @@ public void TestWoundedDefender() { defenseDamage.ShouldBe(3u); } - [Test] + [Fact] public void TestDefenseBonus() { // the retaliation scales linearly with the defense, not with the bonus applied to it DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage, 1.5f); @@ -42,7 +41,7 @@ public void TestDefenseBonus() { defenseDamage.ShouldBe(7u); } - [Test] + [Fact] public void TestUnevenStats() { // a stronger attacker against a full health warrior DamageCalculator.ComputeMeleeDamage(3, 10, 10, 2, 10, 10, out var attackDamage, out var defenseDamage); @@ -59,14 +58,14 @@ public void TestUnevenStats() { defenseDamage.ShouldBe(3u); } - [Test] + [Fact] public void TestRoundsHalvesUp() { // 5 * (2 / 4) * 4.5 rounds up to 5, banker's rounding would give 4 DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 10, 10, out var attackDamage, out _); attackDamage.ShouldBe(5u); } - [Test] + [Fact] public void TestRangedDamage() { // ranged attacks deal the melee attack damage without taking any retaliation DamageCalculator.ComputeMeleeDamage(2, 10, 10, 2, 5, 10, out var attackDamage, out _); @@ -74,7 +73,7 @@ public void TestRangedDamage() { DamageCalculator.ComputeRangedDamage(2, 10, 10, 2, 10, 10, 1.5f).ShouldBe(4u); } - [Test] + [Fact] public void TestSplashDamage() { // splash is half the ranged damage, rounded down DamageCalculator.ComputeSplashDamage(2, 10, 10, 2, 10, 10).ShouldBe(2u); diff --git a/OpenPolytopia/test/src/DirectionsTest.cs b/OpenPolytopia.UnitTest/DirectionsTest.cs similarity index 94% rename from OpenPolytopia/test/src/DirectionsTest.cs rename to OpenPolytopia.UnitTest/DirectionsTest.cs index c8029698..1e159bcf 100644 --- a/OpenPolytopia/test/src/DirectionsTest.cs +++ b/OpenPolytopia.UnitTest/DirectionsTest.cs @@ -1,13 +1,12 @@ namespace OpenPolytopia; using System.Linq; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class DirectionsTest(Node testScene) : TestClass(testScene) { - [Test] +public class DirectionsTest { + [Fact] public void TestCardinalVectors() { Direction.Up.ToVector2I().ShouldBe(new Vector2I(0, -1)); Direction.Down.ToVector2I().ShouldBe(new Vector2I(0, 1)); @@ -15,7 +14,7 @@ public void TestCardinalVectors() { Direction.Right.ToVector2I().ShouldBe(new Vector2I(1, 0)); } - [Test] + [Fact] public void TestDiagonalVectors() { Direction.UpLeft.ToVector2I().ShouldBe(new Vector2I(-1, -1)); Direction.UpRight.ToVector2I().ShouldBe(new Vector2I(1, -1)); @@ -23,7 +22,7 @@ public void TestDiagonalVectors() { Direction.DownRight.ToVector2I().ShouldBe(new Vector2I(1, 1)); } - [Test] + [Fact] public void TestDiagonalsAreCardinalSums() { Direction.UpLeft.ToVector2I().ShouldBe(Direction.Up.ToVector2I() + Direction.Left.ToVector2I()); Direction.UpRight.ToVector2I().ShouldBe(Direction.Up.ToVector2I() + Direction.Right.ToVector2I()); @@ -31,14 +30,14 @@ public void TestDiagonalsAreCardinalSums() { Direction.DownRight.ToVector2I().ShouldBe(Direction.Down.ToVector2I() + Direction.Right.ToVector2I()); } - [Test] + [Fact] public void TestAllDirectionsAreDistinct() { // a duplicated vector means a whole direction is unreachable when pathfinding WrapperDirection.Directions.Length.ShouldBe(8); WrapperDirection.Directions.Distinct().Count().ShouldBe(8); } - [Test] + [Fact] public void TestOppositeDirectionsCancelOut() { (Direction.Up.ToVector2I() + Direction.Down.ToVector2I()).ShouldBe(Vector2I.Zero); (Direction.Left.ToVector2I() + Direction.Right.ToVector2I()).ShouldBe(Vector2I.Zero); @@ -46,7 +45,7 @@ public void TestOppositeDirectionsCancelOut() { (Direction.UpRight.ToVector2I() + Direction.DownLeft.ToVector2I()).ShouldBe(Vector2I.Zero); } - [Test] + [Fact] public void TestHorizontalAndVertical() { WrapperDirection.Horizontal.ShouldBe(new[] { new Vector2I(-1, 0), new Vector2I(1, 0) }); WrapperDirection.Vertical.ShouldBe(new[] { new Vector2I(0, -1), new Vector2I(0, 1) }); @@ -55,7 +54,7 @@ public void TestHorizontalAndVertical() { WrapperDirection.Horizontal.Intersect(WrapperDirection.Vertical).ShouldBeEmpty(); } - [Test] + [Fact] public void TestEveryNeighborIsReachable() { // every tile around the origin must be covered exactly once var origin = new Vector2I(0, 0); diff --git a/OpenPolytopia/test/src/GridTest.cs b/OpenPolytopia.UnitTest/GridTest.cs similarity index 80% rename from OpenPolytopia/test/src/GridTest.cs rename to OpenPolytopia.UnitTest/GridTest.cs index fc18e712..f7357a32 100644 --- a/OpenPolytopia/test/src/GridTest.cs +++ b/OpenPolytopia.UnitTest/GridTest.cs @@ -1,24 +1,23 @@ namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class GridTest(Node testScene) : TestClass(testScene) { - [Test] +public class GridTest { + [Fact] public void TestPositionToIndex() { var grid = new Grid(10); grid.GridPositionToIndex(new Vector2I(2, 2)).ShouldBe(22u); } - [Test] + [Fact] public void TestIndexToPosition() { var grid = new Grid(10); grid.IndexToGridPosition(22u).ShouldBe(new Vector2I(2, 2)); } - [Test] + [Fact] public void TestModifyTile() { var grid = new Grid(10); grid.ModifyTile(0, (ref Tile tile) => tile.Owner = 2); diff --git a/OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj b/OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj new file mode 100644 index 00000000..a43f8a87 --- /dev/null +++ b/OpenPolytopia.UnitTest/OpenPolytopia.UnitTest.csproj @@ -0,0 +1,26 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenPolytopia/test/src/PacketTest.cs b/OpenPolytopia.UnitTest/PacketTest.cs similarity index 96% rename from OpenPolytopia/test/src/PacketTest.cs rename to OpenPolytopia.UnitTest/PacketTest.cs index 715f79c3..7430466c 100644 --- a/OpenPolytopia/test/src/PacketTest.cs +++ b/OpenPolytopia.UnitTest/PacketTest.cs @@ -3,14 +3,13 @@ namespace OpenPolytopia; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using Chickensoft.GoDotTest; using Common; using Common.Network; using Common.Network.Packets; using Godot; using Shouldly; -public class PacketTest(Node testScene) : TestClass(testScene) { +public class PacketTest { private static T RoundTrip(T packet) where T : IPacket, new() { List bytes = []; packet.Serialize(bytes); @@ -26,44 +25,44 @@ public class PacketTest(Node testScene) : TestClass(testScene) { return await PacketProtocol.ReadPacketAsync(stream); } - [Test] + [Fact] public void TestHandshake() { var packet = RoundTrip(new HandshakePacket { Version = "0.1.0" }); packet.Version.ShouldBe("0.1.0"); } - [Test] + [Fact] public void TestHandshakeResponse() { var packet = RoundTrip(new HandshakeResponsePacket { Ok = true, PlayerId = 42 }); packet.Ok.ShouldBeTrue(); packet.PlayerId.ShouldBe(42u); } - [Test] + [Fact] public void TestKeepAlive() { var packet = RoundTrip(new KeepAlivePacket()); packet.ShouldNotBeNull(); } - [Test] + [Fact] public void TestSetName() { var packet = RoundTrip(new SetNamePacket { Name = "Tester àèù" }); packet.Name.ShouldBe("Tester àèù"); } - [Test] + [Fact] public void TestSetNameResponse() { var packet = RoundTrip(new SetNameResponsePacket { Ok = true }); packet.Ok.ShouldBeTrue(); } - [Test] + [Fact] public void TestGetLobbies() { var packet = RoundTrip(new GetLobbiesPacket()); packet.ShouldNotBeNull(); } - [Test] + [Fact] public void TestGetLobbiesResponse() { var lobby = new LobbyData { Id = 123, MaxPlayers = 4 }; lobby.Players.Add(new LobbyPlayerData { PlayerId = 7, Name = "Test", Tribe = 2, Ready = true }); @@ -79,62 +78,62 @@ public void TestGetLobbiesResponse() { packet.Lobbies[0].ReadyCount.ShouldBe(1u); } - [Test] + [Fact] public void TestCreateLobby() { var packet = RoundTrip(new CreateLobbyPacket { MaxPlayers = 8, Tribe = 3 }); packet.MaxPlayers.ShouldBe(8u); packet.Tribe.ShouldBe(3u); } - [Test] + [Fact] public void TestCreateLobbyResponse() { var packet = RoundTrip(new CreateLobbyResponsePacket { Result = LobbyActionResult.Ok, LobbyId = 99 }); packet.Result.ShouldBe(LobbyActionResult.Ok); packet.LobbyId.ShouldBe(99u); } - [Test] + [Fact] public void TestJoinLobby() { var packet = RoundTrip(new JoinLobbyPacket { LobbyId = 21, Tribe = 4 }); packet.LobbyId.ShouldBe(21u); packet.Tribe.ShouldBe(4u); } - [Test] + [Fact] public void TestJoinLobbyResponse() { var packet = RoundTrip(new JoinLobbyResponsePacket { Result = LobbyActionResult.LobbyFull, LobbyId = 5 }); packet.Result.ShouldBe(LobbyActionResult.LobbyFull); packet.LobbyId.ShouldBe(5u); } - [Test] + [Fact] public void TestLeaveLobby() { var packet = RoundTrip(new LeaveLobbyPacket { LobbyId = 33 }); packet.LobbyId.ShouldBe(33u); } - [Test] + [Fact] public void TestLeaveLobbyResponse() { var packet = RoundTrip(new LeaveLobbyResponsePacket { Result = LobbyActionResult.NotInLobby, LobbyId = 33 }); packet.Result.ShouldBe(LobbyActionResult.NotInLobby); packet.LobbyId.ShouldBe(33u); } - [Test] + [Fact] public void TestSetReady() { var packet = RoundTrip(new SetReadyPacket { LobbyId = 11, Ready = true }); packet.LobbyId.ShouldBe(11u); packet.Ready.ShouldBeTrue(); } - [Test] + [Fact] public void TestSetReadyResponse() { var packet = RoundTrip(new SetReadyResponsePacket { Result = LobbyActionResult.Ok, LobbyId = 11 }); packet.Result.ShouldBe(LobbyActionResult.Ok); packet.LobbyId.ShouldBe(11u); } - [Test] + [Fact] public void TestLobbyUpdated() { var lobby = new LobbyData { Id = 55, MaxPlayers = 2 }; lobby.Players.Add(new LobbyPlayerData { PlayerId = 9, Name = "Test", Tribe = 1 }); @@ -145,13 +144,13 @@ public void TestLobbyUpdated() { packet.Lobby.Players[0].Name.ShouldBe("Test"); } - [Test] + [Fact] public void TestLobbyDeleted() { var packet = RoundTrip(new LobbyDeletedPacket { LobbyId = 55 }); packet.LobbyId.ShouldBe(55u); } - [Test] + [Fact] public void TestGameStarted() { var packet = RoundTrip(new GameStartedPacket { LobbyId = 3, Players = [new LobbyPlayerData { PlayerId = 1, Name = "A" }, new LobbyPlayerData { PlayerId = 2, Name = "B" }] @@ -161,7 +160,7 @@ public void TestGameStarted() { packet.Players[1].Name.ShouldBe("B"); } - [Test] + [Fact] public void TestFraming() { PacketRegistrar.RegisterAllPackets(); var packet = new HandshakePacket { Version = "0.1.0" }; @@ -177,14 +176,14 @@ public void TestFraming() { packetId.ShouldBe(1u); } - [Test] + [Fact] public async Task TestReadPacket() { PacketRegistrar.RegisterAllPackets(); var packet = await ReadBackAsync(PacketProtocol.FramePacket(new SetNamePacket { Name = "Tester" })); packet.ShouldBeOfType().Name.ShouldBe("Tester"); } - [Test] + [Fact] public async Task TestReadManyPackets() { PacketRegistrar.RegisterAllPackets(); List bytes = []; @@ -198,7 +197,7 @@ public async Task TestReadManyPackets() { setReady.Ready.ShouldBeTrue(); } - [Test] + [Fact] public async Task TestReadSkipsUnknownPacket() { PacketRegistrar.RegisterAllPackets(); @@ -216,7 +215,7 @@ public async Task TestReadSkipsUnknownPacket() { (await PacketProtocol.ReadPacketAsync(stream)).ShouldBeOfType(); } - [Test] + [Fact] public async Task TestReadRejectsTinyPacket() { // a packet must contain at least the 4 bytes of the packet id List bytes = []; @@ -224,14 +223,14 @@ public async Task TestReadRejectsTinyPacket() { await Should.ThrowAsync(() => ReadBackAsync([.. bytes])); } - [Test] + [Fact] public async Task TestReadRejectsOversizedPacket() { List bytes = []; (NetworkConstants.MAX_PACKET_SIZE + 1).Serialize(bytes); await Should.ThrowAsync(() => ReadBackAsync([.. bytes])); } - [Test] + [Fact] public async Task TestReadRejectsMalformedPayload() { PacketRegistrar.RegisterAllPackets(); diff --git a/OpenPolytopia/test/src/ScoreTest.cs b/OpenPolytopia.UnitTest/ScoreTest.cs similarity index 92% rename from OpenPolytopia/test/src/ScoreTest.cs rename to OpenPolytopia.UnitTest/ScoreTest.cs index 376f8a6a..27613852 100644 --- a/OpenPolytopia/test/src/ScoreTest.cs +++ b/OpenPolytopia.UnitTest/ScoreTest.cs @@ -1,12 +1,11 @@ namespace OpenPolytopia; using Godot; -using Chickensoft.GoDotTest; using Common; using Shouldly; -public class ScoreTest(Node testScene) : TestClass(testScene) { - [Test] +public class ScoreTest { + [Fact] public void TestPlayerScore() { var playerOneScore = new Score(); playerOneScore.ScoreValue.ShouldBe(0); @@ -16,14 +15,14 @@ public void TestPlayerScore() { playerOneScore.ScoreValue.ShouldBe(20); } - [Test] + [Fact] public void TestNegativeScore() { var playerOneScore = new Score(); playerOneScore.AddScore(ScoreType.LoseCity(8)); playerOneScore.ScoreValue.ShouldBe(0); } - [Test] + [Fact] public void TestLoseCity() { var playerOneScore = new Score(); playerOneScore.AddScore(ScoreType.VillageConquered); @@ -34,14 +33,14 @@ public void TestLoseCity() { playerOneScore.ScoreValue.ShouldBe(0); } - [Test] + [Fact] public void TestTroopSpawned() { var playerOneScore = new Score(); playerOneScore.AddScore(ScoreType.TroopSpawned(3, 2)); playerOneScore.ScoreValue.ShouldBe(45); } - [Test] + [Fact] public void TestLoseTroop() { var playerOneScore = new Score(); playerOneScore.AddScore(ScoreType.TroopSpawned(2, 2)); @@ -50,7 +49,7 @@ public void TestLoseTroop() { playerOneScore.ScoreValue.ShouldBe(15); } - [Test] + [Fact] public void TestDestroyedUndoesBuilt() { var playerOneScore = new Score(); playerOneScore.AddScore(ScoreType.MonumentsBuilt); diff --git a/OpenPolytopia/test/src/TechTreeTest.cs b/OpenPolytopia.UnitTest/TechTreeTest.cs similarity index 90% rename from OpenPolytopia/test/src/TechTreeTest.cs rename to OpenPolytopia.UnitTest/TechTreeTest.cs index 7154813f..af635296 100644 --- a/OpenPolytopia/test/src/TechTreeTest.cs +++ b/OpenPolytopia.UnitTest/TechTreeTest.cs @@ -1,12 +1,11 @@ namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class TechTreeTest(Node testScene) : TestClass(testScene) { - [Test] +public class TechTreeTest { + [Fact] public void TestStartingTech() { const BranchType branch = BranchType.Climbing; const string id = "climbing"; @@ -15,7 +14,7 @@ public void TestStartingTech() { techTree[branch].HasResearched(id).ShouldBeTrue(); } - [Test] + [Fact] public void TestStartingTech2() { const BranchType branch = BranchType.Climbing; const string id = "climbing"; @@ -23,7 +22,7 @@ public void TestStartingTech2() { techTree[branch].HasResearched(id).ShouldBeFalse(); } - [Test] + [Fact] public void TestResearch() { const BranchType branch = BranchType.Climbing; const string id = "climbing"; @@ -33,7 +32,7 @@ public void TestResearch() { techTree[branch].HasResearched(id).ShouldBeTrue(); } - [Test] + [Fact] public void TestComputeCost() { const BranchType branch = BranchType.Climbing; var id = "climbing"; diff --git a/OpenPolytopia/test/src/TerrainGenerationTest.cs b/OpenPolytopia.UnitTest/TerrainGenerationTest.cs similarity index 97% rename from OpenPolytopia/test/src/TerrainGenerationTest.cs rename to OpenPolytopia.UnitTest/TerrainGenerationTest.cs index 0344c1e4..3106fa3d 100644 --- a/OpenPolytopia/test/src/TerrainGenerationTest.cs +++ b/OpenPolytopia.UnitTest/TerrainGenerationTest.cs @@ -2,12 +2,11 @@ namespace OpenPolytopia; using System; using System.Threading.Tasks; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class TerrainGenerationTest(Node testScene) : TestClass(testScene) { +public class TerrainGenerationTest { private const uint SIZE = 16; private const int SEED = 42; @@ -31,7 +30,7 @@ public class TerrainGenerationTest(Node testScene) : TestClass(testScene) { return (grid, cityManager, players); } - [Test] + [Fact] public async Task TestCapitals() { var (grid, cityManager, players) = await GenerateMapAsync(); @@ -59,7 +58,7 @@ public async Task TestCapitals() { capitals.ShouldBe(players.Length); } - [Test] + [Fact] public async Task TestTerrain() { var (grid, _, _) = await GenerateMapAsync(); @@ -79,7 +78,7 @@ public async Task TestTerrain() { water.ShouldBeGreaterThan(0); } - [Test] + [Fact] public async Task TestVillages() { var (grid, cityManager, players) = await GenerateMapAsync(); @@ -111,7 +110,7 @@ public async Task TestVillages() { villages.ShouldBeGreaterThan(0); } - [Test] + [Fact] public async Task TestResourcesNearCities() { var (grid, cityManager, _) = await GenerateMapAsync(); @@ -137,7 +136,7 @@ public async Task TestResourcesNearCities() { } } - [Test] + [Fact] public async Task TestRuins() { var (grid, _, _) = await GenerateMapAsync(); @@ -162,7 +161,7 @@ public async Task TestRuins() { waterRuins.ShouldBeLessThanOrEqualTo(total / 3); } - [Test] + [Fact] public async Task TestInvalidPlayers() { var grid = new Grid(SIZE); var terrainGeneration = new TerrainGeneration(grid, new CityManager(grid), new TribeManager(), []); @@ -170,7 +169,7 @@ public async Task TestInvalidPlayers() { await Should.ThrowAsync(terrainGeneration.GenerateMapAsync); } - [Test] + [Fact] public async Task TestSingleUse() { var grid = new Grid(SIZE); var players = new[] { new Player(TribeType.Imperius, 1) }; @@ -181,7 +180,7 @@ public async Task TestSingleUse() { await Should.ThrowAsync(terrainGeneration.GenerateMapAsync); } - [Test] + [Fact] public async Task TestDeterministicSeed() { var (first, _, _) = await GenerateMapAsync(); var (second, _, _) = await GenerateMapAsync(); diff --git a/OpenPolytopia/test/src/TileTest.cs b/OpenPolytopia.UnitTest/TileTest.cs similarity index 91% rename from OpenPolytopia/test/src/TileTest.cs rename to OpenPolytopia.UnitTest/TileTest.cs index 40bf98dd..74d0e9c6 100644 --- a/OpenPolytopia/test/src/TileTest.cs +++ b/OpenPolytopia.UnitTest/TileTest.cs @@ -1,20 +1,19 @@ namespace OpenPolytopia; using System.Threading.Tasks; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class TileTest(Node testScene) : TestClass(testScene) { - [Test] +public class TileTest { + [Fact] public void TestTileCreation() { const TileKind kind = TileKind.Mountain; var tile = new Tile(kind); tile.Kind.ShouldBe(kind); } - [Test] + [Fact] public void TestRoad() { var tile = new Tile(TileKind.Field); tile.Roads.ShouldBe(false); @@ -22,7 +21,7 @@ public void TestRoad() { tile.Roads.ShouldBe(true); } - [Test] + [Fact] public void TestRuin() { var tile = new Tile(TileKind.Field); tile.Ruin.ShouldBe(false); @@ -30,7 +29,7 @@ public void TestRuin() { tile.Ruin.ShouldBe(true); } - [Test] + [Fact] public void TestModifier() { const FieldTileModifier modifier = FieldTileModifier.Fruit; var tile = new Tile(TileKind.Field); @@ -39,7 +38,7 @@ public void TestModifier() { tile.GetTileModifier().ShouldBe(modifier); } - [Test] + [Fact] public void TestBuilding() { const FieldTileBuilding building = FieldTileBuilding.Market; var tile = new Tile(TileKind.Field); @@ -48,7 +47,7 @@ public void TestBuilding() { tile.GetTileBuilding().ShouldBe(building); } - [Test] + [Fact] public void TestOwner() { const int owner = 2; var tile = new Tile(TileKind.Field); @@ -57,7 +56,7 @@ public void TestOwner() { tile.Owner.ShouldBe(owner); } - [Test] + [Fact] public void TestBiome() { const TribeType biome = TribeType.Elyrion; var tile = new Tile(TileKind.Field); @@ -66,7 +65,7 @@ public void TestBiome() { tile.Biome.ShouldBe(biome); } - [Test] + [Fact] public void TestCity() { const int city = 20; var tile = new Tile(TileKind.Field); @@ -75,7 +74,7 @@ public void TestCity() { tile.City.ShouldBe(city); } - [Test] + [Fact] public void TestWonder() { const Wonder wonder = Wonder.EmperorsTomb; var tile = new Tile(TileKind.Field); diff --git a/OpenPolytopia/test/src/TroopManagerTest.cs b/OpenPolytopia.UnitTest/TroopManagerTest.cs similarity index 89% rename from OpenPolytopia/test/src/TroopManagerTest.cs rename to OpenPolytopia.UnitTest/TroopManagerTest.cs index 05c5e0c8..d9b956bd 100644 --- a/OpenPolytopia/test/src/TroopManagerTest.cs +++ b/OpenPolytopia.UnitTest/TroopManagerTest.cs @@ -1,22 +1,20 @@ -namespace OpenPolytopia.test.src; +namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Godot; using Common; using Shouldly; -public class TroopManagerTest(Node testScene) : TestClass(testScene) { +public class TroopManagerTest { private TroopManager _troopManager = null!; - [Setup] - public void Setup() { + public TroopManagerTest() { _troopManager = new TroopManager(10); var troops = EmbeddedResources.LoadTroops(); troops.ShouldNotBeNull(); _troopManager.RegisterTroops(troops); } - [Test] + [Fact] public void TestSpawnTroop() { _troopManager.SpawnTroop(new Vector2I(0, 0), 1, 1, TroopType.Warrior); _troopManager[0u].IsValid().ShouldBeTrue(); @@ -25,7 +23,7 @@ public void TestSpawnTroop() { _troopManager[0u].City.ShouldBe(1u); } - [Test] + [Fact] public void TestDeleteTroop() { var position = new Vector2I(1, 0); _troopManager.SpawnTroop(position, 1, 1, TroopType.Warrior); @@ -34,7 +32,7 @@ public void TestDeleteTroop() { _troopManager[1].IsValid().ShouldBeFalse(); } - [Test] + [Fact] public void TestMoveTroop() { var initialPosition = new Vector2I(2, 0); var finalPosition = new Vector2I(3, 0); @@ -45,7 +43,7 @@ public void TestMoveTroop() { _troopManager[3].IsValid().ShouldBeTrue(); } - [Test] + [Fact] public void TestSetVeteran() { var position = new Vector2I(4, 0); _troopManager.SpawnTroop(position, 1, 1, TroopType.Warrior); @@ -53,7 +51,7 @@ public void TestSetVeteran() { _troopManager[4].Veteran.ShouldBeTrue(); } - [Test] + [Fact] public void TestModifyTroop() { var position = new Vector2I(5, 0); _troopManager.SpawnTroop(position, 1, 1, TroopType.Warrior); diff --git a/OpenPolytopia/test/src/TroopMovementTest.cs b/OpenPolytopia.UnitTest/TroopMovementTest.cs similarity index 90% rename from OpenPolytopia/test/src/TroopMovementTest.cs rename to OpenPolytopia.UnitTest/TroopMovementTest.cs index fcfdfc52..d66ae824 100644 --- a/OpenPolytopia/test/src/TroopMovementTest.cs +++ b/OpenPolytopia.UnitTest/TroopMovementTest.cs @@ -1,23 +1,21 @@ namespace OpenPolytopia; using System.Threading.Tasks; -using Chickensoft.GoDotTest; using Godot; using Common; using Shouldly; -public class TroopMovementTest(Node testScene) : TestClass(testScene) { +public class TroopMovementTest { private TroopManager _troopManager = null!; - [Setup] - public void Setup() { + public TroopMovementTest() { _troopManager = new TroopManager(10); var troops = EmbeddedResources.LoadTroops(); troops.ShouldNotBeNull(); _troopManager.RegisterTroops(troops); } - [Test] + [Fact] public async Task TestNumbersPathAsync() { _troopManager.SpawnTroop(new Vector2I(0, 0), 1, 1, TroopType.Warrior); var counter = 0; @@ -29,7 +27,7 @@ public async Task TestNumbersPathAsync() { counter.ShouldBe(3); } - [Test] + [Fact] public async Task TestMoveTroopToDiscoveredPathAsync() { var lastPos = new Vector2I(9, 9); _troopManager.SpawnTroop(lastPos, 1, 1, TroopType.Warrior); @@ -44,7 +42,7 @@ public async Task TestMoveTroopToDiscoveredPathAsync() { } } - [Test] + [Fact] public async Task TestMoveMultipleTroopsAsync() { _troopManager.SpawnTroop(new Vector2I(5, 0), 1, 1, TroopType.Warrior); _troopManager.SpawnTroop(new Vector2I(6, 0), 1, 1, TroopType.Warrior); diff --git a/OpenPolytopia/test/src/TroopTest.cs b/OpenPolytopia.UnitTest/TroopTest.cs similarity index 90% rename from OpenPolytopia/test/src/TroopTest.cs rename to OpenPolytopia.UnitTest/TroopTest.cs index dd9a8d76..f5d5b02f 100644 --- a/OpenPolytopia/test/src/TroopTest.cs +++ b/OpenPolytopia.UnitTest/TroopTest.cs @@ -1,12 +1,11 @@ namespace OpenPolytopia; -using Chickensoft.GoDotTest; using Common; using Godot; using Shouldly; -public class TroopTest(Node testScene) : TestClass(testScene) { - [Test] +public class TroopTest { + [Fact] public void TestVeteran() { var troop = new TroopData(); troop.Veteran.ShouldBeFalse(); @@ -14,7 +13,7 @@ public void TestVeteran() { troop.Veteran.ShouldBeTrue(); } - [Test] + [Fact] public void TestAttacked() { var troop = new TroopData(); troop.Attacked.ShouldBeFalse(); @@ -22,7 +21,7 @@ public void TestAttacked() { troop.Attacked.ShouldBeTrue(); } - [Test] + [Fact] public void TestMoved() { var troop = new TroopData(); troop.Moved.ShouldBeFalse(); @@ -30,7 +29,7 @@ public void TestMoved() { troop.Moved.ShouldBeTrue(); } - [Test] + [Fact] public void TestCity() { const uint city = 2; var troop = new TroopData(); @@ -39,7 +38,7 @@ public void TestCity() { troop.City.ShouldBe(city); } - [Test] + [Fact] public void TestHp() { const uint hp = 2; var troop = new TroopData(); @@ -48,7 +47,7 @@ public void TestHp() { troop.Hp.ShouldBe(hp); } - [Test] + [Fact] public void TestType() { const TroopType type = TroopType.Archer; var troop = new TroopData(); @@ -57,7 +56,7 @@ public void TestType() { troop.Type.ShouldBe(type); } - [Test] + [Fact] public void TestPlayer() { const uint player = 2; var troop = new TroopData(); @@ -66,7 +65,7 @@ public void TestPlayer() { troop.Player.ShouldBe(player); } - [Test] + [Fact] public void TestResetActions() { var troop = new TroopData { Attacked = true, Moved = true }; troop.ResetActions(); @@ -74,7 +73,7 @@ public void TestResetActions() { troop.Moved.ShouldBeFalse(); } - [Test] + [Fact] public void TestIsValid() { var troop = new TroopData(); troop.IsValid().ShouldBeFalse(); @@ -82,7 +81,7 @@ public void TestIsValid() { troop.IsValid().ShouldBeTrue(); } - [Test] + [Fact] public void TestDelete() { var troop = new TroopData { Player = 2 }; troop.IsValid().ShouldBeTrue(); diff --git a/OpenPolytopia.sln b/OpenPolytopia.sln index 8f566967..02190242 100644 --- a/OpenPolytopia.sln +++ b/OpenPolytopia.sln @@ -6,30 +6,122 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenPolytopia.Common", "Ope EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenPolytopia.Server", "OpenPolytopia.Server\OpenPolytopia.Server.csproj", "{0B313502-8039-43DA-AC92-4B8146E88349}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenPolytopia.UnitTest", "OpenPolytopia.UnitTest\OpenPolytopia.UnitTest.csproj", "{321414DE-F24C-4359-A469-6F6FC29B09D7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 ExportDebug|Any CPU = ExportDebug|Any CPU + ExportDebug|x64 = ExportDebug|x64 + ExportDebug|x86 = ExportDebug|x86 ExportRelease|Any CPU = ExportRelease|Any CPU + ExportRelease|x64 = ExportRelease|x64 + ExportRelease|x86 = ExportRelease|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|x64.ActiveCfg = Debug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|x64.Build.0 = Debug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|x86.ActiveCfg = Debug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Debug|x86.Build.0 = Debug|Any CPU {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|x64.ActiveCfg = ExportDebug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|x64.Build.0 = ExportDebug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|x86.ActiveCfg = ExportDebug|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportDebug|x86.Build.0 = ExportDebug|Any CPU {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|x64.ActiveCfg = ExportRelease|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|x64.Build.0 = ExportRelease|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|x86.ActiveCfg = ExportRelease|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.ExportRelease|x86.Build.0 = ExportRelease|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|Any CPU.Build.0 = Release|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|x64.ActiveCfg = Release|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|x64.Build.0 = Release|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|x86.ActiveCfg = Release|Any CPU + {2B02EE86-08BF-491D-BFD8-B7B202D3170F}.Release|x86.Build.0 = Release|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|x64.ActiveCfg = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|x64.Build.0 = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|x86.ActiveCfg = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Debug|x86.Build.0 = Debug|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|x64.ActiveCfg = ExportDebug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|x64.Build.0 = ExportDebug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|x86.ActiveCfg = ExportDebug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportDebug|x86.Build.0 = ExportDebug|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|x64.ActiveCfg = ExportRelease|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|x64.Build.0 = ExportRelease|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|x86.ActiveCfg = ExportRelease|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.ExportRelease|x86.Build.0 = ExportRelease|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|Any CPU.Build.0 = Release|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|x64.ActiveCfg = Release|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|x64.Build.0 = Release|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|x86.ActiveCfg = Release|Any CPU + {07BAA3DA-9489-4A3A-85AD-92C16108241D}.Release|x86.Build.0 = Release|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|x64.ActiveCfg = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|x64.Build.0 = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|x86.ActiveCfg = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Debug|x86.Build.0 = Debug|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|x64.ActiveCfg = ExportDebug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|x64.Build.0 = ExportDebug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|x86.ActiveCfg = ExportDebug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportDebug|x86.Build.0 = ExportDebug|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|x64.ActiveCfg = ExportRelease|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|x64.Build.0 = ExportRelease|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|x86.ActiveCfg = ExportRelease|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.ExportRelease|x86.Build.0 = ExportRelease|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|Any CPU.Build.0 = Release|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|x64.ActiveCfg = Release|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|x64.Build.0 = Release|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|x86.ActiveCfg = Release|Any CPU + {0B313502-8039-43DA-AC92-4B8146E88349}.Release|x86.Build.0 = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|x64.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|x64.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|x86.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Debug|x86.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|x64.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|x64.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|x86.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportDebug|x86.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|x64.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|x64.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|x86.ActiveCfg = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.ExportRelease|x86.Build.0 = Debug|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|Any CPU.Build.0 = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|x64.ActiveCfg = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|x64.Build.0 = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|x86.ActiveCfg = Release|Any CPU + {321414DE-F24C-4359-A469-6F6FC29B09D7}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/OpenPolytopia/test/src/CityDataTest.cs.uid b/OpenPolytopia/test/src/CityDataTest.cs.uid deleted file mode 100644 index 68a4a4b1..00000000 --- a/OpenPolytopia/test/src/CityDataTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://wjn011jwb3pd diff --git a/OpenPolytopia/test/src/GridTest.cs.uid b/OpenPolytopia/test/src/GridTest.cs.uid deleted file mode 100644 index 18bf3643..00000000 --- a/OpenPolytopia/test/src/GridTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ycvqn6oipqmh diff --git a/OpenPolytopia/test/src/PacketTest.cs.uid b/OpenPolytopia/test/src/PacketTest.cs.uid deleted file mode 100644 index 45f6cd73..00000000 --- a/OpenPolytopia/test/src/PacketTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://rgtxwvw148is diff --git a/OpenPolytopia/test/src/ScoreTest.cs.uid b/OpenPolytopia/test/src/ScoreTest.cs.uid deleted file mode 100644 index 1b72c2cb..00000000 --- a/OpenPolytopia/test/src/ScoreTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dpshc6viov8gx diff --git a/OpenPolytopia/test/src/TechTreeTest.cs.uid b/OpenPolytopia/test/src/TechTreeTest.cs.uid deleted file mode 100644 index e4ed181f..00000000 --- a/OpenPolytopia/test/src/TechTreeTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bm2ev2ldxpo78 diff --git a/OpenPolytopia/test/src/TerrainGenerationTest.cs.uid b/OpenPolytopia/test/src/TerrainGenerationTest.cs.uid deleted file mode 100644 index 06733810..00000000 --- a/OpenPolytopia/test/src/TerrainGenerationTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcebes3h2jpca diff --git a/OpenPolytopia/test/src/TileTest.cs.uid b/OpenPolytopia/test/src/TileTest.cs.uid deleted file mode 100644 index 67bb0a7a..00000000 --- a/OpenPolytopia/test/src/TileTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://sqcbqvffknk3 diff --git a/OpenPolytopia/test/src/TroopManagerTest.cs.uid b/OpenPolytopia/test/src/TroopManagerTest.cs.uid deleted file mode 100644 index cb37ff08..00000000 --- a/OpenPolytopia/test/src/TroopManagerTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dwr0yngsln8f4 diff --git a/OpenPolytopia/test/src/TroopMovementTest.cs.uid b/OpenPolytopia/test/src/TroopMovementTest.cs.uid deleted file mode 100644 index 3fc75fec..00000000 --- a/OpenPolytopia/test/src/TroopMovementTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://qhakfs4fpq6s diff --git a/OpenPolytopia/test/src/TroopTest.cs.uid b/OpenPolytopia/test/src/TroopTest.cs.uid deleted file mode 100644 index c8414a4d..00000000 --- a/OpenPolytopia/test/src/TroopTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://nk8f3825n3dv From 6132c2b4ea9cd51715d3ff1be938d2c8cf7b6a21 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Mon, 31 Aug 2026 19:56:32 +0200 Subject: [PATCH 4/4] fix: added spelling --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index bf19e1db..a308e584 100644 --- a/cspell.json +++ b/cspell.json @@ -65,6 +65,7 @@ "OPTOUT", "paramref", "pascalcase", + "pathfinding", "randomizer", "raymarch", "renovatebot",