-
Notifications
You must be signed in to change notification settings - Fork 28
[Feat] :: Writen Tests for PlayerTrait #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,373 @@ | ||
| // ================================================================================ | ||
| // π Test PlayerTrait π | ||
| // ------------------------------------------------------------------------------- | ||
| // π Purpose : Unit tests for player functionality (init, equip, etc.) | ||
| // π¨βπ» Author : @ryzen-xp | ||
| // ================================================================================ | ||
|
|
||
| #[cfg(test)] | ||
| pub mod tests { | ||
| use coa::models::player::*; | ||
| use starknet::ContractAddress; | ||
| use starknet::contract_address_const; | ||
| use core::array::ArrayTrait; | ||
|
|
||
| const DEFAULT_HP: u256 = 500; | ||
| pub const DEFAULT_MAX_EQUIPPABLE_SLOT: u32 = 10; | ||
| const WAIST_MAX_SLOTS: u32 = 8; | ||
|
|
||
| fn mock_player_address() -> ContractAddress { | ||
| contract_address_const::<0x1234>() | ||
| } | ||
|
|
||
| fn mock_erc1155_address() -> ContractAddress { | ||
| contract_address_const::<0x5678>() | ||
| } | ||
|
|
||
| fn create_test_player() -> Player { | ||
| Player { | ||
| id: mock_player_address(), | ||
| hp: 0, | ||
| max_hp: 0, | ||
| equipped: array![], | ||
| max_equip_slot: 0, | ||
| rank: Default::default(), | ||
| level: 0, | ||
| xp: 0, | ||
| faction: 'test_faction', | ||
| next_rank_in: 0, | ||
| body: Default::default(), | ||
| } | ||
| } | ||
|
|
||
|
|
||
| #[test] | ||
| fn test_init_contract() { | ||
| let mut player = create_test_player(); | ||
|
|
||
| assert(player.max_hp == 0, 'PLAYER_SHOULD_BE_UNINITIALIZED'); | ||
|
|
||
| player.init('test'); | ||
|
|
||
| assert(player.hp == DEFAULT_HP, 'DEFAULT_PLAYER_HP'); | ||
| assert(player.max_hp == DEFAULT_HP, 'PLAYER_MAX_HP_IS_DEFAULT_HP'); | ||
| assert(player.max_equip_slot == DEFAULT_MAX_EQUIPPABLE_SLOT, 'DEFAULT_MAX_EQUIPPABLE_SLOT'); | ||
| assert(player.rank == Default::default(), 'RANK_IS_DEFAULT'); | ||
|
|
||
| let original_hp = player.hp; | ||
| player.init('different_faction'); | ||
| assert(player.hp == original_hp, 'REINIT_SHOULD_NOT_CHANGE_HP'); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: ('ZERO PLAYER',))] | ||
| fn test_check_fails_with_zero_address() { | ||
| let player = Player { | ||
| id: contract_address_const::<0x0>(), | ||
| hp: DEFAULT_HP, | ||
| max_hp: DEFAULT_HP, | ||
| equipped: array![], | ||
| max_equip_slot: DEFAULT_MAX_EQUIPPABLE_SLOT, | ||
| rank: Default::default(), | ||
| level: 0, | ||
| xp: 0, | ||
| faction: 'test', | ||
| next_rank_in: 0, | ||
| body: Default::default(), | ||
| }; | ||
|
|
||
| player.check(); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_add_xp_no_level_up() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let leveled_up = player.add_xp(500); | ||
|
|
||
| assert(!leveled_up, 'SHOULD_NOT_LEVEL_UP'); | ||
| assert(player.xp == 500, 'XP_SHOULD_BE_500'); | ||
| assert(player.level == 0, 'LEVEL_SHOULD_BE_0'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_add_xp_with_level_up() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let leveled_up = player.add_xp(1500); | ||
|
|
||
| assert(leveled_up, 'SHOULD_LEVEL_UP'); | ||
| assert(player.xp == 1500, 'XP_SHOULD_BE_1500'); | ||
| assert(player.level == 1, 'LEVEL_SHOULD_BE_1'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_add_xp_multiple_levels() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let leveled_up = player.add_xp(2500); | ||
|
|
||
| assert(leveled_up, 'SHOULD_LEVEL_UP'); | ||
| assert(player.xp == 2500, 'XP_SHOULD_BE_2500'); | ||
| assert(player.level == 2, 'LEVEL_SHOULD_BE_2'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_get_xp() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
| player.add_xp(750); | ||
|
|
||
| assert(player.get_xp() == 750, 'XP_SHOULD_BE_750'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_has_free_inventory_slot_empty() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| assert(player.has_free_inventory_slot(), 'SHOULD_HAVE_FREE_SLOTS'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_has_free_inventory_slot_full() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| // Fill slots | ||
| let mut i = 0; | ||
| while i < DEFAULT_MAX_EQUIPPABLE_SLOT { | ||
| player.equipped.append(i.into()); | ||
| i += 1; | ||
| }; | ||
|
|
||
| assert(!player.has_free_inventory_slot(), 'SHOULD_NOT_HAVE_FREE_SLOTS'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_equip_item() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let item_id: u256 = u256 { low: 0, high: 0x2000 }; | ||
|
|
||
| player.equip(item_id); | ||
|
|
||
| assert(player.equipped.len() == 1, 'SHOULD_HAVE_1_EQUIPPED_ITEM'); | ||
| assert(*player.equipped.at(0) == item_id, 'ITEM_SHOULD_BE_IN_LIST'); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: ('INSUFFICIENT EQUIP SLOTS',))] | ||
| fn test_equip_item_insufficient_slots() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let mut i = 0; | ||
| while i < DEFAULT_MAX_EQUIPPABLE_SLOT { | ||
| player.equipped.append(i.into()); | ||
| i += 1; | ||
| }; | ||
|
|
||
| player.equip(99999_u256); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_normal() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let is_alive = player.receive_damage(100); | ||
|
|
||
| assert(is_alive, 'PLAYER_SHOULD_BE_ALIVE'); | ||
| assert(player.hp == DEFAULT_HP - 100, 'HP_SHOULD_BE_REDUCED'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_lethal() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let is_alive = player.receive_damage(DEFAULT_HP + 100); | ||
|
|
||
| assert(!is_alive, 'PLAYER_SHOULD_BE_DEAD'); | ||
| assert(player.hp == 0, 'HP_SHOULD_BE_0'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_exact_lethal() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let is_alive = player.receive_damage(DEFAULT_HP); | ||
|
|
||
| assert(!is_alive, 'PLAYER_SHOULD_BE_DEAD'); | ||
| assert(player.hp == 0, 'HP_SHOULD_BE_0'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_calculate_damage_reduction_no_armor() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let reduction = player.calculate_damage_reduction(); | ||
| assert(reduction == 0, 'SHOULD_HAVE_NO_DAMAGE_REDUCTION'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_calculate_damage_reduction_with_armor() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| player.body.upper_torso.append(1_u256); | ||
| player.body.lower_torso.append(2_u256); | ||
| player.body.head = 3_u256; | ||
|
|
||
| let reduction = player.calculate_damage_reduction(); | ||
| assert(reduction == 18, 'SHOULD_HAVE_18_DAMAGE_REDUCTION'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_with_armor() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| player.body.upper_torso.append(1_u256); | ||
|
|
||
| let is_alive = player.receive_damage(50); | ||
|
|
||
| assert(is_alive, 'PLAYER_SHOULD_BE_ALIVE'); | ||
| assert(player.hp == DEFAULT_HP - 40, 'HP_SHOULD_BE_REDUCED_BY_40'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_armor_blocks_all() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| player.body.upper_torso.append(1_u256); | ||
| player.body.lower_torso.append(2_u256); | ||
| player.body.head = 3_u256; | ||
|
|
||
| let original_hp = player.hp; | ||
| let is_alive = player.receive_damage(15); | ||
|
|
||
| assert(is_alive, 'PLAYER_SHOULD_BE_ALIVE'); | ||
| assert(player.hp == original_hp, 'HP_SHOULD_NOT_BE_REDUCED'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_get_multiplier() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let multiplier = player.get_multiplier(); | ||
| assert(multiplier == 0, 'MULTIPLIER_SHOULD_BE_0'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_is_available() { | ||
| let mut player = create_test_player(); | ||
| player.init('test_faction'); | ||
|
|
||
| let available = player.is_available(123_u256); | ||
| assert(available, 'ITEM_SHOULD_BE_AVAILABLE'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_helper_functions() { | ||
| let test_val: u256 = 0x123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0; | ||
|
|
||
| let high = get_high(test_val); | ||
| let low = get_low(test_val); | ||
|
|
||
| assert(high == test_val.high, 'HIGH_BITS_SHOULD_MATCH'); | ||
| assert(low == test_val.low, 'LOW_BITS_SHOULD_MATCH'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_player_progression() { | ||
| let mut player = create_test_player(); | ||
| player.init('warrior'); | ||
|
|
||
| let leveled_up = player.add_xp(1000); | ||
| assert(leveled_up, 'SHOULD_LEVEL_UP_TO_1'); | ||
| assert(player.level == 1, 'LEVEL_SHOULD_BE_1'); | ||
|
|
||
| player.equip(u256 { low: 0, high: 0x2000 }); | ||
| player.equip(u256 { low: 0, high: 0x105 }); | ||
| assert(player.equipped.len() == 2, 'SHOULD_HAVE_2_EQUIPPED_ITEMS'); | ||
|
|
||
| let is_alive = player.receive_damage(100); | ||
| assert(is_alive, 'SHOULD_SURVIVE_DAMAGE'); | ||
| assert(player.hp < DEFAULT_HP, 'HP_SHOULD_BE_REDUCED'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_combat_scenario() { | ||
| let mut player = create_test_player(); | ||
| player.init('knight'); | ||
|
|
||
| player.body.upper_torso.append(1_u256); | ||
| player.body.head = 2_u256; | ||
|
|
||
| let mut is_alive = player.receive_damage(50); | ||
| assert(is_alive, 'SHOULD_SURVIVE_FIRST_HIT'); | ||
|
|
||
| is_alive = player.receive_damage(200); | ||
| assert(is_alive, 'SHOULD_SURVIVE_SECOND_HIT'); | ||
|
|
||
| let expected_hp = DEFAULT_HP - 37 - 187; | ||
| assert(player.hp == expected_hp, 'HP_CAL_SHOULD_BE_CORRECT'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_zero_damage() { | ||
| let mut player = create_test_player(); | ||
| player.init('test'); | ||
| let original_hp = player.hp; | ||
|
|
||
| let is_alive = player.receive_damage(0); | ||
|
|
||
| assert(is_alive, 'PLAYER_SHOULD_BE_ALIVE'); | ||
| assert(player.hp == original_hp, 'HP_SHOULD_NOT_CHANGE'); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: ('CANNOT EQUIP',))] | ||
| fn test_equip_same_item_twice() { | ||
| let mut player = create_test_player(); | ||
| player.init('test'); | ||
| let item_id = u256 { low: 0, high: 0x2000 }; | ||
|
|
||
| player.equip(item_id); | ||
| player.equip(item_id); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_receive_damage_when_dead() { | ||
| let mut player = create_test_player(); | ||
| player.init('test'); | ||
|
|
||
| player.receive_damage(DEFAULT_HP + 100); // kill | ||
| let is_alive = player.receive_damage(50); | ||
|
|
||
| assert(!is_alive, 'DEAD_PLAYER_SHOULD_REMAIN_DEAD'); | ||
| assert(player.hp == 0, 'HP_SHOULD_STAY_ZERO'); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_add_zero_xp() { | ||
| let mut player = create_test_player(); | ||
| player.init('test'); | ||
|
|
||
| let leveled_up = player.add_xp(0); | ||
|
|
||
| assert(!leveled_up, 'SHOULD_NOT_LEVEL_UP'); | ||
| assert(player.xp == 0, 'XP_SHOULD_STILL_BE_0'); | ||
| assert(player.level == 0, 'LEVEL_SHOULD_BE_0'); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Avoid duplicating production constants in tests (drift risk).
DEFAULT_HPandDEFAULT_MAX_EQUIPPABLE_SLOTmirror production values. If those change, tests silently become wrong. Capture runtime values from the initialized player instead.Example adjustments:
let base_hp = player.hp;orplayer.max_hpinstead ofDEFAULT_HP.let slot_cap = player.max_equip_slot;instead ofDEFAULT_MAX_EQUIPPABLE_SLOT.See concrete diffs below in relevant tests.
π€ Prompt for AI Agents