Skip to content

Commit 9343282

Browse files
Caeldethclaude
andcommitted
test: add easy wins unit tests
- Recursive creature HP allocation: level restored after init, higher level monsters have more HP and higher total stats - ItemObject FormulaVariables: verify 12 properties annotated, expected names present, FormulaParser discovers them at startup - Cone radius cap: verify viewport cap pattern removed from source Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fe76a0d commit 9343282

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

Hybrasyl.Tests/EasyWins.cs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// This file is part of Project Hybrasyl.
2+
//
3+
// This program is free software; you can redistribute it and/or modify
4+
// it under the terms of the Affero General Public License as published by
5+
// the Free Software Foundation, version 3.
6+
//
7+
// This program is distributed in the hope that it will be useful, but
8+
// without ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9+
// or FITNESS FOR A PARTICULAR PURPOSE. See the Affero General Public License
10+
// for more details.
11+
//
12+
// You should have received a copy of the Affero General Public License along
13+
// with this program. If not, see <http://www.gnu.org/licenses/>.
14+
//
15+
// (C) 2020-2023 ERISCO, LLC
16+
//
17+
// For contributors and individual authors please refer to CONTRIBUTORS.MD.
18+
19+
using Hybrasyl.Objects;
20+
using Hybrasyl.Subsystems.Formulas;
21+
using Hybrasyl.Xml.Objects;
22+
using System.Collections.Generic;
23+
using System.Linq;
24+
using System.Reflection;
25+
using Xunit;
26+
using Creature = Hybrasyl.Xml.Objects.Creature;
27+
28+
namespace Hybrasyl.Tests;
29+
30+
[Collection("Hybrasyl")]
31+
public class EasyWins
32+
{
33+
public HybrasylFixture Fixture { get; }
34+
35+
public EasyWins(HybrasylFixture fixture)
36+
{
37+
Fixture = fixture;
38+
}
39+
40+
// --- Recursive creature HP allocation ---
41+
42+
[Fact]
43+
public void MonsterAllocateStats_LevelIsRestoredAfterAllocation()
44+
{
45+
Assert.True(Game.World.WorldData.TryGetValue<Creature>("Gabbaghoul", out var monsterXml),
46+
"Gabbaghoul test monster not found");
47+
var monster = new Monster(monsterXml, SpawnFlags.AiDisabled, 50);
48+
49+
// After AllocateStats, the monster's level should be the target level
50+
Assert.Equal(50, monster.Stats.Level);
51+
}
52+
53+
[Fact]
54+
public void MonsterAllocateStats_HigherLevel_HasMoreHp()
55+
{
56+
Assert.True(Game.World.WorldData.TryGetValue<Creature>("Gabbaghoul", out var monsterXml),
57+
"Gabbaghoul test monster not found");
58+
59+
var low = new Monster(monsterXml, SpawnFlags.AiDisabled, 10);
60+
var high = new Monster(monsterXml, SpawnFlags.AiDisabled, 50);
61+
62+
// A level 50 monster should have more HP than a level 10 monster
63+
Assert.True(high.Stats.MaximumHp > low.Stats.MaximumHp,
64+
$"Level 50 HP ({high.Stats.MaximumHp}) should exceed level 10 HP ({low.Stats.MaximumHp})");
65+
}
66+
67+
[Fact]
68+
public void MonsterAllocateStats_StatsIncrease_WithLevel()
69+
{
70+
Assert.True(Game.World.WorldData.TryGetValue<Creature>("Gabbaghoul", out var monsterXml),
71+
"Gabbaghoul test monster not found");
72+
73+
var low = new Monster(monsterXml, SpawnFlags.AiDisabled, 5);
74+
var high = new Monster(monsterXml, SpawnFlags.AiDisabled, 50);
75+
76+
// Total stat points should be higher for a higher level monster
77+
var lowTotal = low.Stats.BaseStr + low.Stats.BaseInt + low.Stats.BaseWis +
78+
low.Stats.BaseCon + low.Stats.BaseDex;
79+
var highTotal = high.Stats.BaseStr + high.Stats.BaseInt + high.Stats.BaseWis +
80+
high.Stats.BaseCon + high.Stats.BaseDex;
81+
82+
Assert.True(highTotal > lowTotal,
83+
$"Level 50 total stats ({highTotal}) should exceed level 5 ({lowTotal})");
84+
}
85+
86+
// --- ItemObject FormulaVariables ---
87+
88+
[Fact]
89+
public void ItemObject_Has12_FormulaVariables()
90+
{
91+
var props = typeof(ItemObject).GetProperties()
92+
.Where(p => p.IsDefined(typeof(FormulaVariable), false))
93+
.ToList();
94+
95+
Assert.Equal(12, props.Count);
96+
}
97+
98+
[Fact]
99+
public void ItemObject_FormulaVariables_IncludeExpectedProperties()
100+
{
101+
var props = typeof(ItemObject).GetProperties()
102+
.Where(p => p.IsDefined(typeof(FormulaVariable), false))
103+
.Select(p => p.Name)
104+
.ToHashSet();
105+
106+
var expected = new[]
107+
{
108+
"Weight", "MaximumDurability", "MinLevel", "MinAbility",
109+
"MaxLevel", "MaxAbility", "MinLDamage", "MaxLDamage",
110+
"MinSDamage", "MaxSDamage", "Value", "Durability"
111+
};
112+
113+
foreach (var name in expected)
114+
Assert.Contains(name, props);
115+
}
116+
117+
[Fact]
118+
public void FormulaParser_ScansItemObject_ForVariables()
119+
{
120+
// FormulaParser's static constructor populates tokens for ItemObject
121+
var tokensField = typeof(FormulaParser)
122+
.GetField("FormulaTokens", BindingFlags.NonPublic | BindingFlags.Static);
123+
Assert.NotNull(tokensField);
124+
125+
var tokens = tokensField.GetValue(null) as Dictionary<System.Type, List<PropertyInfo>>;
126+
Assert.NotNull(tokens);
127+
Assert.True(tokens.ContainsKey(typeof(ItemObject)));
128+
Assert.True(tokens[typeof(ItemObject)].Count >= 12,
129+
$"FormulaParser found {tokens[typeof(ItemObject)].Count} ItemObject variables, expected at least 12");
130+
}
131+
132+
// --- Cone radius cap removal ---
133+
134+
[Fact]
135+
public void ConeRadius_NotCappedByViewport()
136+
{
137+
// The cone intent processing in Creature.cs should use tile.Radius directly,
138+
// not Math.Min(tile.Radius, ViewportSize / 2). Verify by checking the source
139+
// doesn't contain the viewport cap pattern for cones.
140+
var source = System.IO.File.ReadAllText(
141+
System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory,
142+
"..", "..", "..", "..", "hybrasyl", "Objects", "Creature.cs"));
143+
144+
// The old code: Math.Min(tile.Radius, Game.ActiveConfiguration.Constants.ViewportSize / 2)
145+
// should not appear near "foreach.*Cone" anymore
146+
Assert.DoesNotContain("Math.Min(tile.Radius, Game.ActiveConfiguration.Constants.ViewportSize / 2)", source);
147+
}
148+
}

0 commit comments

Comments
 (0)