class TestVendingMachine:
    def setUp(self):
        self.vending_machine = VendingMachine()
        self.vending_machine.reset()

    def test_release_change_when_no_payment_expects_0_change(self):
        # Arrange

        # Act
        result = self.vending_machine.release_change()

        # Assert
        assert_equals(0, result)

    def test_release_change_with_payment_expects_change_returned(self):
        # Arrange
        self.vending_machine.insert_coin(1)

        # Act
        result = self.vending_machine.release_change()

        # Assert
        assert_greater(result, 0)

    @unittest.skip("buy_product now returns an exception")
    def test_buy_product_with_no_payment_expects_nothing(self):
        # Arrange

        # Act
        result = self.vending_machine.buy_product()

        # Assert
        assert_is_none(result)

    def test_buy_product_with_payment_expects_product(self):
        # Arrange
        self.vending_machine.insert_coin(1)

        # Act
        result = self.vending_machine.buy_product()

        # Assert
        assert_is_not_none(result)

    @raises(RuntimeError)
    def test_buy_product_with_no_payment_expects_exception(self):
        # Arrange

        # Act
        result = self.vending_machine.buy_product()

        # Assert

    @raises(RuntimeError)
    def test_buy_multiple_products_with_no_additional_payment(self):
        # Arrange

        # Act
        self.vending_machine.insert_coin(1)
        self.vending_machine.buy_product()
        self.vending_machine.buy_product()
class TestVendingMachine(unittest.TestCase):
    """Tests for vending machine"""
    def setUp(self):
        self.vending_machine = VendingMachine()

    def test_vending_machine_insert_quarters(self):
        """should accept valid coins"""
        self.vending_machine.insert_coin(25)

        self.assertEqual(self.vending_machine.display(), "Current Amount: 25")

    def test_vending_machine_accepts_dimes(self):
        """should accept valid coins"""
        self.vending_machine.insert_coin(10)

        self.assertEqual(self.vending_machine.display(), "Current Amount: 10")

    def test_vending_machine_accepts_nickels(self):
        """should accept valid coins"""
        self.vending_machine.insert_coin(5)

        self.assertEqual(self.vending_machine.display(), "Current Amount: 5")

    def test_vending_machine_rejects_pennies_and_returns_them(self):
        """should reject and put pennies in coin return"""

        self.vending_machine.insert_coin(1)

        self.assertEqual(self.vending_machine.display(), "INSERT COINS")
        self.assertEqual(self.vending_machine.coin_return, 1)

    def test_vending_machine_updates_display_when_valid_coin_accepted(self):
        """should update display when received valid coin"""
        self.vending_machine.insert_coin(25)

        self.assertEqual(self.vending_machine.display(), "Current Amount: 25")

    def test_vending_machine_displays_insert_coin_when_no_coins_inserted(self):
        """should display 'INSERT COIN'"""
        self.assertEqual(self.vending_machine.display(), "INSERT COINS")

    def test_product_is_dispensed_if_enough_money_is_received(self):
        """should dispense product if sufficient funds have been received"""
        for i in range(4):
            self.vending_machine.insert_coin(25)

        self.assertEqual(self.vending_machine.select_product("cola"), "cola")
        self.assertEqual(self.vending_machine.display(), "THANK YOU")

        self.assertEqual(self.vending_machine.display(), "INSERT COINS")
        self.assertEqual(self.vending_machine.current_amount(), 0)

    def test_machine_displays_price_if_insufficient_funds(self):
        """should display price of item if not enough funds have been received"""
        self.vending_machine.select_product("cola")

        self.assertEqual(self.vending_machine.display(), "PRICE: 100")
        self.assertEqual(self.vending_machine.display(), "INSERT COINS")

    def test_product_is_dispensed_and_money_is_returned_if_money_left_over(self):
        """should dispense products and give back any extra money"""
        for i in range(4):
            self.vending_machine.insert_coin(25)

        self.assertEqual(self.vending_machine.select_product("chips"), "chips")

        self.assertEqual(self.vending_machine.return_coins(), [Coin(5.670, 24.26, 1.75, 25), Coin(5.670, 24.26, 1.75, 25)])

    def test_refund_coins(self):
        """should return all coins"""
        self.vending_machine.insert_coin(25)
        self.assertEqual(self.vending_machine.return_coins(), [Coin(5.670, 24.26, 1.75, 25)])

        self.assertEqual(self.vending_machine.display(), "INSERT COINS")

    def test_machine_displays_sold_out_if_item_is_out_of_stock(self):
        """should display sold out if item is out of stock. Will display money left over"""

        for i in range(8):
            self.vending_machine.insert_coin(25)

        for i in range(2):
            self.vending_machine.select_product("cola")

        self.assertEqual(self.vending_machine.display(), "SOLD OUT")
        self.assertEqual(self.vending_machine.display(), "Current Amount: 100")

    # def test_machine_displays_exact_change_only_when_not_able_to_make_change(self):
    #     """vending machine displays exact change if not able to make change"""
    #     self.vending_machine.change['nickels'] = 1
    #
    #     for i in range(3):
    #         self.vending_machine.accept_coins(25)
    #
    #     self.vending_machine.select_product("candy")
    #
    #     self.assertEqual(self.vending_machine.display(), "EXACT CHANGE ONLY")
    #
    def test_machine_should_update_adding_of_coins(self):
        """update coin quantity"""
        self.vending_machine.insert_coin(25)

        self.assertEqual(self.vending_machine.change['quarters']['quantity'], 6)