class TestBuyInfiniteStock(IFPTestCase):
    def setUp(self):
        super().setUp()
        self.sale_item = Thing(self.game, "widget")
        self.actor = Actor(self.game, "Dmitri")
        self.currency = Thing(self.game, "penny")
        self.me.addThing(self.currency)
        self.actor.addSelling(self.sale_item, self.currency, 1, True)
        self.start_room.addThing(self.actor)
        self.sale_item.makeKnown(self.me)

    def test_buy(self):
        stock_before = self.actor.for_sale[self.sale_item.ix].number

        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        expected = f"(Received: {self.sale_item.verbose_name}) "
        self.assertEqual(msg, expected,
                         "Unexpected msg after attempting to buy item")

        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item. Received success message. ",
        )

        stock_after = self.actor.for_sale[self.sale_item.ix].number

        self.assertIs(
            stock_before,
            stock_after,
            "Stock of infinite item should not have changed after buying",
        )
class TestBuyNotEnoughMoney(IFPTestCase):
    def setUp(self):
        super().setUp()
        self.sale_item = Thing(self.game, "widget")
        self.actor = Actor(self.game, "Dmitri")
        self.currency = Thing(self.game, "penny")
        self.me.addThing(self.currency)
        self.actor.addSelling(self.sale_item, self.currency, 2, 1)
        self.start_room.addThing(self.actor)
        self.sale_item.makeKnown(self.me)

    def test_buy(self):
        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        BASE_FAILURE_MSG = "You don't have enough"
        self.assertIn(
            BASE_FAILURE_MSG,
            msg,
            "Unexpected message after attempting to buy item with insufficient funds",
        )

        self.assertItemNotIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item with insufficient money.",
        )
class TestBuyPerson(IFPTestCase):
    def setUp(self):
        super().setUp()
        self.sale_item = Actor(self.game, "kate")
        self.actor = Actor(self.game, "dmitri")
        self.currency = Thing(self.game, "penny")
        self.me.addThing(self.currency)
        self.actor.addSelling(self.sale_item, self.currency, 2, 1)
        self.start_room.addThing(self.actor)
        self.sale_item.makeKnown(self.me)

    def test_buy(self):
        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        FAILURE_MSG = "You cannot buy or sell a person. "
        self.assertEqual(
            FAILURE_MSG, msg,
            "Unexpected message after attempting to buy an Actor")

        self.assertItemNotIn(self.sale_item, self.me.contains,
                             "Attempted to buy an Actor.")
class TestBuyFiniteStock(IFPTestCase):
    def setUp(self):
        super().setUp()
        self.sale_item = Thing(self.game, "widget")
        self.actor = Actor(self.game, "Dmitri")
        self.currency = Thing(self.game, "penny")
        self.me.addThing(self.currency)
        self.actor.addSelling(self.sale_item, self.currency, 1, 1)
        self.start_room.addThing(self.actor)
        self.sale_item.makeKnown(self.me)

        self.OUT_STOCK_MSG = "That item is out of stock. "

    def test_buy(self):
        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        expected = f"(Received: {self.sale_item.verbose_name}) "
        self.assertEqual(msg, expected,
                         "Unexpected msg after attempting to buy item")

        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item. Received success message. ",
        )

        self.game.turnMain(f"buy {self.sale_item.verbose_name}")
        msg = self.app.print_stack.pop()

        self.assertEqual(
            msg,
            self.OUT_STOCK_MSG,
            "Tried to buy item which should be out of stock. Received unexpected msg",
        )
        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy out of stock item. Number in inventory should not have "
            "changed. ",
        )

    def test_buy_from(self):
        BuyFromVerb()._runVerbFuncAndEvents(self.game, self.sale_item,
                                            self.actor)

        msg = self.app.print_stack.pop()
        expected = f"(Received: {self.sale_item.verbose_name}) "
        self.assertEqual(msg, expected,
                         "Unexpected msg after attempting to buy item")

        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item. Received success message. ",
        )

        BuyFromVerb()._runVerbFuncAndEvents(self.game, self.sale_item,
                                            self.actor)
        msg = self.app.print_stack.pop()

        self.assertEqual(
            msg,
            self.OUT_STOCK_MSG,
            "Tried to buy item which should be out of stock. Received unexpected msg",
        )
        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy out of stock item. Number in inventory should not have "
            "changed. ",
        )
class TestBuyInRoomWithMultipleActors(IFPTestCase):
    def setUp(self):
        super().setUp()
        self.sale_item = Thing(self.game, "bulb")
        self.actor1 = Actor(self.game, "Dmitri")
        self.actor2 = Actor(self.game, "Kate")
        self.currency = Thing(self.game, "penny")
        self.me.addThing(self.currency)
        self.actor1.addSelling(self.sale_item, self.currency, 1, 1)
        self.start_room.addThing(self.actor1)
        self.start_room.addThing(self.actor2)
        self.sale_item.makeKnown(self.me)

    def test_buy(self):
        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        BASE_DISAMBIG_MSG = "Would you like to buy from"
        self.assertIn(
            BASE_DISAMBIG_MSG,
            msg,
            "Unexpected message after attempting to buy from ambiguous Actor",
        )

        self.assertItemNotIn(self.sale_item, self.me.contains,
                             "Attempted to buy from ambiguous Actor.")

    def test_buy_with_lastTurn_dobj_actor(self):
        self.game.parser.command.dobj = GrammarObject(target=self.actor1)

        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        expected = f"(Received: {self.sale_item.verbose_name}) "
        self.assertEqual(
            msg,
            expected,
            "Unexpected msg after attempting to buy from ambigous Actor",
        )

        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item. Received success message. ",
        )

    def test_buy_with_lastTurn_iobj_actor(self):
        self.game.parser.command.iobj = GrammarObject(target=self.actor1)

        self.game.turnMain(f"buy {self.sale_item.verbose_name}")

        msg = self.app.print_stack.pop()
        expected = f"(Received: {self.sale_item.verbose_name}) "
        self.assertEqual(
            msg, expected,
            "Unexpected msg after attempting to buy from ambigous Actor")

        self.assertItemExactlyOnceIn(
            self.sale_item,
            self.me.contains,
            "Attempted to buy item. Received success message. ",
        )