Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f03d4a1
Added domain models for all classes except Basket
Magnus-droid Jan 12, 2025
4681c26
Finished domain models for the core tasks
Magnus-droid Jan 12, 2025
6bd5ad9
Added Item class and Item tests
Magnus-droid Jan 12, 2025
573f10f
Added Bagel class and bagel creation test
Magnus-droid Jan 12, 2025
a882abd
Added Filling and Coffee class + their creation tests
Magnus-droid Jan 12, 2025
5bf806c
Added fillingAttachment test
Magnus-droid Jan 12, 2025
d61d891
Implemented the attachFilling method in Bagel + updated test for it
Magnus-droid Jan 12, 2025
1bfa6ed
Updated domain model for basket to send a signal on invalid attempts
Magnus-droid Jan 12, 2025
ef48f45
(Forgot to commit earlier) Added coffee and fillings classes
Magnus-droid Jan 12, 2025
8dcacc6
Created ItemFactory class + item creation test
Magnus-droid Jan 12, 2025
f2919dd
Added tests for coffee and fillings creation
Magnus-droid Jan 12, 2025
65d5fcf
Implemented createItem to pass tests
Magnus-droid Jan 12, 2025
3a1f27c
Updated comment explaining the null test
Magnus-droid Jan 12, 2025
c3f21a7
Created Basket skeleton + test skeleton
Magnus-droid Jan 12, 2025
9ec5d76
Added test for adding items to basket
Magnus-droid Jan 13, 2025
d0daeb5
Implemented addItem method to pass first test
Magnus-droid Jan 13, 2025
6d766b6
Updated addItem method to not go over max capacity and pass 2nd test
Magnus-droid Jan 13, 2025
a63b4dc
Added basic removeItem method test
Magnus-droid Jan 13, 2025
1ef4876
implemented basic remove Item method to pass test
Magnus-droid Jan 13, 2025
8bef245
Added test for removing non existing items and improved removeItem ac…
Magnus-droid Jan 13, 2025
2d4834b
Imporved tests and added tests for max capacity
Magnus-droid Jan 13, 2025
c2bebbb
implemented changeCapacity to pass first test
Magnus-droid Jan 13, 2025
4eae0da
imprOved changeCapacity and added test
Magnus-droid Jan 13, 2025
531be2a
Changed/removed som redundant methods and updated the logic according…
Magnus-droid Jan 13, 2025
774dd34
Added error messages to be printed out for add and remove item methods
Magnus-droid Jan 13, 2025
055217e
Added class diagram that I forgot to commit until now, fixed formatti…
Magnus-droid Jan 13, 2025
c7799ea
domain model for EXT1 added, added tests for discounts
Magnus-droid Jan 13, 2025
a57f7df
Fixed the tests as I had misunderstood something, increased capacity …
Magnus-droid Jan 13, 2025
63db50d
Finished extension1 with a very long and ugly implementation. Sorry!
Magnus-droid Jan 14, 2025
8425258
Added receipt class and tests
Magnus-droid Jan 14, 2025
310009d
Finished extension 2 (I did red-green, just forgot to commit until it…
Magnus-droid Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ I want customers to only be able to order things that we stock in our inventory.

| SKU | Price | Name | Variant |
|------|-------|---------|---------------|
| BGLO | 0.49 | Bagel | Onion |
| BGLP | 0.39 | Bagel | Plain |
| BGLE | 0.49 | Bagel | Everything |
| BGLO | 0.49 | Bagel | Onion |
| BGLS | 0.49 | Bagel | Sesame |
| COFB | 0.99 | Coffee | Black |
| COFW | 1.19 | Coffee | White |
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/booleanuk/core/Bagel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.booleanuk.core;

import java.util.ArrayList;

public class Bagel extends Item{
private ArrayList<Filling> fillings = new ArrayList<>();
private int maxFillings = 3;

public Bagel(String id, double price, String description) {
super(id, price, description);
}

// Allows up to only 3 fillings (let's not get silly here) to be attached to bagels
public boolean attachFilling(Filling filling) {
System.out.println(this.fillings.size());
if (this.fillings.size() <= this.maxFillings - 1) {
this.fillings.add(filling);
return true;
}
return false;
}

public ArrayList<Filling> getAllFillings() {
return this.fillings;
}
}
52 changes: 52 additions & 0 deletions src/main/java/com/booleanuk/core/Basket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.booleanuk.core;

import java.util.ArrayList;

public class Basket {
private final ArrayList<Item> basket = new ArrayList<>();
private int maxCapacity = 5;
private double totalCost = 0.0;

public boolean addItem(Item item) {
if (this.basket.size() <= this.maxCapacity - 1) {
this.basket.add(item);
this.totalCost += item.getPrice();
return true;
}
System.out.println("Basket full!");
return false;

}

public boolean removeItem(Item item) {
if (this.basket.contains(item)) {
this.basket.remove(item);
this.totalCost -= item.getPrice();
return true;
}
System.out.println("No such item in the basket!");
return false;
}

public boolean changeCapacity(int newCapacity) {
if (newCapacity > 0) {
this.maxCapacity = newCapacity;
return true;
}
return false;
}

public ArrayList<Item> getBasket(){
return this.basket;
}

public double getTotalCost() {
return this.totalCost;
}

public int getMaxCapacity() {
return this.maxCapacity;
}


}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/main/java/com/booleanuk/core/Coffee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.booleanuk.core;

public class Coffee extends Item {
public Coffee(String id, double price, String description) {
super(id, price, description);
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/booleanuk/core/Filling.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.booleanuk.core;

public class Filling extends Item{
public Filling(String id, double price, String description) {
super(id, price, description);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/booleanuk/core/Item.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.booleanuk.core;

public class Item {
private final String id;
private final double price;
private final String description;

public Item(String id, double price, String description) {
this.id = id;
this.price = price;
this.description = description;
}

public String getId() {
return id;
}

public double getPrice() {
return price;
}

public String getDescription() {
return description;
}
}
53 changes: 53 additions & 0 deletions src/main/java/com/booleanuk/core/ItemFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.booleanuk.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

public class ItemFactory {
private String id;
private final HashMap<String, ArrayList<Object>> inventory = new HashMap<>() {{
put("BGLP", new ArrayList<>(Arrays.asList(0.39, "Bagel", "Plain")));
put("BGLE", new ArrayList<>(Arrays.asList(0.49, "Bagel", "Everything")));
put("BGLO", new ArrayList<>(Arrays.asList(0.49, "Bagel", "Onion")));
put("BGLS", new ArrayList<>(Arrays.asList(0.49, "Bagel", "Sesame")));
put("COFB", new ArrayList<>(Arrays.asList(0.99, "Coffee", "Black")));
put("COFW", new ArrayList<>(Arrays.asList(1.19, "Coffee", "White")));
put("COFC", new ArrayList<>(Arrays.asList(1.29, "Coffee","Cappuccino")));
put("COFL", new ArrayList<>(Arrays.asList(1.29, "Coffee", "Latte")));
put("FILB", new ArrayList<>(Arrays.asList(0.12, "Filling", "Bacon")));
put("FILE", new ArrayList<>(Arrays.asList(0.12, "Filling", "Egg")));
put("FILC", new ArrayList<>(Arrays.asList(0.12, "Filling", "Cheese")));
put("FILX", new ArrayList<>(Arrays.asList(0.12, "Filling", "Cream Cheese")));
put("FILS", new ArrayList<>(Arrays.asList(0.12, "Filling", "Smoked Salmon")));
put("FILH", new ArrayList<>(Arrays.asList(0.12, "Filling", "Ham")));
}};


//private internal setters
private double setPrice() {
return (double) inventory.get(this.id).getFirst();
}

private String setDescription() {
return (String) inventory.get(this.id).get(2);
}

// create and return new instance of bagel, coffee or filling based on what the provided SKU (id) was
public Item createItem(String id) {
this.id = id;
if (this.inventory.containsKey(this.id)) {
if (this.id.startsWith("B")) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to make this case-insensitive

return new Bagel(this.id, setPrice(), setDescription());

} else if (this.id.startsWith("C")) {
return new Coffee(this.id, setPrice(), setDescription());

} else if (this.id.startsWith("F")) {
return new Filling(this.id, setPrice(), setDescription());
}
}
return null;
}

}
63 changes: 63 additions & 0 deletions src/main/java/com/booleanuk/core/domain-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
(Get/set methods don't have a scenario because they return null/do nothing if the input for the setter is invalid or the getter tries to get something it can't.)

# Item class

| Members | Methods | Output |
|--------------------|-------------------------|------------------------|
| String id | String getId() | SKU of the item |
| double price | double getPrice() | Price of the item |
| String description | String getDescription() | Description of the item |

# Bagel class

| Inheritance | Members | Methods | Scenario | Result/Output |
|---------------------|------------------------------|----------------------------------------|-------------------------------------|------------------------------------------------|
| Child of Item class | String id | String getId() | | SKU of the bagel |
| | double price | double getPrice() | | Price of the bagel |
| | String description | String getDescription() | | Description of the bagel |
| | ArrayList\<Filling> fillings | boolean attachFilling(Filling filling) | 3 or more fillings already attached | Return false, don't add the filling |
| | | | Less than 3 fillings attached | Return true, add filling to fillings ArrayList |
| | | ArrayList\<Filling> getAllFillings() | | All fillings attached to the bagel |

# Filling class

| Inheritance | Members | Methods | Output |
|---------------------|--------------------|-------------------------|-----------------------------|
| Child of Item class | String id | String getId() | SKU of the filling |
| | double price | double getPrice() | Price of the filling |
| | String description | String getDescription() | Description of the filling |

# Coffee class


| Inheritance | Members | Methods | Output |
|---------------------|--------------------|-------------------------|---------------------------|
| Child of Item class | String id | String getId() | SKU of the coffee |
| | double price | double getPrice() | Price of the coffee |
| | String description | String getDescription() | Description of the coffee |

# ItemFactory class


| Members | Methods | Scenario | Output/Result |
|-------------------------------------------------|----------------------------|----------------------|-----------------------------------------------------------------------|
| HashMap\<String>, ArrayList\<Object>> inventory | void setPrice() | | Sets the price of the item internally based on the provided SKU |
| String id | void setDescription | | Sets the description of the item internally based on the provided SKU |
| | Item createItem(String id) | Invalid id | return null |
| | | id starts with 'B' | create and return Bagel object based on id |
| | | id starts with 'C' | create and return Coffee object based on id |
| | | id starts with 'F' | create and return Filling object based on id |


# Basket class


| Members | Methods | Scenario | Output/Result |
|-------------------------|-----------------------------------------|-------------------------------------|--------------------------------------------------------------------------|
| ArrayList\<Item> basket | boolean addToBasket(Item item) | Basket at max capacity | Don't add, return false |
| int maxCapacity; | | Basket not at max capacity | Add item to basket, increase totalPrice by price of item, return true |
| double totalPrice; | boolean removeFromBasket(Item item) | Item does not exist in basket | Don't remove, return false |
| | | Item in basket | Remove the item, decrease total totalPrice by price of item, return true |
| | boolean changeCapacity(int newCapacity) | newCapacity is less than 1 | Don't change capacity, return false |
| | | newCapacity is larger or equal to 1 | Update to new capacity, return true |
| | ArrayList\<Item> getBasket() | | Returns contents of basket |
26 changes: 26 additions & 0 deletions src/main/java/com/booleanuk/extension/Bagel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.booleanuk.extension;

import java.util.ArrayList;

public class Bagel extends Item {
private ArrayList<Filling> fillings = new ArrayList<>();
private int maxFillings = 3;

public Bagel(String id, double price, String description) {
super(id, price, description);
}

// Allows up to only 3 fillings (let's not get silly here) to be attached to bagels
public boolean attachFilling(Filling filling) {
System.out.println(this.fillings.size());
if (this.fillings.size() <= this.maxFillings - 1) {
this.fillings.add(filling);
return true;
}
return false;
}

public ArrayList<Filling> getAllFillings() {
return this.fillings;
}
}
111 changes: 111 additions & 0 deletions src/main/java/com/booleanuk/extension/Basket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.booleanuk.extension;

import jdk.jfr.Label;

import java.security.cert.Extension;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class Basket {
private final ArrayList<Item> basket = new ArrayList<>();
private int maxCapacity = 25;
private double totalCost = 0.0;

public boolean addItem(Item item) {
if (this.basket.size() <= this.maxCapacity - 1) {
this.basket.add(item);
this.totalCost += item.getPrice();
return true;
}
System.out.println("Basket full!");
return false;

}

public boolean removeItem(Item item) {
if (this.basket.contains(item)) {
this.basket.remove(item);
this.totalCost -= item.getPrice();
return true;
}
System.out.println("No such item in the basket!");
return false;
}

public boolean changeCapacity(int newCapacity) {
if (newCapacity > 0) {
this.maxCapacity = newCapacity;
return true;
}
return false;
}

public ArrayList<Item> getBasket(){
return this.basket;
}

public double getTotalCost() {
return this.totalCost;
}

public int getMaxCapacity() {
return this.maxCapacity;
}


//This methods will allow multiple discounts to be applied and likely got this ugly because of it
//I.e. if there are 18 bagels of the same type, first the 12 bagel discount is given and then the 6 bagel discount for the remaining bagles
//The coffee discount needs "stand-alone" bagels, so not bagles that are already part of another discount calculation
public void checkDiscounts() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can become hard to maintain if other types of discounts are added in hje future. I think it belongs in its own class, and could do with further decomposition into smaller methods.

HashMap<String, ArrayList<Item>> counterMap = new HashMap<>();
double counter = 0.0;

for (Item item : this.basket) {
counterMap.computeIfAbsent(item.getId(), k -> new ArrayList<>()).add(item);
}

for (String id : counterMap.keySet()) {
int remainder12;
int finalRemainder;
if (id.startsWith("BGL")) {
//Check for 12 bagel discount
int quotient12 = counterMap.get(id).size() / 12;
counter += 3.99 * quotient12;
if (quotient12 != 0) {
remainder12 = counterMap.get(id).size() % (12 * quotient12);
} else {
remainder12 = counterMap.get(id).size();
}

//Check for 6 bagel discount
int quotient6 = remainder12 / 6;
counter += 2.49 * quotient6;
if (quotient6 != 0) {
finalRemainder = remainder12 % (6 * quotient6);
} else {
finalRemainder = remainder12;
}

//Check for bagel and coffee discounts
if (counterMap.containsKey("COFB")) {
while (!counterMap.get("COFB").isEmpty() && finalRemainder > 0) {
counter += 1.25;
counterMap.get("COFB").removeFirst();
finalRemainder--;
}

}
//Good chance that the coffee check has removed all elements in the list so need to check if null
//before the remaining (non-discounted) items are calculated
if (counterMap.get(id).getFirst() != null) {
counter += finalRemainder * counterMap.get(id).getFirst().getPrice();
}
}
}
this.totalCost = counter;
}


}
7 changes: 7 additions & 0 deletions src/main/java/com/booleanuk/extension/Coffee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.booleanuk.extension;

public class Coffee extends Item {
public Coffee(String id, double price, String description) {
super(id, price, description);
}
}
Loading
Loading