From c7673e7a0a045d528a2da2eb502b0351a4bfa30c Mon Sep 17 00:00:00 2001 From: CFDeadlines <47742787+Coffee-fueled-deadlines@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:14:36 -0400 Subject: [PATCH 1/4] Update Inventory.py --- PyDnD/Inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyDnD/Inventory.py b/PyDnD/Inventory.py index 5f867d9..7fc69ea 100644 --- a/PyDnD/Inventory.py +++ b/PyDnD/Inventory.py @@ -4,7 +4,7 @@ {License_info} -Inventory Module is creating and managing player inventories +Inventory Module is creating and managing player inventories """ # META Data From 6fa5130bfe5028b1265ab18afadfe92821e50c32 Mon Sep 17 00:00:00 2001 From: CFDeadlines <47742787+Coffee-fueled-deadlines@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:16:12 -0400 Subject: [PATCH 2/4] Update Inventory.py --- PyDnD/Inventory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PyDnD/Inventory.py b/PyDnD/Inventory.py index 7fc69ea..04c652e 100644 --- a/PyDnD/Inventory.py +++ b/PyDnD/Inventory.py @@ -43,6 +43,9 @@ def __init__(self, max_size=10): self.items = [] self.max_size = max_size + def test_method(self): + print("This method exists to test github actions") + def add_item(self, item, quantity=1): """ Adds a specified quantity of an item to the inventory if there is space. From f29d8d947f5f2b9cd14ccc59befb4b1c7ba4ca89 Mon Sep 17 00:00:00 2001 From: CFDeadlines <47742787+Coffee-fueled-deadlines@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:20:47 -0400 Subject: [PATCH 3/4] Update Inventory.py --- PyDnD/Inventory.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/PyDnD/Inventory.py b/PyDnD/Inventory.py index 04c652e..5f867d9 100644 --- a/PyDnD/Inventory.py +++ b/PyDnD/Inventory.py @@ -4,7 +4,7 @@ {License_info} -Inventory Module is creating and managing player inventories +Inventory Module is creating and managing player inventories """ # META Data @@ -43,9 +43,6 @@ def __init__(self, max_size=10): self.items = [] self.max_size = max_size - def test_method(self): - print("This method exists to test github actions") - def add_item(self, item, quantity=1): """ Adds a specified quantity of an item to the inventory if there is space. From 1b0c8dbdd4d863f66bc2698625c05821cae32c80 Mon Sep 17 00:00:00 2001 From: CFDeadlines <47742787+Coffee-fueled-deadlines@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:50:09 -0400 Subject: [PATCH 4/4] Adjusted Systems Adjusted systems and added tests --- PyDnD/LevelingSystem.py | 2 - PyDnD/Player.py | 10 +--- example.py | 26 +++++++++ tests/test_dice.py | 53 ++++++++++++++++++ tests/test_levelingsystem.py | 61 +++++++++++++++++++++ tests/test_player.py | 103 +++++++++++++++++++++++++++++++++++ tests/test_roll.py | 55 +++++++++++++++++++ 7 files changed, 300 insertions(+), 10 deletions(-) create mode 100644 tests/test_dice.py create mode 100644 tests/test_levelingsystem.py create mode 100644 tests/test_player.py create mode 100644 tests/test_roll.py diff --git a/PyDnD/LevelingSystem.py b/PyDnD/LevelingSystem.py index 282b61c..d8ce304 100644 --- a/PyDnD/LevelingSystem.py +++ b/PyDnD/LevelingSystem.py @@ -93,8 +93,6 @@ def removeExp(self, xp): if self.player.level == 1: if xp > self.player._experience: self.player._experience = 0 - else: - self.player._experience -= xp break else: self.levelDown() diff --git a/PyDnD/Player.py b/PyDnD/Player.py index 69a22e9..d2366a8 100644 --- a/PyDnD/Player.py +++ b/PyDnD/Player.py @@ -436,16 +436,10 @@ def featpoints(self, value): # Inventory Methods def add_item_to_inventory(self, item, quantity=1): - try: - self.inventory.add_item(item, quantity) - except InventoryIsFull as e: - print(e) + self.inventory.add_item(item, quantity) def remove_item_from_inventory(self, item, quantity=1): - try: - self.inventory.remove_item(item, quantity) - except ItemNotInInventory as e: - print(e) + self.inventory.remove_item(item, quantity) def get_inventory(self): return self.inventory.items diff --git a/example.py b/example.py index fc74f45..ac6bec9 100644 --- a/example.py +++ b/example.py @@ -57,6 +57,32 @@ newPlayer.add_item_to_inventory("Mjolnir") print( f"\t\tThor's inventory is: \n\t\t\t{newPlayer.get_inventory()}\n" ) + # Oh no he's not worthy again + newPlayer.remove_item_from_inventory("Mjolnir") + print( f"\t\tThor's inventory is: \n\t\t\t{newPlayer.get_inventory()}\n" ) + print("\n\n") + + print( "LEVEL DOWN") + + print("\n\n") + # Lets see what Thor looks like as a level 2 + newPlayer.removeExp(500) + print( "\tNew Level: " + str( newPlayer.level ) ) # newPlayer.level is automatically increased when XP threshold increases + print( "\tCurrent Experience: " + str( newPlayer.experience ) ) # Current, experience after leveling up + print( "\tEXP to next Level: " + str( newPlayer.nextLvlExperience ) ) # 3000 Experience total is required to get to level 3 + print( "\n\t--Stats--\n") + print( "\t\tStrength is: " + str( newPlayer.strength )) + print( "\t\tDexterity is: " + str( newPlayer.dexterity )) + print( "\t\tConsitution is: " + str( newPlayer.constitution )) + print( "\t\tWisdom is: " + str( newPlayer.wisdom )) + print( "\t\tIntelligence is: " + str( newPlayer.intelligence )) + print( "\t\tCharisma is: " + str( newPlayer.charisma )) + print( "\n\t--Inventory--\n" ) + + # Lets give Thor back his hammer + newPlayer.add_item_to_inventory("Mjolnir") + print( f"\t\tThor's inventory is: \n\t\t\t{newPlayer.get_inventory()}\n" ) + # Oh no he's not worthy again newPlayer.remove_item_from_inventory("Mjolnir") print( f"\t\tThor's inventory is: \n\t\t\t{newPlayer.get_inventory()}\n" ) diff --git a/tests/test_dice.py b/tests/test_dice.py new file mode 100644 index 0000000..bf72065 --- /dev/null +++ b/tests/test_dice.py @@ -0,0 +1,53 @@ +import unittest +from PyDnD.Dice import Dice + +class TestDice(unittest.TestCase): + + def test_single_die_roll(self): + """Test rolling a single die.""" + dice = Dice(num_dice=1, sides=6) + dice.roll() + self.assertIn(dice.value, range(1, 7), "Roll value should be between 1 and 6") + self.assertEqual(len(dice.rolls), 1, "Should have only one roll") + + def test_multiple_dice_roll(self): + """Test rolling multiple dice.""" + dice = Dice(num_dice=3, sides=6) + dice.roll() + # Ensure the total value is within the expected range for 3d6 + self.assertIn(dice.value, range(3, 19), "Roll value should be between 3 and 18") + self.assertEqual(len(dice.rolls), 3, "Should have 3 rolls") + + def test_dice_with_modifier(self): + """Test rolling dice with a modifier.""" + dice = Dice(num_dice=2, sides=6, modifier=2) + dice.roll() + # Minimum roll with modifier: 2 * 1 + 2 = 4 + # Maximum roll with modifier: 2 * 6 + 2 = 14 + self.assertIn(dice.value, range(4, 15), "Roll value with modifier should be between 4 and 14") + + def test_dice_with_drop_lowest(self): + """Test rolling dice and dropping the lowest roll.""" + dice = Dice(num_dice=4, sides=6, drop_lowest=1) + dice.roll() + # Check the number of rolls and the value after dropping the lowest + self.assertEqual(len(dice.rolls), 4, "Should have 4 rolls") + self.assertTrue(3 <= dice.value <= 18, "Roll value after dropping lowest should be between 3 and 18") + + def test_dice_with_invalid_num_dice(self): + """Test rolling with an invalid number of dice.""" + with self.assertRaises(ValueError): + Dice(num_dice=0, sides=6) + + def test_dice_with_invalid_sides(self): + """Test rolling with an invalid number of sides.""" + with self.assertRaises(ValueError): + Dice(num_dice=1, sides=0) + + def test_dice_with_invalid_drop_lowest(self): + """Test rolling with drop_lowest greater than num_dice.""" + with self.assertRaises(ValueError): + Dice(num_dice=2, sides=6, drop_lowest=3) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_levelingsystem.py b/tests/test_levelingsystem.py new file mode 100644 index 0000000..5846fa5 --- /dev/null +++ b/tests/test_levelingsystem.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import MagicMock + +from PyDnD.LevelingSystem import LevelingSystem +from PyDnD.Player import Player + +class TestLevelingSystem(unittest.TestCase): + + def setUp(self): + """Set up a basic player and leveling system for testing.""" + self.player = Player(name="Test Player", level=1) + self.leveling_system = LevelingSystem(self.player) + + def test_initial_experience(self): + """Test that the player starts with the correct initial experience.""" + self.assertEqual(self.player.experience, 0, "Initial experience should be 0 at level 1") + + def test_give_experience_level_up(self): + """Test that giving experience correctly levels up the player.""" + self.leveling_system.giveExp(1000) + self.assertEqual(self.player.level, 2, "Player should level up to 2 after gaining 1000 XP") + self.assertEqual(self.player.experience, 1000, "Player's experience should be 1000 after leveling up") + self.assertEqual(self.leveling_system.nextLvlExperience, 3000 - 1000, "Next level experience should be correctly calculated") + + def test_remove_experience_level_down(self): + """Test that removing experience correctly levels down the player.""" + self.leveling_system.giveExp(3000) + self.assertEqual(self.player.level, 3, "Player should level up to 3 after gaining 3000 XP") + + self.leveling_system.removeExp(2000) + self.assertEqual(self.player.level, 2, "Player should level down to 2 after losing 2000 XP") + self.assertEqual(self.player.experience, 1000, "Player's experience should be 1000 after leveling down") + self.assertEqual(self.leveling_system.nextLvlExperience, 3000 - 1000, "Next level experience should be correctly calculated for level 2") + + def test_no_level_down_below_1(self): + """Test that the player does not level down below level 1.""" + self.leveling_system.giveExp(500) + self.leveling_system.removeExp(1000) + self.assertEqual(self.player.level, 1, "Player should not level down below 1") + self.assertEqual(self.player.experience, 0, "Player's experience should be 0 after losing all XP") + + def test_get_threshold_for_next_level(self): + """Test calculation of the experience threshold for the next level.""" + threshold = self.leveling_system.getThresholdForNextLevel() + expected_threshold = int(1000 * (2 + LevelingSystem.nCr(2, 2)) - 2 * 1000) + self.assertEqual(threshold, expected_threshold, "Threshold for next level should be correctly calculated") + + def test_get_threshold_for_current_level(self): + """Test calculation of the experience threshold for the current level.""" + threshold = self.leveling_system.getThresholdForCurrentLevel() + expected_threshold = int(1000 * (1 + LevelingSystem.nCr(1, 2)) - 1 * 1000) + self.assertEqual(threshold, expected_threshold, "Threshold for current level should be correctly calculated") + + def test_invalid_nCr(self): + """Test that nCr calculation handles invalid inputs.""" + self.assertEqual(LevelingSystem.nCr(5, 0), 1.0, "nCr with r=0 should be 1.0") + self.assertEqual(LevelingSystem.nCr(5, 5), 1.0, "nCr with r=n should be 1.0") + self.assertEqual(LevelingSystem.nCr(5, 3), 10.0, "nCr should correctly calculate the combinations") + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_player.py b/tests/test_player.py new file mode 100644 index 0000000..a4afa45 --- /dev/null +++ b/tests/test_player.py @@ -0,0 +1,103 @@ +import unittest +from PyDnD.Player import Player +from PyDnD.Inventory import ItemNotInInventory, InventoryIsFull + +class TestPlayer(unittest.TestCase): + + def setUp(self): + """Set up a basic player for testing.""" + self.player = Player( + name="Test Player", + age="25", + gender="Male", + alignment="NG", + description="A brave warrior", + biography="Born to be a hero", + level=1, + wealth=100, + strength=15, + dexterity=12, + constitution=14, + wisdom=10, + intelligence=13, + charisma=8, + hp=10, + mp=5, + inventory_size=10 + ) + + def test_initialization(self): + """Test that the player is initialized correctly.""" + self.assertEqual(self.player.name, "Test Player") + self.assertEqual(self.player.age, "25") + self.assertEqual(self.player.gender, "Male") + self.assertEqual(self.player.alignment, "NG") + self.assertEqual(self.player.description, "A brave warrior") + self.assertEqual(self.player.biography, "Born to be a hero") + self.assertEqual(self.player.level, 1) + self.assertEqual(self.player.wealth, 100) + self.assertEqual(self.player.strength, 15) + self.assertEqual(self.player.dexterity, 12) + self.assertEqual(self.player.constitution, 14) + self.assertEqual(self.player.wisdom, 10) + self.assertEqual(self.player.intelligence, 13) + self.assertEqual(self.player.charisma, 8) + self.assertEqual(self.player.hp, 10) + self.assertEqual(self.player.mp, 5) + self.assertEqual(len(self.player.inventory.items), 0) + + def test_experience_and_leveling(self): + """Test the experience and leveling system.""" + self.player.giveExp(1000) + self.assertEqual(self.player.level, 2) + self.assertEqual(self.player.experience, 1000) + self.assertEqual(self.player.nextLvlExperience, 2000) + + self.player.removeExp(500) + self.assertEqual(self.player.level, 1) + self.assertEqual(self.player.experience, 500) + self.assertEqual(self.player.nextLvlExperience, 500) + + def test_inventory_addition(self): + """Test adding items to the player's inventory.""" + self.player.add_item_to_inventory("Sword", quantity=9) # Fill inventory to 9/10 slots + self.assertEqual(len(self.player.get_inventory()), 9) + + self.player.add_item_to_inventory("Shield") # 10/10 slots now + self.assertEqual(len(self.player.get_inventory()), 10) + + with self.assertRaises(InventoryIsFull): + self.player.add_item_to_inventory("Helmet") # Should raise InventoryIsFull since it's full + + + def test_inventory_removal(self): + """Test removing items from the player's inventory.""" + self.player.add_item_to_inventory("Potion", quantity=2) + self.player.remove_item_from_inventory("Potion") # Removes one potion + self.assertEqual(self.player.get_inventory().count("Potion"), 1) + + with self.assertRaises(ItemNotInInventory): + self.player.remove_item_from_inventory("Potion", quantity=2) # Only 1 potion left, removing 2 should raise error + + + def test_alignment_validation(self): + """Test alignment validation.""" + with self.assertRaises(ValueError): + self.player.alignment = "ABC" + + def test_negative_hp(self): + """Test that negative HP raises an error.""" + with self.assertRaises(ValueError): + self.player.hp = -5 + + def test_invalid_stat(self): + """Test that invalid stats raise an error.""" + with self.assertRaises(ValueError): + self.player.strength = -1 + with self.assertRaises(ValueError): + self.player.dexterity = "high" + + def test_inventory_full(self): + """Test that adding too many items raises an InventoryIsFull exception.""" + self.player.add_item_to_inventory("Gold Coin", quantity=10) + diff --git a/tests/test_roll.py b/tests/test_roll.py new file mode 100644 index 0000000..944dd26 --- /dev/null +++ b/tests/test_roll.py @@ -0,0 +1,55 @@ +import unittest +from PyDnD.Roll import Roll + +class TestRoll(unittest.TestCase): + + def test_single_die_roll(self): + """Test rolling a single die without modifiers or drop_lowest.""" + result = Roll.roll(num_dice=1, sides=6) + self.assertIn(result, range(1, 7), "Roll value should be between 1 and 6") + + def test_multiple_dice_roll(self): + """Test rolling multiple dice without modifiers or drop_lowest.""" + result = Roll.roll(num_dice=3, sides=6) + self.assertIn(result, range(3, 19), "Roll value should be between 3 and 18") + + def test_dice_with_modifier(self): + """Test rolling dice with a positive modifier.""" + result = Roll.roll(num_dice=2, sides=6, modifier=2) + self.assertIn(result, range(4, 15), "Roll value with modifier should be between 4 and 14") + + def test_dice_with_negative_modifier(self): + """Test rolling dice with a negative modifier.""" + result = Roll.roll(num_dice=2, sides=6, modifier=-2) + self.assertIn(result, range(0, 13), "Roll value with negative modifier should be between 0 and 13") + + def test_dice_with_drop_lowest(self): + """Test rolling dice and dropping the lowest roll.""" + result = Roll.roll(num_dice=4, sides=6, drop_lowest=1) + self.assertIn(result, range(3, 19), "Roll value after dropping lowest should be between 3 and 18") + + def test_roll_with_return_rolls(self): + """Test rolling dice and returning the individual rolls.""" + total, rolls = Roll.roll(num_dice=5, sides=6, return_rolls=True) + self.assertEqual(len(rolls), 5, "Should return a list of 5 rolls") + for roll in rolls: + self.assertIn(roll, range(1, 7), "Each roll should be between 1 and 6") + self.assertEqual(total, sum(rolls), "Total should be the sum of the rolls") + + def test_invalid_num_dice(self): + """Test that an invalid number of dice raises a ValueError.""" + with self.assertRaises(ValueError): + Roll.roll(num_dice=0, sides=6) + + def test_invalid_sides(self): + """Test that an invalid number of sides raises a ValueError.""" + with self.assertRaises(ValueError): + Roll.roll(num_dice=1, sides=0) + + def test_invalid_drop_lowest(self): + """Test that dropping more dice than rolled raises a ValueError.""" + with self.assertRaises(ValueError): + Roll.roll(num_dice=2, sides=6, drop_lowest=3) + +if __name__ == '__main__': + unittest.main()