diff --git a/src/main/java/com/booleanuk/core/Bagel.java b/src/main/java/com/booleanuk/core/Bagel.java new file mode 100644 index 000000000..f76866fb9 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Bagel.java @@ -0,0 +1,47 @@ +package com.booleanuk.core; + +import java.util.ArrayList; + +public class Bagel implements Product { + private final Triple bagelType; + private final ArrayList> fillings; + + public Bagel(Triple bagelType, Triple fillingType) { + this.bagelType = bagelType; + this.fillings = new ArrayList<>(); + this.fillings.add(fillingType); + } + + public Bagel(Triple bagelType, ArrayList> fillings) { + this.bagelType = bagelType; + this.fillings = new ArrayList<>(); + this.fillings.addAll(fillings); + } + + @Override + public float calculateCost() { + return bagelType.c() + (float) fillings.stream().mapToDouble(Triple::c).sum(); + } + + public float calculateBreadCost() { + return bagelType.c(); + } + + public ArrayList> getFillings() { + return new ArrayList<>(fillings); + } + + public Triple getBagelType() { + return bagelType; + } + + @Override + public float basicPrice() { + return bagelType.c(); + } + + @Override + public String name() { + return bagelType.b() + " " + bagelType.a(); + } +} diff --git a/src/main/java/com/booleanuk/core/Basket.java b/src/main/java/com/booleanuk/core/Basket.java new file mode 100644 index 000000000..b5115f770 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Basket.java @@ -0,0 +1,228 @@ +package com.booleanuk.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.NoSuchElementException; + +public class Basket { + private final ArrayList products; + private ArrayList unDiscountedProducts; + private int basketSize; + + public Basket(int basketSize) { + products = new ArrayList<>(); + unDiscountedProducts = new ArrayList<>(); + this.basketSize = basketSize; + } + + public int size() { + return products.size(); + } + + public void addProduct(Product product) { + if (products.size() < basketSize) { + products.add(product); + unDiscountedProducts.add(product); + } + } + + public float findDiscount() { + ArrayList bagels = new ArrayList<>(); + for (Product p: unDiscountedProducts) { + if (p instanceof Bagel) { + bagels.add(p); + } + } + // Sort and compare bread cost + bagels.sort((o1, o2) -> (int) (1000 * (((Bagel) o2).calculateBreadCost() - ((Bagel) o1).calculateBreadCost()))); + if (bagels.size() >= 12) { + return calculateDiscount(bagels, 12, 3.99f) + findDiscount(); + } else if (bagels.size() >= 6) { + return calculateDiscount(bagels, 6, 2.49f) + findDiscount(); + } else if (bagels.size() < unDiscountedProducts.size()) { + // Sort so Bagels are first, coffee after. After sort by cost, but coffee is sorted inversely. + unDiscountedProducts.sort((o1, o2) -> switch (o1) { + case Bagel bagel when o2 instanceof Bagel -> + (int) (1000 * (((Bagel) o2).calculateBreadCost() - bagel.calculateBreadCost())); + case Coffee ignored when o2 instanceof Coffee -> + (int) (1000 * (o1.calculateCost() - o2.calculateCost())); + case Bagel ignored -> -1; + case null, default -> 1; + }); + + + int coffeeSize = products.size() - bagels.size(); + int coffeeBagelDeals = Math.min(bagels.size(), coffeeSize); + float sumCost = 0.0f; + for (int i = 0; i < coffeeBagelDeals; i++) { + sumCost += unDiscountedProducts.get(unDiscountedProducts.size() - 1 - i).calculateCost() + ((Bagel) bagels.get(i)).calculateBreadCost(); + } + return sumCost - 1.25f * coffeeBagelDeals; + } + return 0; + } + + private float calculateDiscount(ArrayList items, int num, float dis) { + float sumBreadCost = 0.0f; + for (int i = 0; i < num; i++) { + sumBreadCost += ((Bagel)items.get(i)).calculateBreadCost(); + unDiscountedProducts.remove(items.get(i)); + } + return sumBreadCost - dis; + } + + public void removeProduct(Product product) { + if (!products.contains(product)) { + throw new NoSuchElementException("No such product exists"); + } + products.remove(product); + } + + public ArrayList getProducts() { + return new ArrayList<>(products); + } + + public void setBasketSize(int basketSize) { + if (basketSize < products.size()) { + products.clear(); + } + this.basketSize = basketSize; + } + + public float calculateCost() { + float sum = 0.0f; + for (Product p: products) { + sum += p.calculateCost(); + } + float discount = findDiscount(); + sum -= discount; + unDiscountedProducts = new ArrayList<>(products); + return sum; + } + + record ReceiptInfo(HashMap fillings, + ArrayList, Float, Float>> deals, ArrayList remaining) { + } + + public ReceiptInfo receiptInformation() { + HashMap fillings = new HashMap<>(); // to display later + ArrayList, Float, Float>> deals = new ArrayList<>(); // T< HM , price, discount>> + ArrayList remaining = new ArrayList<>(); + + + + unDiscountedProducts = new ArrayList<>(products); + ArrayList bagels = new ArrayList<>(); + for (Product p: unDiscountedProducts) { + if (p instanceof Bagel) { + for (Triple t: ((Bagel) p).getFillings()) { + if (fillings.containsKey(t.b())) { + fillings.replace(t.b(), fillings.get(t.b()) + 1); + } else { + fillings.put(t.b(), 1); + } + } + bagels.add(p); + } + } + + bagels.sort((o1, o2) -> (int) (1000 * (((Bagel) o2).calculateBreadCost() - ((Bagel) o1).calculateBreadCost()))); + + boolean keepRunning = true; + while (keepRunning) { + if (bagels.size() >= 12) { + HashMap breadKinds = new HashMap<>(); + float breadCost = 3.99f; + for (int i = 0; i < 12; i++) { + String bagelType = bagels.get(i).name(); + if (breadKinds.containsKey(bagelType)) { + breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1); + } else { + breadKinds.put(bagelType, 1); + } + } + float discount = calculateDiscount(bagels, 12, 3.99f); + deals.add(new Triple<>(breadKinds, breadCost, -discount)); + for (int i = 0; i < 12; i++) { + bagels.removeFirst(); + } + } else if (bagels.size() >= 6) { + HashMap breadKinds = new HashMap<>(); + float breadCost = 2.49f; + for (int i = 0; i < 6; i++) { + String bagelType = bagels.get(i).name(); + if (breadKinds.containsKey(bagelType)) { + breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1); + } else { + breadKinds.put(bagelType, 1); + } + } + float discount = calculateDiscount(bagels, 6, 2.49f); + deals.add(new Triple<>(breadKinds, breadCost, -discount)); + for (int i = 0; i < 6; i++) { + bagels.removeFirst(); + } + } else if (bagels.size() < unDiscountedProducts.size()) { + // Sort so Bagels are first, after that, sort by cost. + unDiscountedProducts.sort((o1, o2) -> switch (o1) { + case Bagel bagel when o2 instanceof Bagel -> + (int) (1000 * (((Bagel) o2).calculateBreadCost() - bagel.calculateBreadCost())); + case Coffee ignored when o2 instanceof Coffee -> + (int) (1000 * (o2.calculateCost() - o1.calculateCost())); + case Bagel ignored -> -1; + case null, default -> 1; + }); + + + HashMap breadKinds = new HashMap<>(); + HashMap coffeeType = new HashMap<>(); + ArrayList coffeeList = new ArrayList<>(); + + for (Product p: unDiscountedProducts) { + if (p instanceof Coffee) { + coffeeList.add(p); + } + } + + int coffeeBagelDeals = Math.min(bagels.size(), coffeeList.size()); + for (int i = 0; i < coffeeBagelDeals; i++) { + String bagelType = bagels.get(i).name(); + if (breadKinds.containsKey(bagelType)) { + breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1); + } else { + breadKinds.put(bagelType, 1); + } + + String coffeeString = coffeeList.get(i).name(); + if (coffeeType.containsKey(coffeeString)) { + coffeeType.replace(coffeeString, coffeeType.get(coffeeString) + 1); + } else { + coffeeType.put(coffeeString, 1); + } + } + + for (int i = 0; i < coffeeBagelDeals; i++) { + HashMap dealContents = new HashMap<>(); + dealContents.put(coffeeList.get(i).name(), 1); + dealContents.put(unDiscountedProducts.getFirst().name(), 1); + float coffeeCost = ((Coffee) coffeeList.get(i)).getCoffeeType().c(); + float bagelCost = ((Bagel) unDiscountedProducts.getFirst()).getBagelType().c(); + float dis = 1.25f - coffeeCost - bagelCost; + deals.add(new Triple<>(dealContents, 1.25f, dis)); + unDiscountedProducts.removeFirst(); + unDiscountedProducts.remove(coffeeList.get(i)); + } + } else { + remaining.addAll(unDiscountedProducts); + keepRunning = false; + } + } + + return new ReceiptInfo(fillings, deals, remaining); + } + + public void clear() { + products.clear(); + unDiscountedProducts.clear(); + } +} diff --git a/src/main/java/com/booleanuk/core/Coffee.java b/src/main/java/com/booleanuk/core/Coffee.java new file mode 100644 index 000000000..017d6c85d --- /dev/null +++ b/src/main/java/com/booleanuk/core/Coffee.java @@ -0,0 +1,28 @@ +package com.booleanuk.core; + +public class Coffee implements Product{ + private final Triple coffeeType; + + public Coffee(Triple coffeeType) { + this.coffeeType = coffeeType; + } + + @Override + public float calculateCost() { + return coffeeType.c(); + } + + public Triple getCoffeeType() { + return coffeeType; + } + + @Override + public String name() { + return coffeeType.b(); + } + + @Override + public float basicPrice() { + return coffeeType.c(); + } +} diff --git a/src/main/java/com/booleanuk/core/Controller.java b/src/main/java/com/booleanuk/core/Controller.java new file mode 100644 index 000000000..6fb6f04a2 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Controller.java @@ -0,0 +1,114 @@ +package com.booleanuk.core; + +import java.util.*; + +public class Controller { + private final View view; + private static final HashMap> privatePrices = new HashMap<>() {{ + put("BGLO", new Triple<>("Bagel", "Onion", 0.49f)); + put("BGLP", new Triple<>("Bagel", "Plain", 0.39f)); + put("BGLE", new Triple<>("Bagel", "Everything", 0.49f)); + put("BGLS", new Triple<>("Bagel", "Sesame", 0.49f)); + put("FILB", new Triple<>("Filling", "Bacon", 0.12f)); + put("FILE", new Triple<>("Filling", "Egg", 0.12f)); + put("FILC", new Triple<>("Filling", "Cheese", 0.12f)); + put("FILX", new Triple<>("Filling", "Cream Cheese", 0.12f)); + put("FILS", new Triple<>("Filling", "Smoked Salmon", 0.12f)); + put("FILH", new Triple<>("Filling", "Ham", 0.12f)); + put("COFB", new Triple<>("Coffee", "Black", 0.99f)); + put("COFW", new Triple<>("Coffee", "White", 1.19f)); + put("COFC", new Triple<>("Coffee", "Cappuccino", 1.29f)); + put("COFL", new Triple<>("Coffee", "Latte", 1.29f)); + }}; + public static final Map> prices = Collections.unmodifiableMap(privatePrices); + private Basket basket; + private int basketSize; + + public Controller(View view, Basket basket, int basketSize) { + this.view = view; + this.basket = basket; + this.basketSize = basketSize; + } + + public static void main(String[] args) { + int bSize = 50; + Controller controller = new Controller(new View(), new Basket(bSize), bSize); + + controller.start(); + } + + private void start() { + boolean keepRunning = true; + while(keepRunning) { + int chosenOption = view.mainMenu(); + switch (chosenOption) { + case 1: + if (basket.size() < basketSize) { + Bagel b = view.addBagel(); + if (b != null) { + basket.addProduct(b); + } + } else { + view.basketFull(); + } + break; + case 2: + if(basket.size() > 0) { + basket.removeProduct(view.chooseBagel(basket.getProducts())); + } else { + view.emptyBasket(); + } + break; + case 3: + basket.setBasketSize(view.getNewBasketSize()); + break; + case 4: + view.printPrice(basket.calculateCost()); + break; + case 5: + if (basket.size() < basketSize) { + Coffee c = view.addCoffee(); + if (c != null) { + basket.addProduct(c); + } + } else { + view.basketFull(); + } + break; + case 6: + view.printReceipt(basket.calculateCost(), basket.findDiscount(), basket.receiptInformation()); + basket.clear(); + keepRunning = false; + view.printExit(); + break; + case 12: + ArrayList> ingredients = new ArrayList<>(); + ingredients.add(Controller.prices.get("FILB")); + for (int i = 0; i < 4; i++) { + basket.addProduct(new Bagel(Controller.prices.get("BGLO"), ingredients)); + } + ingredients.add(Controller.prices.get("FILC")); + for (int i = 0; i < 4; i++) { + basket.addProduct(new Bagel(Controller.prices.get("BGLE"), ingredients)); + } + ingredients.add(Controller.prices.get("FILX")); + for (int i = 0; i < 4; i++) { + basket.addProduct(new Bagel(Controller.prices.get("BGLS"), ingredients)); + } + ingredients.add(Controller.prices.get("FILS")); + for (int i = 0; i < 4; i++) { + basket.addProduct(new Bagel(Controller.prices.get("BGLP"), ingredients)); + } + System.out.println("16 bagels added!"); + basket.addProduct(new Coffee(Controller.prices.get("COFC"))); + basket.addProduct(new Coffee(Controller.prices.get("COFB"))); + System.out.println("2 coffees added!"); + break; + default: + keepRunning = false; + view.printExit(); + break; + } + } + } +} diff --git a/src/main/java/com/booleanuk/core/Product.java b/src/main/java/com/booleanuk/core/Product.java new file mode 100644 index 000000000..8f36079c2 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Product.java @@ -0,0 +1,7 @@ +package com.booleanuk.core; + +public interface Product { + public float calculateCost(); + public String name(); + public float basicPrice(); +} diff --git a/src/main/java/com/booleanuk/core/Triple.java b/src/main/java/com/booleanuk/core/Triple.java new file mode 100644 index 000000000..571e719e2 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Triple.java @@ -0,0 +1,4 @@ +package com.booleanuk.core; + +public record Triple(A a, B b, C c) { +} diff --git a/src/main/java/com/booleanuk/core/View.java b/src/main/java/com/booleanuk/core/View.java new file mode 100644 index 000000000..b3b6d71e9 --- /dev/null +++ b/src/main/java/com/booleanuk/core/View.java @@ -0,0 +1,184 @@ +package com.booleanuk.core; + +import java.util.*; + +public class View { + private final Scanner scanner; + + public View() { + scanner = new Scanner(System.in); + } + + public int mainMenu() { + System.out.println("What do you want to do?"); + System.out.println("1. Add Bagel"); + System.out.println("2. Remove Bagel"); + System.out.println("3. Change basket size"); + System.out.println("4. See total cost"); + System.out.println("5. Add Coffee"); + System.out.println("6. Get receipt and clear basket"); + System.out.println("\n(For testing) 12. Add 16 bagels and 2 coffees of various types"); + + return getInt(); + } + + public void printExit() { + System.out.println("Exiting..."); + } + + public int getInt() { + int output; + try { + output = scanner.nextInt(); + } catch (Exception e) { + System.err.println("Something went wrong"); + output = Integer.MIN_VALUE; + } + return output; + } + + public Bagel addBagel() { + System.out.println("Choose a bagel"); + Triple bagelType = displayPrices("Bagel"); + if (bagelType == null) return null; + + System.out.println("Choose filling, choose None to stop choosing."); + boolean loop = true; + ArrayList> fillings = new ArrayList<>(); + while (loop) { + Triple temp = displayPrices("Filling"); + if (temp != null) { + fillings.add(temp); + } else { + loop = false; + } + } + Bagel b = new Bagel(bagelType, fillings); + System.out.printf("It will cost $%.2f, is this ok?%n", b.calculateCost()); + System.out.println("1. Yes"); + System.out.println("2. No"); + int ans = getInt(); + if (ans == 1) { + return b; + } else { + return null; + } + } + + public Coffee addCoffee() { + System.out.println("Choose a coffee type"); + Triple coffeeType = displayPrices("Coffee"); + if (coffeeType == null) return null; + Coffee c = new Coffee(coffeeType); + System.out.printf("It will cost $%.2f, is this ok?%n", c.calculateCost()); + System.out.println("1. Yes"); + System.out.println("2. No"); + int ans = getInt(); + if (ans == 1) { + return c; + } else { + return null; + } + } + + private Triple displayPrices(String filter) { + ArrayList> temp = new ArrayList<>(); + int increment = 1; + System.out.println("0. None"); + for (Triple t: Controller.prices.values()) { + if (t.a().equals(filter) || filter.isEmpty()) { + System.out.printf("%h. %s: $%.2f%n", increment, t.b(), t.c()); + temp.add(t); + increment++; + } + } + if (temp.isEmpty()) { + System.out.println("No options available"); + return null; + } + System.out.println("Please write what you want"); + int output = getInt() - 1; + if (output >= temp.size() || output < 0) { + return null; + } + return temp.get(output); + } + + public void basketFull() { + System.out.println("Basket is full. You cannot add more bagels."); + } + + public Product chooseBagel(ArrayList bagels) { + if (bagels.isEmpty()) { + System.out.println("No options available"); + return null; + } + System.out.println("Choose a bagel"); + for (int i = 0; i < bagels.size(); i++) { + System.out.printf("%d. %s%n", i + 1, bagels.get(i).name()); + } + System.out.println("Please write what you want"); + int output = getInt() - 1; + if (output == bagels.size()) { + return null; + } + return bagels.get(output); + } + + public int getNewBasketSize() { + System.out.println("What should the new basket size be?"); + System.out.println("WARNING: Changing basket size to a number smaller than the current number of bagels will empty the current basket!"); + return getInt(); + } + + public void printPrice(float price) { + System.out.printf("The total cost is $%.2f.%n", price); + } + + public void emptyBasket() { + System.out.println("Your basket is empty."); + } + + public void printReceipt(float totCost, float totDisc, Basket.ReceiptInfo info) { + Date now = new Date(); + System.out.printf("~~~ Bob's Bagels ~~~\n" + + "\n" + + " %tF %tT\n" + + "\n" + + "----------------------------\n" + + "\n\nLone Products:\n", now, now); + for (Product p: info.remaining()) { + System.out.printf("%-25s %8.2f%n", p.name(), p.basicPrice()); + } + if (info.remaining().isEmpty()) { + System.out.println("None\n"); + } + + + System.out.println("\nFillings:"); + for (Map.Entry item :info.fillings().entrySet()) { + System.out.printf("%-20s %4d %8.2f%n", item.getKey(), item.getValue(), item.getValue() * 0.12f); + } + if (info.fillings().entrySet().isEmpty()) { + System.out.println("None\n"); + } + System.out.println("\nDeals:"); + // HM, price, discount + for (Triple, Float, Float> deal: info.deals()) { + for (Map.Entry item : deal.a().entrySet()) { + System.out.printf(" %-16s %4d%n", item.getKey(), item.getValue()); + } + System.out.printf(" Deal Cost %22.2f%n", deal.b()); + System.out.printf(" Discount %23.2f%n%n", deal.c()); + + } + if (info.deals().isEmpty()) { + System.out.println("None\n"); + } + + System.out.print("Total Cost"); + System.out.printf("%24.2f%n", totCost); + System.out.print("Total Saved"); + System.out.printf("%23.2f%n", totDisc); + } +} diff --git a/src/main/java/com/booleanuk/core/classDiagram.png b/src/main/java/com/booleanuk/core/classDiagram.png new file mode 100644 index 000000000..90db42a4c Binary files /dev/null and b/src/main/java/com/booleanuk/core/classDiagram.png differ diff --git a/src/main/java/com/booleanuk/core/domain-model.md b/src/main/java/com/booleanuk/core/domain-model.md new file mode 100644 index 000000000..714b943d3 --- /dev/null +++ b/src/main/java/com/booleanuk/core/domain-model.md @@ -0,0 +1,13 @@ +| Classes | Variables | Methods | Scenario | Outcome | +|--------------|----------------------------|-------------------------------------------|--------------------------------------------------|-------------------------------------------------| +| `Basket` | `List bagels` | `addBagel(Bagel bagel)` | there is space in bagels | bagel is added | +| | `List bagels` | | there's no space in bagels | user notified that bagels has no space | +| `Controller` | `Basket basket, View view` | `basket.removeBagel(Bagel bagel)` | view.removeBagel(...) specifies a specific bagel | specified bagel is removed | +| | | | basket has no bagels | user is notified: no bagel to remove | +| | `int basketSize` | `changeBasketSize(int size)` | basket has fewer bagels than size | size is changed | +| | | | basket has more bagels than size | basket is emptied, then size is changed | +| `Basket` | | `calculateCost()` | items in bagels | cost is calculated and returned | +| | | | bagels list empty | 0 is returned | +| `View` | | `AddBagel(Hashmap prices)` | user agrees to price | requested bagel is returned to controller | +| | | | user disagrees to price | no bagel is returned or added | +| | | | user wants to add a bagel | all options+costs are displayed to choose from | \ No newline at end of file diff --git a/src/main/java/com/booleanuk/core/gleekDiagramInfo.txt b/src/main/java/com/booleanuk/core/gleekDiagramInfo.txt new file mode 100644 index 000000000..0d2dddc10 --- /dev/null +++ b/src/main/java/com/booleanuk/core/gleekDiagramInfo.txt @@ -0,0 +1,65 @@ +Controller + - view: View + - prices: HashMap> + - basket: Basket + - basketSize: int + +changeBasketSize(int size): void + +start(): void + +View + -scanner: Scanner + +mainMenu(): int + +getInt(): int + +addBagel: Bagel + +addCoffee(): Coffee + +chooseProduct: Product + +printReceipt(float totCost, float totDisc, ReceiptInfo info): void + +Basket + - products: ArrayList + - unDiscountedProducts: ArrayList + - basketSize: int + +addProduct(): void + +findDiscount: float + +calculateDiscount(ArrayList items, int num, float dis): float + +setBasketSize(int basketSize): void + +receiptInformation(): ReceiptInfo + +clear(): void + +Product:service + +calculateCost(): float + +name(): String + +basicPrice(): float + +Bagel + - bagelType: Triple + - fillings: ArrayList> + +calculateCost(): float + +name(): String + +basicPrice(): float + +calculateBreadCost(): float + +Coffee + - coffeeType: Triple + +calculateCost(): float + +name(): String + +basicPrice(): float + +getCoffeeType(): Triple + +ReceiptInfo + + HashMap fillings + + ArrayList, Float, Float>> deals + + ArrayList remaining + +Triple + +Controller-->View +Controller-->Basket +Controller -.-> Triple +Basket --> Product +Basket -.-> ReceiptInfo +ReceiptInfo --> Product +Product --> Bagel +Product --> Coffee +Bagel -.-> Triple +Coffee -.-> Triple diff --git a/src/test/java/com/booleanuk/core/BagelTest.java b/src/test/java/com/booleanuk/core/BagelTest.java new file mode 100644 index 000000000..231736afc --- /dev/null +++ b/src/test/java/com/booleanuk/core/BagelTest.java @@ -0,0 +1,26 @@ +package com.booleanuk.core; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class BagelTest { + @Test + public void testCalculateCost() { + Bagel bagel = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0.61f, bagel.calculateCost(), 0.001); + } + + @Test + public void testAddSeveralFillings() { + ArrayList> fillings = new ArrayList<>() {{ + add(Controller.prices.get("FILB")); + add(Controller.prices.get("FILC")); + }}; + Bagel bagel = new Bagel(Controller.prices.get("BGLO"), fillings); + Assertions.assertEquals(0.73f, bagel.calculateCost(), 0.001); + } +} \ No newline at end of file diff --git a/src/test/java/com/booleanuk/core/BasketTest.java b/src/test/java/com/booleanuk/core/BasketTest.java new file mode 100644 index 000000000..89180d43a --- /dev/null +++ b/src/test/java/com/booleanuk/core/BasketTest.java @@ -0,0 +1,240 @@ +package com.booleanuk.core; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +class BasketTest { + + @Test + public void testAddBagel() { + Basket basket = new Basket(12); + Bagel bagel = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel); + Assertions.assertEquals(1, basket.size()); + } + + @Test + public void testAddBagelToFullBasket() { + Basket basket = new Basket(1); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel1); + Assertions.assertEquals(1, basket.size()); + basket.addProduct(bagel2); + Assertions.assertEquals(1, basket.size()); + } + + @Test + public void testRemoveBagel() { + Basket basket = new Basket(12); + Bagel bagel = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel); + Assertions.assertEquals(1, basket.size()); + basket.removeProduct(bagel); + Assertions.assertEquals(0, basket.size()); + } + + @Test + public void testRemoveNonexistentBagel() { + Basket basket = new Basket(12); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + basket.addProduct(bagel1); + Assertions.assertThrows(NoSuchElementException.class, () -> basket.removeProduct(bagel2)); + } + + @Test + public void testGetBagelsIsClone() { + Basket basket = new Basket(12); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel1); + basket.addProduct(bagel2); + Assertions.assertEquals(2, basket.size()); + ArrayList bagelsCopy = basket.getProducts(); + bagelsCopy.remove(bagel1); + Assertions.assertEquals(2, basket.size()); + Assertions.assertEquals(1, bagelsCopy.size()); + } + + @Test + public void testChangeSize() { + Basket basket = new Basket(1); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel1); + Assertions.assertEquals(1, basket.size()); + basket.addProduct(bagel2); + Assertions.assertEquals(1, basket.size()); + basket.setBasketSize(12); + basket.addProduct(bagel2); + Assertions.assertEquals(2, basket.size()); + } + + @Test + public void testChangeSizeToSmallerThanNumberOfBagels() { + Basket basket = new Basket(2); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Assertions.assertEquals(0, basket.size()); + basket.addProduct(bagel1); + basket.addProduct(bagel2); + Assertions.assertEquals(2, basket.size()); + basket.setBasketSize(1); + Assertions.assertEquals(0, basket.size()); + } + + @Test + public void testCalculateCost() { + Basket basket = new Basket(2); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB")); + basket.addProduct(bagel1); + Assertions.assertEquals(0.61f, basket.calculateCost(), 0.001); + basket.addProduct(bagel2); + Assertions.assertEquals(1.12f, basket.calculateCost(), 0.001); + } + + @Test + public void testCalculateCostOnEmptyBasket() { + Basket basket = new Basket(2); + Assertions.assertEquals(0.0f, basket.calculateCost(), 0.001); + } + + @Test + public void testCalculateCostOn2BagelsAnd1Coffee() { + Basket basket = new Basket(12); + Bagel bagel1 = new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB")); + Bagel bagel2 = new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB")); + Coffee coffee = new Coffee(Controller.prices.get("COFC")); + basket.addProduct(bagel1); + basket.addProduct(bagel2); + basket.addProduct(coffee); + Assertions.assertEquals(1.88f, basket.calculateCost(), 0.001); + } + + @Test + public void testFindDiscountOn13Bagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 12; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(1.89f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOn12PlainBagels() { + Basket b = new Basket(24); + for (int i = 0; i < 12; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(0.69f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOn12BagelsWithPlainBagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 6; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(1.29f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOn18Bagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 18; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(2.34f, b.findDiscount(), 0.001); + } + + + + @Test + public void testFindDiscountOn18BagelsWithPlainBagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 9; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(1.44f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOn19Bagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 19; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(2.34f, b.findDiscount(), 0.001); + } + + + + @Test + public void testFindDiscountOn20BagelsWithPlainBagels() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 10; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(1.54f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOnOneBagelAndOneCoffee() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + b.addProduct(new Coffee(Controller.prices.get("COFB"))); + Assertions.assertEquals(0.23f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOnTwoBagelsAndTwoCoffees() { + Basket b = new Basket(24); + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + b.addProduct(new Coffee(Controller.prices.get("COFB"))); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + b.addProduct(new Coffee(Controller.prices.get("COFC"))); + Assertions.assertEquals(0.66f, b.findDiscount(), 0.001); + } + + @Test + public void testFindDiscountOn19BagelsAndOneCoffee() { + Basket b = new Basket(24); + b.addProduct(new Coffee(Controller.prices.get("COFB"))); + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + for (int i = 0; i < 18; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLO"), Controller.prices.get("FILB"))); + } + Assertions.assertEquals(2.47f, b.findDiscount(), 0.001); + } + + @Test + public void testReceiptInfo() { + Basket b = new Basket(24); + for (int i = 0; i < 12; i++) { + b.addProduct(new Bagel(Controller.prices.get("BGLP"), Controller.prices.get("FILB"))); + } + Basket.ReceiptInfo i = b.receiptInformation(); + Assertions.assertEquals(12, i.fillings().get("Bacon")); + Assertions.assertEquals(0, i.remaining().size()); + Assertions.assertEquals(1, i.deals().size()); + } +} \ No newline at end of file