class TestPlayerMethods(unittest.TestCase): def setUp(self): self.item_factory = ItemFactory(item_data) self.player = Player( inventory={}, wearing=self.item_factory.create_dictionary_from_nouns( [Noun.BOXER_SHORTS]), score=0, health=100, # percent caffeine_level=50 # milligrams ) def test_combing(self): comb = self.item_factory.create_from_noun(Noun.COMB) beard_oil = self.item_factory.create_from_noun(Noun.BEARD_OIL) self.assertEqual(self.player.beard_status, BeardHealth.STRAGGLY_MESS) (result, message) = self.player.do_verb(Verb.COMB, Noun.BEARD) self.assertFalse( result, "Shouldn't be able to comb if you're not holding a comb") self.player.give(comb) (result, message) = self.player.do_verb(Verb.COMB) self.assertFalse( result, "I didn't provide a noun, so what the hell did I just comb?") self.assertEqual( message, "Comb what?", "Unexpected message when trying to comb without a noun") (result, message) = self.player.do_verb(Verb.COMB, Noun.BOXER_SHORTS) self.assertFalse(result, "You should *not* be able to comb your shorts") self.assertEqual( message, "You can't comb that.", "Unexpected message when trying to comb without a noun") (result, message) = self.player.do_verb(Verb.COMB, Noun.BEARD) self.assertTrue(result) self.assertEqual( self.player.beard_status, BeardHealth.QUITE_TIDY, "Combing beard without oil should result in QUITE TIDY") (result, message) = self.player.do_verb(Verb.COMB, Noun.BEARD) self.assertFalse(result) self.assertEqual( self.player.beard_status, BeardHealth.QUITE_TIDY, "Combing an already tidy beard should change nothing.") self.player.give(beard_oil) (result, message) = self.player.do_verb(Verb.COMB, Noun.BEARD) self.assertFalse( result, "Just having the beard oil should make no difference") self.assertEqual( self.player.beard_status, BeardHealth.QUITE_TIDY, "Just having the beard oil should make no difference") self.player.wear(Noun.BEARD_OIL) (result, message) = self.player.do_verb(Verb.COMB, Noun.BEARD) self.assertTrue( result, "Combing a QUITE TIDY beard while wearing the beard oil should work" ) self.assertEqual( self.player.beard_status, BeardHealth.PERFECTION, "Combing a QUITE TIDY beard while wearing the beard oil should result in PERFECTION" ) def test_riding(self): # Something you can't ride (result, message) = self.player.do_verb(Verb.RIDE, Noun.BOXER_SHORTS) self.assertFalse(result, "Shouldn't be able to ride boxer shorts!") # Something you can ride bike = self.item_factory.create_from_noun(Noun.PENNY_FARTHING) self.assertFalse(self.player.is_riding_anything) (result, message) = self.player.do_verb(Verb.RIDE, Noun.PENNY_FARTHING) self.assertFalse( result, "Shouldn't be able to ride the bike unless you're holding it.") self.player.give(bike) (result, message) = self.player.do_verb(Verb.RIDE, Noun.PENNY_FARTHING) self.assertTrue( result, "Should be able to ride the bike if you're holding it.") (result, message) = self.player.do_verb(Verb.DISMOUNT, Noun.BOXER_SHORTS) self.assertFalse( result, "Shouldn't be able to dismount something you're not riding.") self.assertTrue(self.player.is_riding_anything) self.assertTrue(self.player.is_riding(Noun.PENNY_FARTHING)) self.assertFalse(self.player.is_riding(Noun.BOXER_SHORTS)) (item, message) = self.player.take(Noun.PENNY_FARTHING) self.assertIsNone( item, "Shouldn't be able to drop something you're riding.") (result, message) = self.player.do_verb(Verb.DISMOUNT, Noun.PENNY_FARTHING) self.assertTrue( result, "Should be able to dismount the bike if you're riding it.") self.assertFalse(self.player.is_riding_anything) # Shouldn't be able to ride anything twice (result, message) = self.player.do_verb(Verb.RIDE, Noun.PENNY_FARTHING) (result, message) = self.player.do_verb(Verb.RIDE, Noun.PENNY_FARTHING) self.assertFalse( result, "Shouldn't be able to ride more than one thing at once.") self.player.do_verb(Verb.DISMOUNT, Noun.PENNY_FARTHING) rules = {"can_ride": (False, "You can't ride that in here!")} (result, message) = self.player.do_verb(Verb.RIDE, Noun.PENNY_FARTHING, rules) self.assertFalse(result, "Shouldn't be able to ride if prohibited by rules.") self.assertEqual(message, "You can't ride that in here!") def test_basic_wearing(self): self.assertFalse( self.player.is_fully_clothed, "Player wearing just boxers shouldn't read as fully clothed.") # These trousers aren't wearable: attrs = { 'has_trait.return_value': False, 'get_trait.return_value': None } trousers = Mock(id="trousers", name="trousers", **attrs) self.player.give(trousers) (result, message) = self.player.wear("trousers") self.assertFalse( result, "Should not be able to wear an item with no wearable trait") self.assertEqual(message, "You can't wear that.", "Unexpected message from wear failure") # This shirt is wearable and moveable def has_trait(trait): return trait in ("wearable", "moveable") def get_trait(trait): return {} if trait in ("wearable", "moveable") else None attrs = { 'has_trait.side_effect': has_trait, 'get_trait.side_effect': get_trait } shirt = Mock(id="shirt", name="shirt", **attrs) self.player.give(shirt) (result, message) = self.player.wear("shirt") self.assertTrue( result, f"Should be able to wear a basic wearable item. Message was: {message}" ) def test_wearing_tops(self): # Two wearable, moveable tops: def has_trait(trait): return trait in ("wearable", "moveable") def get_trait(trait): if trait in ("wearable"): return {"slot": "top"} if trait in ("moveable"): return {} return None attrs = { 'has_trait.side_effect': has_trait, 'get_trait.side_effect': get_trait } shirt1 = Mock(id="shirt1", name="shirt one", **attrs) shirt2 = Mock(id="shirt2", name="shirt two", **attrs) self.player.give(shirt1) self.player.give(shirt2) (result, message) = self.player.wear("shirt1") self.assertTrue( result, f"Should be able to wear one top. Failure message was: {message}") (result, message) = self.player.wear("shirt2") self.assertFalse( result, f"Should not be able to wear two tops. Unexpected success message was: {message}" ) self.assertIn( "take something off", message, "Failure message on trying to wear two shirts should include correct advice." ) def test_wearing_bottoms(self): # Two wearable, moveable bottoms: def has_trait(trait): return trait in ("wearable", "moveable") def get_trait(trait): if trait in ("wearable"): return {"slot": "bottom"} if trait in ("moveable"): return {} return None attrs = { 'has_trait.side_effect': has_trait, 'get_trait.side_effect': get_trait } trousers1 = Mock(id="trousers1", **attrs) # Workaround because Mock itself has an annoying name attribute! https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute trousers1.configure_mock(name="trousers1") trousers2 = Mock(id="trousers2", name="trousers two", **attrs) # Workaround because Mock itself has an annoying name attribute! https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute trousers2.configure_mock(name="trousers2") self.player.give(trousers1) self.player.give(trousers2) (result, message) = self.player.wear("trousers1") self.assertTrue( result, f"Should be able to wear one set of bottoms. Failure message was: {message}" ) (result, message) = self.player.wear("trousers2") self.assertFalse( result, f"Should not be able to wear two sets of bottoms. Unexpected success message was: {message}" ) self.assertIn( "take something off", message, "Failure message on trying to wear two pairs of trousers should include correct advice." ) def test_wearing_status(self): # Top def has_trait_top(trait): return trait in ("wearable", "moveable") def get_trait_top(trait): if trait in ("moveable"): return {} if trait in ("wearable"): return {"slot": "top"} return None attrs = { 'has_trait.side_effect': has_trait_top, 'get_trait.side_effect': get_trait_top } shirt = Mock(id="shirt", **attrs) # Workaround because Mock itself has an annoying name attribute! https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute shirt.configure_mock(name="shirt") # Bottoms def has_trait_bottom(trait): return trait in ("wearable", "moveable") def get_trait_bottom(trait): if trait in ("wearable"): return {"slot": "bottom"} if trait in ("moveable"): return {} return None attrs = { 'has_trait.side_effect': has_trait_bottom, 'get_trait.side_effect': get_trait_bottom } trousers = Mock(id="trousers", **attrs) # Workaround because Mock itself has an annoying name attribute! https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute trousers.configure_mock(name="trousers") self.player.give(shirt) self.player.give(trousers) # Basics self.assertTrue(self.player.is_wearing(Noun.BOXER_SHORTS), "Test player should start with boxers on") self.assertFalse( self.player.is_wearing("didgeridoo"), "is_wearing should not be true for an arbitrary didgeridoo") self.assertFalse(self.player.is_fully_clothed) # Add a top and re-test self.player.wear("shirt") self.assertEqual(self.player.wearing_in_slot('top'), shirt) self.assertIsNone(self.player.wearing_in_slot('bottom')) self.assertFalse(self.player.is_fully_clothed) # Add trousers self.player.wear("trousers") self.assertEqual(self.player.wearing_in_slot('top'), shirt) self.assertEqual(self.player.wearing_in_slot('bottom'), trousers) self.assertTrue(self.player.is_fully_clothed) self.player.unwear("trousers") self.assertFalse(self.player.is_fully_clothed) self.player.unwear("shirt") self.assertFalse(self.player.is_fully_clothed)
class TestItemMethods(unittest.TestCase): def setUp(self): self.factory = ItemFactory(item_data) def test_traitless_item(self): item = self.factory.create_from_noun("basic") self.assertEqual(item.name, "a very basic item") self.assertIsInstance(item, Item) def test_basic_item(self): item = self.factory.create_from_noun("shirt") self.assertEqual(item.name, "a natty Paisley print shirt") self.assertEqual( item.description, "a delightful fitted shirt with a strong Paisley pattern. As you look closely at it your eyes water slightly." ) self.assertTrue(item.has_trait("moveable")) self.assertTrue(item.has_trait("wearable")) def test_basic_stateful_item(self): item = self.factory.create_from_noun("torch") self.assertEqual(item.name, "an Ever Ready torch") self.assertTrue(item.has_trait("moveable")) self.assertFalse(item.has_trait("wearable")) def test_state_change_returns(self): item = self.factory.create_from_noun("torch") (result, message) = item.do_verb("turn off") self.assertFalse( result, "Turning off a turned off item unexpectedly did something.") (result, message) = item.do_verb("turn on") self.assertTrue(result, "Could not turn on a turned off item.") self.assertEqual(message, "You turn on the torch.", "Wrong message when turning on item.") (result, message) = item.do_verb("turn off") self.assertTrue(result, "Could not turn off a turned on item.") self.assertEqual(message, "You turn off the torch.", "Wrong message when turning off item.") def test_stateful_item_states(self): item = self.factory.create_from_noun("torch") (result, message) = item.do_verb("turn on") self.assertTrue(result, "You should be able to turn on a torch.") (result, message) = item.do_verb("turn off") self.assertTrue(result, "You should be able to turn off a torch.") (result, message) = item.do_verb("throw") self.assertFalse(result, "Shouln't be able to throw the torch.") self.assertEqual(message, "You can't do that.", "Wrong failure message when throwing torch.") self.assertEqual( item.description, "a plastic 1970s Ever Ready torch. It is switched off.") item.do_verb("turn on") self.assertEqual( item.description, "a plastic 1970s Ever Ready torch. It's switched on, and emits a surprising amount of light." ) item.do_verb("turn off") self.assertEqual( item.description, "a plastic 1970s Ever Ready torch. It is switched off.") item.do_verb("turn off") self.assertEqual( item.description, "a plastic 1970s Ever Ready torch. It is switched off.") def test_simple_verbable_item(self): item = self.factory.create_from_noun("simpleverbable") (result, message) = item.do_verb("flobble") self.assertFalse(result, "Shouldn't be able to flobble a SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertTrue(result, "Should be able to command a SimpleVerbableItem.") self.assertEqual(message, "simple verb message result", "Wrong command result from SimpleVerbableItem") @patch('item.random') def test_simple_verbable_item_with_random_result(self, random): # https://stackoverflow.com/questions/26091330/how-to-validate-a-unit-test-with-random-values # Seed a patched random number generator my_random = Random(123) random.choice._mock_side_effect = my_random.choice item = self.factory.create_from_noun("simpleverbablerandom") (result, message) = item.do_verb("flobble") self.assertFalse(result, "Shouldn't be able to flobble a SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertTrue(result, "Should be able to command a SimpleVerbableItem.") # This is the order our seed guarantees: self.assertEqual(message, "message0", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message1", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message0", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message1", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message1", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message0", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message0", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message1", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message2", "Wrong command result from SimpleVerbableItem") (result, message) = item.do_verb("command") self.assertEqual(message, "message2", "Wrong command result from SimpleVerbableItem") def test_container_item(self): item = self.factory.create_from_noun("bag") self.assertTrue(item.has("shirt")) self.assertTrue(item.has("torch")) def test_stateful_container_item(self): item = self.factory.create_from_noun("cupboard") self.assertFalse(item.has("shirt")) self.assertFalse(item.has("torch")) item.do_verb("open") self.assertTrue(item.has("shirt")) self.assertTrue(item.has("torch")) def test_recursive_take(self): container = self.factory.create_from_noun("outercontainer") self.assertTrue(container.has("bag")) self.assertTrue(container.has("shirt")) self.assertTrue(container.has("torch")) self.assertIsNotNone(container.take("torch")) self.assertIsNotNone(container.take("shirt")) self.assertIsNotNone(container.take("bag")) def test_recursive_get_item_reference(self): container = self.factory.create_from_noun("outercontainer") bag = container.get_item_reference("bag") self.assertIsNotNone(bag, "Could not get bag from inside container") self.assertEqual(bag.id, "bag") shirt = container.get_item_reference("shirt") self.assertIsNotNone( shirt, "Could not get shirt from inside bag inside container") self.assertEqual(shirt.id, "shirt") torch = container.get_item_reference("torch") self.assertIsNotNone( torch, "Could not get torch from inside bag inside container") self.assertEqual(torch.id, "torch") def test_recursive_stateful_container(self): anotherbag = self.factory.create_from_noun("anotherbag") self.assertTrue(anotherbag.has("shirt")) def test_factory(self): item = self.factory.create_from_noun("torch") self.assertIsInstance(item, StatefulItem) self.assertEqual(item.name, "an Ever Ready torch") self.assertTrue(item.has_trait("moveable")) self.assertFalse(item.has_trait("wearable")) def test_stateful_item_rules(self): item = self.factory.create_from_noun("statefulitemwithrules") (result, message) = item.do_verb("turn off") self.assertFalse( result, "Turning off an item that's turned off shouldn't work.") (result, message) = item.do_verb("turn on", extras={"player_appearance_level": 99}) self.assertFalse( result, "Should not be able to turn item on with player appearance below 100" ) self.assertEqual(message, "Appearance rule condition not met.") (result, message) = item.do_verb("turn on", extras={"player_appearance_level": 100}) self.assertTrue( result, "Should be able to turn item on with player appearance of 100") self.assertEqual(message, "Turning on.") # As you were item.do_verb("turn off") # Should get an exception if we don't pass in the required extra. with self.assertRaisesRegex( Exception, "Item.*requires missing extra.*") as context: item.do_verb("turn on", extras={"nottherightextra": 123})