def test_specific_valid_position_logs_one_success(self, machine: VendingMachine, caplog): """ Ensures that only one message gets logged """ machine.view_items(1, 1) self.logs_one_message(caplog)
def test_view_all_items(self, machine: VendingMachine, caplog): """ Test ensures that the number of items returned to the user is len(items) - 1 (one initial success message) """ machine.view_items() assert len(caplog.records) == len(machine.items)
def test_deposit_always_logs_a_message(self, deposit: Decimal, caplog): deposit = money.to_money(deposit) machine = VendingMachine() machine.deposit(deposit) self.logs_one_message(caplog) # Resetting the log capturing utility because hypothesis won't reset it caplog.clear()
def test_incorrect_position_doesnt_add_purchase( self, loaded_machine: VendingMachine): """ Test case to ensure that if the position is invalid, a purchase doesn't get added to the purchase log. """ loaded_machine.purchase_item("ABC123") assert len(loaded_machine.purchases) == 0
def test_insufficient_funds_doesnt_add_purchase(self, machine: VendingMachine): """ Test case should ensure that if the user didn't have funds to complete the purchase, a purchase isn't added to the log """ machine.purchase_item("A1") assert len(machine.purchases) == 0
def test_deposit_0_or_less_logs_error_to_user(self, caplog): deposit = money.to_money(Decimal("-5")) machine = VendingMachine() machine.deposit(deposit) self.logs_one_message(caplog) assert "ERROR" in caplog.text assert "negative or 0" in caplog.text
def test_unfunded_logs_success(self, machine: VendingMachine, caplog): """ Tests to make sure that the success message still displays, even with 0 balance """ machine.dispense_change() self.logs_one_message(caplog) assert "SUCCESS" in caplog.text assert "Dispensed" in caplog.text
def test_purchased_stock_decrements(self, loaded_machine: VendingMachine): """ Mostly already captured by tests on the item, but ensuring that the item purchased decrements its stock """ previous_stock = loaded_machine.items["A1"].remaining_stock loaded_machine.purchase_item("A1") current_stock = loaded_machine.items["A1"].remaining_stock assert current_stock == (previous_stock - 1)
def test_deposit_money_logs_success_to_user(self, caplog): deposit = money.to_money(Decimal("30")) machine = VendingMachine() machine.deposit(deposit) self.logs_one_message(caplog) assert "SUCCESS" in caplog.text assert "Successfully deposited" in caplog.text
def test_view_purchases_logs_header_message(self, machine: VendingMachine, caplog): """ Test case should ensure that a header message gets emitted, regardless of whether there were purchases or not. """ machine.view_purchases() self.logs_one_message(caplog) assert "You've spent 0 on 0 items." in caplog.text assert "You bought" not in caplog.text
def test_successful_purchase_gets_logged_as_success( self, loaded_machine: VendingMachine, caplog): """ Test case should ensure that if everything goes well, the user sees a success message """ loaded_machine.purchase_item("A1") self.logs_one_message(caplog) assert "SUCCESS" in caplog.text assert "Purchased" in caplog.text assert "Enjoy!" in caplog.text
def test_funded_logs_success_with_funded_amount( self, loaded_machine: VendingMachine, caplog): """ Tests to make sure that the success message has the balance in it """ balance = loaded_machine.balance loaded_machine.dispense_change() self.logs_one_message(caplog) assert str(balance) in caplog.text assert "SUCCESS" in caplog.text assert "Dispensed" in caplog.text
def test_invalid_position_logs_error(self, machine: VendingMachine, caplog): """ Makes sure that if the user types in an invalid position, an error message shows """ machine.view_items(column=22, row=100) self.logs_one_message(caplog) assert "ERROR" in caplog.text assert "isn't a slot" in caplog.text
def test_out_of_stock_doesnt_add_purchase(self, loaded_machine: VendingMachine): """ Test case to ensure that if there isn't any stock left of an item, a purchase doesn't get added to the purchase log. """ loaded_machine.items["A1"].remaining_stock = 0 loaded_machine.purchase_item("A1") assert len(loaded_machine.purchases) == 0
def test_insufficient_funds_gets_logged_as_error(self, machine: VendingMachine, caplog): """ Test case should ensure that if the user hasn't loaded enough money into the machine that the attempt to purchase an item will fail. """ machine.purchase_item("A1") self.logs_one_message(caplog) assert "ERROR" in caplog.text assert "Insufficient funds" in caplog.text
def test_resets_balance(self, machine: VendingMachine, deposit: Decimal): """ Test case to ensure that no leftover balance is retained after someone requests their change, regardless of size of previous deposits """ machine.deposit(deposit) machine.deposit(deposit) change = machine.dispense_change() assert change == money.add(deposit, deposit) assert machine.balance == Decimal(0)
def test_purchased_decreases_balance(self, loaded_machine: VendingMachine): """ Test case ensures that the balance on the machine gets correctly updated according to the price of the item purchased """ current_balance = loaded_machine.balance price_of_item = loaded_machine.items["A1"].price expected_balance = current_balance - price_of_item loaded_machine.purchase_item("A1") assert loaded_machine.balance == expected_balance
def test_successful_purchase_gets_added_to_purchase_log( self, loaded_machine: VendingMachine): """ Ensures the purchase gets appended to the log """ position = "A1" price = loaded_machine.items[position].price loaded_machine.purchase_item(position) assert len(loaded_machine.purchases) == 1 purchase = loaded_machine.purchases[0] assert purchase.position == position assert purchase.price == price
def test_incorrect_position_gets_logged_as_error( self, loaded_machine: VendingMachine, caplog): """ Test case should ensure that entering a position on the machine that doesn't exist should log an error back to the console. For example, A1 should exist, while ABC123 shouldn't """ loaded_machine.purchase_item("ABC123") self.logs_one_message(caplog) assert "ERROR" in caplog.text assert "no item located" in caplog.text assert "Please try again!" in caplog.text
def test_deposit_money_accepts_positive_amounts(self, deposit: Decimal): """ Test case ensures that any positive amount rounded to the nearest cent can be accepted by the vending machine. """ deposit = money.to_money(deposit) machine = VendingMachine() machine.deposit(deposit) machine.deposit(deposit) assert machine.balance == money.add(deposit, deposit)
def test_view_purchases_log(self, loaded_machine: VendingMachine, caplog): """ Test case ensures that the correct number of messages get logged. """ loaded_machine.purchase_item("A1") loaded_machine.purchase_item("A1") # Clearing messages emitted by purchasing the item caplog.clear() loaded_machine.view_purchases() assert len(caplog.records) == 3 assert "You bought" in caplog.text
def test_out_of_stock_gets_logged_as_error(self, loaded_machine: VendingMachine, caplog): """ Test case should ensure error messages from out of stock are getting logged to the user correctly. """ loaded_machine.items["A1"].remaining_stock = 0 loaded_machine.purchase_item("A1") self.logs_one_message(caplog) assert "ERROR" in caplog.text assert "Out of stock!" in caplog.text
def start(): """ Initiates the state of the vending machine. If there's an existing vending machine, and start is called again, the existing state is not touched. """ if os.path.isfile(STATE_FILE_LOCATION): fancy_print( LOG_HELP, "An existing vending machine exists. Proceeding with that.") return None machine = VendingMachine() with open(STATE_FILE_LOCATION, "w") as file: json.dump(machine.to_json(), file) fancy_print(LOG_SUCCESS, "Vending machine created.") return None
def test_to_and_from_json_inverse(loaded_machine): """ Test case to ensure the machine is json serializable and will load to its previous state if reloaded immediately. """ dumped = loaded_machine.to_json() loaded = VendingMachine.from_json(dumped) assert loaded == loaded_machine
def test_fill_machine_assigns_correct_stock(stock: int): """ Test case should ensure the param given to constructor successfully passes through to all generated vending machine items. """ machine = VendingMachine(stock=stock) for item in machine.items.values(): assert item.remaining_stock == stock
def test_fill_machine_stops_filling_after_number_out_of_items(): """ Test case ensures that if too many items are specified, the program will just utlize all of them instead of crashing and burning. """ num_items = len(VendingMachine.vending_machine_items) machine = VendingMachine(stock=num_items + 1) assert len(machine.items.keys()) == num_items
def view_purchases(): """ Views all purchases. If no machine exists, error is thrown. """ if not os.path.isfile(STATE_FILE_LOCATION): fancy_print(LOG_ERROR, "Please initialize the vending machine first.") return None with open(STATE_FILE_LOCATION) as file: loaded = json.load(file) machine = VendingMachine.from_json(loaded) machine.view_purchases() return None
def view_balance(): """ Views the current balance you have in the machine. If no machine exists, error is thrown. """ if not os.path.isfile(STATE_FILE_LOCATION): fancy_print(LOG_ERROR, "Please initialize the vending machine first.") return None with open(STATE_FILE_LOCATION) as file: loaded = json.load(file) machine = VendingMachine.from_json(loaded) fancy_print(LOG_SUCCESS, f"Your current balance is {machine.balance}.") return None
def view_items(column: str = None, row: int = None, position: str = None): """ Viewing what items are in the machine. Filters are additive. """ if not os.path.isfile(STATE_FILE_LOCATION): fancy_print(LOG_ERROR, "Please initialize the vending machine first.") return None with open(STATE_FILE_LOCATION) as file: loaded = json.load(file) machine = VendingMachine.from_json(loaded) if position: machine.view_items(position[0], position[1]) else: machine.view_items(column, row) return None
def dispense_change(): """ Removing the money from the existing vending machine. If no machine exists, error is thrown. """ if not os.path.isfile(STATE_FILE_LOCATION): fancy_print(LOG_ERROR, "Please initialize the vending machine first.") return None with open(STATE_FILE_LOCATION) as file: loaded = json.load(file) machine = VendingMachine.from_json(loaded) machine.dispense_change() with open(STATE_FILE_LOCATION, "w") as file: json.dump(machine.to_json(), file) return None