ex-oop-05-coffe-vending-mac.../CoffeeVendingMachines.Test/CoffeeVendingMachineTests.cs
github-classroom[bot] 2b1ce9b58f
Initial commit
2024-11-08 15:45:55 +00:00

308 lines
12 KiB
C#

using FluentAssertions;
using Xunit;
namespace CoffeeVendingMachines.Test;
public sealed class CoffeeVendingMachineTests
{
private const string Location = "Room 204a";
[Fact]
public void Construction_Default()
{
var machine = new CoffeeVendingMachine(Location);
machine.Location.Should()
.NotBeNullOrWhiteSpace()
.And.Be(Location);
machine.TotalMoneyCurrentlyInput
.Should().Be(0, "no coins have been inserted yet");
machine.TotalChangeAmountInMachine
.Should().Be(1155, "three pieces of each coin are the default set");
machine.AvailableProducts.Should()
.NotBeNullOrEmpty()
.And.HaveCount(3)
.And.BeEquivalentTo(new Product[]
{
new("Cappuccino", 85, 10),
new("Mocca", 100, 10),
new("Cacao", 60, 10)
}, "those three products are created by default if none are passed to the ctor");
}
[Fact]
public void Construction_Full()
{
Product[] products = GetDefaultProducts();
var machine = new CoffeeVendingMachine(GetDefaultCoinDepots(),
products, Location);
machine.Location.Should()
.NotBeNullOrWhiteSpace()
.And.Be(Location);
machine.TotalMoneyCurrentlyInput
.Should().Be(0, "no coins have been inserted yet");
machine.TotalChangeAmountInMachine
.Should().Be(1385, "sum of coin depot values");
machine.AvailableProducts.Should()
.NotBeNullOrEmpty()
.And.HaveCount(products.Length)
.And.BeEquivalentTo(products);
}
[Fact]
public void InsertCoin_Simple()
{
var machine = GetDefaultMachine();
machine.TotalMoneyCurrentlyInput.Should().Be(0);
machine.InsertCoin(CoinType.Cent20).Should().BeTrue();
machine.TotalMoneyCurrentlyInput.Should().Be(20);
}
[Fact]
public void InsertCoin_Multiple()
{
var machine = GetDefaultMachine();
machine.TotalMoneyCurrentlyInput.Should().Be(0);
machine.InsertCoin(CoinType.Cent20).Should().BeTrue();
machine.InsertCoin(CoinType.Cent50).Should().BeTrue();
machine.InsertCoin(CoinType.Cent50).Should().BeTrue();
machine.InsertCoin(CoinType.Euro02).Should().BeTrue();
machine.TotalMoneyCurrentlyInput.Should().Be(320, "20 + 2x50 + 200");
}
[Fact]
public void Cancel_Simple()
{
var machine = new CoffeeVendingMachine(Location);
Insert(CoinType.Cent10, 2);
Insert(CoinType.Cent20, 1);
Insert(CoinType.Cent50, 3);
Insert(CoinType.Euro01, 1);
machine.Cancel().Should().NotBeNull()
.And.HaveCount(4,
"only four kinds of coins have been inserted, the other two input depots were empty")
.And.BeEquivalentTo(new CoinDepot[]
{
new(CoinType.Cent10, 2),
new(CoinType.Cent20, 1),
new(CoinType.Cent50, 3),
new(CoinType.Euro01, 1)
});
return;
void Insert(CoinType coin, int times)
{
for (var i = 0; i < times; i++)
{
machine.InsertCoin(coin);
}
}
}
[Fact]
public void Cancel_Empty()
{
var machine = new CoffeeVendingMachine(Location);
machine.Cancel().Should().NotBeNull()
.And.BeEmpty("no coins have been inserted");
}
[Fact]
public void SelectProduct_Simple()
{
var machine = GetDefaultMachine();
machine.InsertCoin(CoinType.Euro01);
machine.SelectProduct("Coffee1", out CoinDepot[]? change, out int? losses)
.Should().BeTrue("enough money inserted, product exists and is in stock");
change.Should().NotBeNullOrEmpty("selected product less than money inserted, change returned")
.And.HaveCount(1, "change money returned in as few coins as possible and 10 cent coin available")
.And.BeEquivalentTo(new[] { new CoinDepot(CoinType.Cent10, 1) });
losses.Should().BeNull("change could be returned in total");
machine.TotalMoneyCurrentlyInput.Should().Be(0, "product bought, change returned");
machine.TotalChangeAmountInMachine.Should().Be(1475, "1385 + 100 - 10");
machine.AvailableProducts[2].NumberSold.Should().Be(1, "sale registered in product");
}
[Fact]
public void SelectProduct_ProductNotExists()
{
var machine = GetDefaultMachine();
machine.InsertCoin(CoinType.Euro02);
machine.SelectProduct("Potato Salad", out CoinDepot[]? change, out int? losses)
.Should().BeFalse("product does not exist");
change.Should().BeNull("no change return triggered");
losses.Should().BeNull("no change return triggered");
machine.TotalMoneyCurrentlyInput.Should().Be(200, "input unchanged");
machine.TotalChangeAmountInMachine.Should().Be(1385, "change money unchanged");
}
[Fact]
public void SelectProduct_NotEnoughMoney()
{
var machine = GetDefaultMachine();
machine.InsertCoin(CoinType.Cent50);
machine.SelectProduct("Milk", out CoinDepot[]? change, out int? losses)
.Should().BeFalse("product costs more than input");
change.Should().BeNull("no change return triggered");
losses.Should().BeNull("no change return triggered");
machine.TotalMoneyCurrentlyInput.Should().Be(50, "input unchanged");
machine.TotalChangeAmountInMachine.Should().Be(1385, "change money unchanged");
}
[Fact]
public void SelectProduct_ProductOutOfStock()
{
var machine = new CoffeeVendingMachine(GetDefaultCoinDepots(),
new Product[] { new("Soup", 80, 0) }, Location);
machine.InsertCoin(CoinType.Euro01);
machine.SelectProduct("Soup", out CoinDepot[]? change, out int? losses)
.Should().BeFalse("product is out of stock");
change.Should().BeNull("no change return triggered");
losses.Should().BeNull("no change return triggered");
machine.TotalMoneyCurrentlyInput.Should().Be(100, "input unchanged");
machine.TotalChangeAmountInMachine.Should().Be(1385, "change money unchanged");
}
[Fact]
public void SelectProduct_ProductGoingOutOfStock()
{
var machine = new CoffeeVendingMachine(GetDefaultCoinDepots(),
new Product[] { new("Soup", 80, 1) }, Location);
machine.InsertCoin(CoinType.Euro01);
machine.SelectProduct("Soup", out _, out _).Should().BeTrue();
machine.AvailableProducts.Should().BeEmpty("we had one product and that got sold");
}
[Fact]
public void SelectProduct_NotEnoughChange()
{
var machine = new CoffeeVendingMachine([
new CoinDepot(CoinType.Cent05),
new CoinDepot(CoinType.Cent10),
new CoinDepot(CoinType.Cent20),
new CoinDepot(CoinType.Cent50, 1),
new CoinDepot(CoinType.Euro01),
new CoinDepot(CoinType.Euro02)
],
GetDefaultProducts(), Location);
machine.InsertCoin(CoinType.Euro01);
machine.InsertCoin(CoinType.Euro02);
machine.SelectProduct("Soup", out CoinDepot[]? change, out int? losses)
.Should().BeTrue("product is in stock and customer inserted enough money");
change.Should()
.NotBeNull("customer entered more money than required so we return change")
.And.HaveCount(1, "we only have a single 50 cent coin")
.And.BeEquivalentTo(new[] { new CoinDepot(CoinType.Cent50, 1) });
losses.Should()
.NotBeNull("we are unable to return the full change of 70 cents")
.And.Be(20, "customer looses 20 cents which we are unable to return");
machine.TotalMoneyCurrentlyInput.Should().Be(0, "user input transferred to change depots");
machine.TotalChangeAmountInMachine.Should().Be(300,
"we were unable to return all the change but we kept all the input as future change money");
}
[Fact]
public void SelectProduct_InputAsChange()
{
var machine = new CoffeeVendingMachine(new CoinDepot[]
{
new(CoinType.Cent05),
new(CoinType.Cent10),
new(CoinType.Cent20),
new(CoinType.Cent50, 1),
new(CoinType.Euro01),
new(CoinType.Euro02)
},
GetDefaultProducts(), Location);
machine.InsertCoin(CoinType.Cent10);
machine.InsertCoin(CoinType.Cent05);
machine.InsertCoin(CoinType.Cent05);
machine.InsertCoin(CoinType.Cent20);
machine.InsertCoin(CoinType.Euro02);
machine.SelectProduct("Soup", out CoinDepot[]? change, out int? losses)
.Should().BeTrue("product is in stock and customer inserted enough money");
change.Should()
.NotBeNull("customer entered more money than required so we return change")
.And.HaveCount(1, "we return a 10 cent coin")
.And.BeEquivalentTo(new CoinDepot[]
{
new(CoinType.Cent10, 1)
});
losses.Should()
.BeNull("we are able to return the full change of 10 cents");
machine.TotalMoneyCurrentlyInput.Should().Be(0, "user input transferred to change depots");
machine.TotalChangeAmountInMachine.Should().Be(280,
"we used some of the input as change, but we kept the rest as future change money");
}
[Fact]
public void StringRepresentation_Simple()
{
var machine = GetDefaultMachine();
machine.InsertCoin(CoinType.Cent50);
machine.InsertCoin(CoinType.Cent20);
machine.InsertCoin(CoinType.Cent20);
machine.InsertCoin(CoinType.Cent20);
machine.SelectProduct("Cacao", out _, out _);
machine.ToString().Should()
.NotBeNullOrWhiteSpace()
.And.Be("""
|=======================================|
|Machine located at: Room 204a |
|=======================================|
|Cent05 x5 |
|Cent10 x9 |
|Cent20 x11 |
|Cent50 x7 |
|Euro01 x4 |
|Euro02 x2 |
|=======================================|
|Milk 0,75 [4 in stock | 0 sold]|
|Soup 2,30 [2 in stock | 0 sold]|
|Coffee1 0,90 [8 in stock | 0 sold]|
|Coffee2 0,85 [8 in stock | 0 sold]|
|Cacao 1,00 [4 in stock | 1 sold]|
|=======================================|
""");
}
private static CoffeeVendingMachine GetDefaultMachine() =>
new(GetDefaultCoinDepots(),
GetDefaultProducts(), Location);
private static Product[] GetDefaultProducts() =>
[
new("Milk", 75, 4),
new("Soup", 230, 2),
new("Coffee1", 90, 8),
new("Coffee2", 85, 8),
new("Cacao", 100, 5)
];
private static CoinDepot[] GetDefaultCoinDepots() =>
[
new(CoinType.Cent05, 05),
new(CoinType.Cent10, 10),
new(CoinType.Cent20, 08),
new(CoinType.Cent50, 06),
new(CoinType.Euro01, 04),
new(CoinType.Euro02, 02)
];
}