Add unit tests for weapon-special calculations

Covers the math for [attack]add=, [attack]divide=, [attack]multiply= and
[attack]sub=.

* 5 + 2 = 7
* 5 - 3 = 2
* 5 + 2 - 3 = 2. Yes it does, that's half of why this unit test exists ...
* 5 + 2 + 3 = 8
* 5 + 3 + 2 = 8
* 5 + 2 - (-3) = 7
* 3 * 3.34 = 10
* 3 * 3.334 = 9. ... and that's the other half of why this unit test exists.

(cherry picked from commit e28f29b4ac)
This commit is contained in:
Steve Cotton 2022-12-28 14:40:46 +01:00 committed by Steve Cotton
parent 971ea6c6ef
commit a35ae685de
2 changed files with 231 additions and 2 deletions

View file

@ -0,0 +1,208 @@
# wmllint: no translatables
# This file uses [attacks], but it would apply equally to other weapon specials that pass is_cumulable=false to the
# effect class' constructor. That's why the tests are called special_calculation_* instead of attack_calculation_*.
#
# This isn't applicable to [leadership], which passes is_cumulable=true to effect's constructor.
#define TWO_CALCULATION_UNIT_TEST ID START OPERATIONS_1 OPERATIONS_2 EXPECTED
# Assert that setting a unit's strikes to START and then performing the calculations in
# OPERATIONS_1 and OPERATIONS_2 gets the end result of EXPECTED.
{COMMON_KEEP_A_B_UNIT_TEST "special_calculation_{ID}" (
[event]
name=start
[object]
silent=yes
[filter]
id=bob
[/filter]
[effect]
apply_to=attack
[set_specials]
mode=replace
[attacks]
value={START}
[/attacks]
[attacks]
{OPERATIONS_1}
[/attacks]
[attacks]
{OPERATIONS_2}
# This macro is also used to implement ONE_CALCULATION_UNIT_TEST, by leaving OPERATIONS_2 empty.
# The schema validation might be expanded to check that, in which case it would be correct for
# it to fail here; the fix would be to cut & paste the code into ONE_CALCULATION_UNIT_TEST.
[/attacks]
[/set_specials]
[/effect]
[/object]
[lua]
code=<<
local alice = wesnoth.units.find({id="alice"})[1]
local bob = wesnoth.units.find({id="bob"})[1]
local args = ...
-- Bob attacks Alice, doing it this way round ensures that it's melee rather than ranged combat.
_, _, att_weapon, _ = wesnoth.simulate_combat(bob, alice)
unit_test.assert_equal(att_weapon.num_blows, args.expected, "Bob didnt have the expected number of attacks")
>>
[args]
expected={EXPECTED}
[/args]
[/lua]
{SUCCEED}
[/event]
)}
#enddef
#define ONE_CALCULATION_UNIT_TEST ID START OPERATIONS EXPECTED
# Assert that setting a unit's strikes to START and then performing the calculations in
# OPERATIONS gets the end result of EXPECTED.
{TWO_CALCULATION_UNIT_TEST ({ID}) ({START}) ({OPERATIONS}) () ({EXPECTED})}
#enddef
#####
# API(s) being tested: [attacks]add=
##
# Expected end state:
# Bob's attack is the obvious answer: 5 strikes + 2 strikes = 7 strikes.
#####
{ONE_CALCULATION_UNIT_TEST add 5 (add=2) 7}
#####
# API(s) being tested: [attacks]sub=
##
# Expected end state:
# Bob's attack is the obvious answer: 5 strikes - 3 strikes = 2 strikes.
#####
{ONE_CALCULATION_UNIT_TEST sub 5 (sub=3) 2}
#####
# API(s) being tested: [attacks]add=,[attacks]cumulative=
##
# Expected end state:
# Bob's attack has 8 strikes. These tags don't specify ids, cumulative doesn't affect add, and the larger value is chosen.
#####
{TWO_CALCULATION_UNIT_TEST add2_add3_cumulative 5 (cumulative,add=yes,2) (cumulative,add=yes,3) 8}
#####
# API(s) being tested: [attacks]add=,[attacks]cumulative=
##
# Expected end state:
# Bob's attack has 8 strikes. These tags don't specify ids, cumulative doesn't affect add, and the larger value is chosen.
#####
{TWO_CALCULATION_UNIT_TEST add3_add2_cumulative 5 (cumulative,add=yes,3) (cumulative,add=yes,2) 8}
#####
# API(s) being tested: [attacks]sub=
##
# Expected end state:
# Bob's attack has 7 strikes. The difference to add2_add3_cumulative is that sub chooses the lower value.
#####
{TWO_CALCULATION_UNIT_TEST add2_sub_minus3_cumulative 5 (cumulative,add=yes,2) (cumulative,sub=yes,-3) 7}
#####
# API(s) being tested: [attacks]sub=,[attacks]cumulative=
##
# Expected end state:
# Bob's attack has 2 strikes. These tags don't specify ids, cumulative doesn't affect sub, and the more negative value is chosen.
#####
{TWO_CALCULATION_UNIT_TEST sub2_sub3_cumulative 5 (cumulative,sub=yes,2) (cumulative,sub=yes,3) 2}
#####
# API(s) being tested: [attacks]sub=,[attacks]cumulative=
##
# Expected end state:
# Bob's attack has 2 strikes. These tags don't specify ids, cumulative doesn't affect sub, and the more negative value is chosen.
#####
{TWO_CALCULATION_UNIT_TEST sub3_sub2_cumulative 5 (cumulative,sub=yes,3) (cumulative,sub=yes,2) 2}
#####
# API(s) being tested: [attacks]
##
# Expected end state:
# Bob's attack has 12 strikes. When both are in the same [attacks] tag, addition has priority over multiplication.
#####
{ONE_CALCULATION_UNIT_TEST add_multiply_combined 2 (add,multiply=2,3) 12}
#####
# API(s) being tested: [attacks]
##
# Expected end state:
# Bob's attack has 12 strikes. Even in separate [attacks] tag and in the opposite order, addition has priority over multiplication.
#####
{TWO_CALCULATION_UNIT_TEST add_multiply_separated 2 (multiply=3) (add=2) 12}
#####
# API(s) being tested: [attacks]add=,[attacks]sub=
##
# Expected end state:
# Bob's attack has 2 strikes. When both add and sub are used in the same [attacks] tag, only the sub is used.
#####
{ONE_CALCULATION_UNIT_TEST add_sub_combined 5 (add,sub=2,3) 2}
#####
# API(s) being tested: [attacks]add=,[attacks]sub=
##
# Expected end state:
# Bob's attack has 2 strikes. Even in separate [attacks] tags, without separate ids the sub overwrites the add.
#####
{TWO_CALCULATION_UNIT_TEST add_sub_separated 5 (cumulative,add=yes,2) (cumulative,sub=yes,3) 2}
#####
# API(s) being tested: [attacks]cumulative=
##
# Expected end state:
# Bob's attack has 2 strikes. These tags don't specify ids, and cumulative doesn't affect add or sub.
#####
{TWO_CALCULATION_UNIT_TEST add_sub_cumulative 5 (cumulative,add=yes,2) (cumulative,sub=yes,3) 2}
#####
# API(s) being tested: [attacks]id=
##
# Expected end state:
# Bob's attack has 4 strikes. Having separate ids means both changes apply.
#####
{TWO_CALCULATION_UNIT_TEST add_sub_with_ids 5 (id,add=first,2) (id,sub=second,3) 4}
#####
# API(s) being tested: [attacks]divide=
##
# Expected end state:
# Bob's attack has 3 strikes after rounding down.
#####
{ONE_CALCULATION_UNIT_TEST divide 10 (divide=3) 3}
#####
# API(s) being tested: [attacks]divide=
##
# Expected end state:
# Bob's attack has 4 strikes after rounding down.
#####
{ONE_CALCULATION_UNIT_TEST divide_float_2dp 10 (divide=2.02) 4}
#####
# API(s) being tested: [attacks]divide=
##
# Expected end state:
# Bob's attack has 5 strikes. Here 2.008 is truncated to 2.00, and then 10 / 2.00 is 5.
#####
{ONE_CALCULATION_UNIT_TEST divide_float_3dp 10 (divide=2.008) 5}
#####
# API(s) being tested: [attacks]
##
# Expected end state:
# Bob's attack is the expected answer: 10 strikes * 2 / 3 = 6 strikes after rounding down.
#####
{ONE_CALCULATION_UNIT_TEST divide_multiply_combined 10 (divide,multiply=3,2) 6}
#####
# API(s) being tested: [attacks]divide=,[attacks]multiply=
##
# Expected end state:
# Bob's attack is the expected answer: 10 strikes * 2 / 3 = 6 strikes after rounding down.
#####
{TWO_CALCULATION_UNIT_TEST divide_multiply_separated 10 (divide=3) (multiply=2) 6}
#####
# API(s) being tested: [attacks]multiply=
##
# Expected end state:
# Bob's attack has 10 strikes, because 3 * 3.34 rounds by flooring to 10.
#####
{ONE_CALCULATION_UNIT_TEST multiply_float_2dp 3 (multiply=3.34) 10}
#####
# API(s) being tested: [attacks]multiply=
##
# Expected end state:
# Bob's attack has 9 strikes, because 3 * 3.334 first rounds 3.334 to 3.33, and then 3 * 3.33 floors to 9.
#####
{ONE_CALCULATION_UNIT_TEST multiply_float_3dp 3 (multiply=3.334) 9}
#undef ONE_CALCULATION_UNIT_TEST
#undef TWO_CALCULATION_UNIT_TEST

View file

@ -274,11 +274,32 @@
0 swarm_disables_upgrades_with_abilities_adjacent_fail
0 swarm_disables_upgrades_with_abilities_adjacent_leadership
0 swarm_disables_upgrades_with_abilities_adjacent_leadership_fail
0 test_add_in_leadership_abilities
0 test_sub_in_leadership_abilities
0 unslowable_status_test
0 unpetrifiable_status_test
0 test_force_chance_to_hit_macro
# Math operations in ability or specials tags
0 special_calculation_add
0 special_calculation_add2_add3_cumulative
0 special_calculation_add3_add2_cumulative
0 special_calculation_add_multiply_combined
0 special_calculation_add_multiply_separated
0 special_calculation_add_sub_combined
0 special_calculation_add_sub_cumulative
0 special_calculation_add2_sub_minus3_cumulative
0 special_calculation_add_sub_separated
0 special_calculation_add_sub_with_ids
0 special_calculation_divide
0 special_calculation_divide_float_2dp
0 special_calculation_divide_float_3dp
0 special_calculation_divide_multiply_combined
0 special_calculation_divide_multiply_separated
0 special_calculation_multiply_float_2dp
0 special_calculation_multiply_float_3dp
0 special_calculation_sub
0 special_calculation_sub2_sub3_cumulative
0 special_calculation_sub3_sub2_cumulative
0 test_add_in_leadership_abilities
0 test_sub_in_leadership_abilities
#
# Deterministic unit facing tests
0 recruit_facing_enemy_one