tdd-java-demo

tdd java demo with micro-commits

git clone https://9o.is/git/tdd-java-demo.git

commit 1aacfe986ccf497dfb63d90553f194d1ca6b88fc
parent 07f14abe783086ffac90ea5d87a70d877c88cb08
Author: Jul <jul@9o.is>
Date:   Thu,  1 Apr 2021 02:32:10 +0800

move models to model package

Diffstat:
Dsrc/main/java/takehome/Basket.java | 56--------------------------------------------------------
Dsrc/main/java/takehome/Discount.java | 51---------------------------------------------------
Msrc/main/java/takehome/Discounts.java | 2++
Dsrc/main/java/takehome/Item.java | 23-----------------------
Msrc/main/java/takehome/Items.java | 2++
Msrc/main/java/takehome/Runner.java | 3+++
Asrc/main/java/takehome/model/Basket.java | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/takehome/model/Discount.java | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/takehome/model/Item.java | 23+++++++++++++++++++++++
Msrc/main/java/takehome/view/CreateBasketView.java | 4++--
Msrc/main/java/takehome/view/PurchaseDayView.java | 2+-
Msrc/main/java/takehome/view/TotalView.java | 4++--
Dsrc/test/java/takehome/BasketTest.java | 74--------------------------------------------------------------------------
Dsrc/test/java/takehome/DiscountTest.java | 119-------------------------------------------------------------------------------
Dsrc/test/java/takehome/ItemTest.java | 27---------------------------
Asrc/test/java/takehome/model/BasketTest.java | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/java/takehome/model/DiscountTest.java | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/java/takehome/model/ItemTest.java | 27+++++++++++++++++++++++++++
18 files changed, 364 insertions(+), 355 deletions(-)

diff --git a/src/main/java/takehome/Basket.java b/src/main/java/takehome/Basket.java @@ -1,56 +0,0 @@ -package takehome; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; - -import java.time.LocalDate; -import java.util.Map; - -public class Basket { - private final Multiset<Item> items; - private LocalDate purchaseDate; - - public Basket(Map<Item, Integer> amounts) { - this.items = toMultiset(amounts); - this.purchaseDate = LocalDate.MAX; - } - - public Multiset<Item> getItems() { - return items; - } - - double getTotal() { - double total = 0; - for (Item item : items.elementSet()) { - int amount = getAmount(item); - total += item.getTotal(amount); - } - return total; - } - - Integer getAmount(Item item) { - return items.count(item); - } - - public double getTotal(Discount[] discounts) { - double total = getTotal(); - for (Discount discount : discounts) { - if (discount.isValid(purchaseDate)) { - total -= discount.getDiscount(this); - } - } - return total; - } - - private Multiset<Item> toMultiset(Map<Item, Integer> map) { - Multiset<Item> multiset = HashMultiset.create(); - for (Item item : map.keySet()) { - multiset.add(item, map.get(item)); - } - return multiset; - } - - public void setPurchaseDate(LocalDate purchaseDate) { - this.purchaseDate = purchaseDate; - } -} diff --git a/src/main/java/takehome/Discount.java b/src/main/java/takehome/Discount.java @@ -1,51 +0,0 @@ -package takehome; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; -import com.google.common.collect.Multisets; - -import java.time.LocalDate; -import java.util.Arrays; - -public class Discount { - private final Multiset<Item> items; - private final double amount; - private final LocalDate startDate; - private final LocalDate endDate; - - public Discount(double amount, Item ...items) { - this(amount, LocalDate.MIN, LocalDate.MAX, items); - } - - public Discount(double amount, LocalDate startDate, LocalDate endDate, Item... items) { - this.amount = amount; - this.startDate = startDate; - this.endDate = endDate; - this.items = HashMultiset.create(Arrays.asList(items)); - } - - public double getAmount() { - return amount; - } - - @SuppressWarnings("UnstableApiUsage") - double getDiscount(Basket basket) { - Multiset<Item> basketSet = basket.getItems(); - - int occurrences = 0; - boolean occurrence = Multisets.containsOccurrences(basketSet, items); - - while (occurrence) { - occurrences++; - basketSet = Multisets.difference(basketSet, items); - occurrence = Multisets.containsOccurrences(basketSet, items); - } - - return amount * occurrences; - } - - public boolean isValid(LocalDate date) { - return date.equals(startDate) || date.equals(endDate) || - (date.isAfter(startDate) && date.isBefore(endDate)); - } -} diff --git a/src/main/java/takehome/Discounts.java b/src/main/java/takehome/Discounts.java @@ -1,5 +1,7 @@ package takehome; +import takehome.model.Discount; + import java.time.LocalDate; import static takehome.Items.*; diff --git a/src/main/java/takehome/Item.java b/src/main/java/takehome/Item.java @@ -1,23 +0,0 @@ -package takehome; - -public class Item { - private final String name; - private final double cost; - - public Item(String name, double cost) { - this.name = name; - this.cost = cost; - } - - public String getName() { - return name; - } - - public double getCost() { - return cost; - } - - double getTotal(int amount) { - return amount * getCost(); - } -} diff --git a/src/main/java/takehome/Items.java b/src/main/java/takehome/Items.java @@ -1,5 +1,7 @@ package takehome; +import takehome.model.Item; + public final class Items { public static final Item SOUP = new Item("soup", 0.65); public static final Item BREAD = new Item("bread", 0.80); diff --git a/src/main/java/takehome/Runner.java b/src/main/java/takehome/Runner.java @@ -1,5 +1,8 @@ package takehome; +import takehome.model.Basket; +import takehome.model.Discount; +import takehome.model.Item; import takehome.view.CreateBasketView; import takehome.view.PurchaseDayView; import takehome.view.TotalView; diff --git a/src/main/java/takehome/model/Basket.java b/src/main/java/takehome/model/Basket.java @@ -0,0 +1,56 @@ +package takehome.model; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; + +import java.time.LocalDate; +import java.util.Map; + +public class Basket { + private final Multiset<Item> items; + private LocalDate purchaseDate; + + public Basket(Map<Item, Integer> amounts) { + this.items = toMultiset(amounts); + this.purchaseDate = LocalDate.MAX; + } + + public Multiset<Item> getItems() { + return items; + } + + public double getTotal() { + double total = 0; + for (Item item : items.elementSet()) { + int amount = getAmount(item); + total += item.getTotal(amount); + } + return total; + } + + public Integer getAmount(Item item) { + return items.count(item); + } + + public double getTotal(Discount[] discounts) { + double total = getTotal(); + for (Discount discount : discounts) { + if (discount.isValid(purchaseDate)) { + total -= discount.getDiscount(this); + } + } + return total; + } + + private Multiset<Item> toMultiset(Map<Item, Integer> map) { + Multiset<Item> multiset = HashMultiset.create(); + for (Item item : map.keySet()) { + multiset.add(item, map.get(item)); + } + return multiset; + } + + public void setPurchaseDate(LocalDate purchaseDate) { + this.purchaseDate = purchaseDate; + } +} diff --git a/src/main/java/takehome/model/Discount.java b/src/main/java/takehome/model/Discount.java @@ -0,0 +1,53 @@ +package takehome.model; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.google.common.collect.Multisets; +import takehome.model.Basket; +import takehome.model.Item; + +import java.time.LocalDate; +import java.util.Arrays; + +public class Discount { + private final Multiset<Item> items; + private final double amount; + private final LocalDate startDate; + private final LocalDate endDate; + + public Discount(double amount, Item ...items) { + this(amount, LocalDate.MIN, LocalDate.MAX, items); + } + + public Discount(double amount, LocalDate startDate, LocalDate endDate, Item... items) { + this.amount = amount; + this.startDate = startDate; + this.endDate = endDate; + this.items = HashMultiset.create(Arrays.asList(items)); + } + + public double getAmount() { + return amount; + } + + @SuppressWarnings("UnstableApiUsage") + public double getDiscount(Basket basket) { + Multiset<Item> basketSet = basket.getItems(); + + int occurrences = 0; + boolean occurrence = Multisets.containsOccurrences(basketSet, items); + + while (occurrence) { + occurrences++; + basketSet = Multisets.difference(basketSet, items); + occurrence = Multisets.containsOccurrences(basketSet, items); + } + + return amount * occurrences; + } + + public boolean isValid(LocalDate date) { + return date.equals(startDate) || date.equals(endDate) || + (date.isAfter(startDate) && date.isBefore(endDate)); + } +} diff --git a/src/main/java/takehome/model/Item.java b/src/main/java/takehome/model/Item.java @@ -0,0 +1,23 @@ +package takehome.model; + +public class Item { + private final String name; + private final double cost; + + public Item(String name, double cost) { + this.name = name; + this.cost = cost; + } + + public String getName() { + return name; + } + + public double getCost() { + return cost; + } + + public double getTotal(int amount) { + return amount * getCost(); + } +} diff --git a/src/main/java/takehome/view/CreateBasketView.java b/src/main/java/takehome/view/CreateBasketView.java @@ -1,7 +1,7 @@ package takehome.view; -import takehome.Basket; -import takehome.Item; +import takehome.model.Basket; +import takehome.model.Item; import java.io.PrintStream; import java.util.HashMap; diff --git a/src/main/java/takehome/view/PurchaseDayView.java b/src/main/java/takehome/view/PurchaseDayView.java @@ -1,6 +1,6 @@ package takehome.view; -import takehome.Basket; +import takehome.model.Basket; import java.io.PrintStream; import java.time.LocalDate; diff --git a/src/main/java/takehome/view/TotalView.java b/src/main/java/takehome/view/TotalView.java @@ -1,7 +1,7 @@ package takehome.view; -import takehome.Basket; -import takehome.Discount; +import takehome.model.Basket; +import takehome.model.Discount; import java.io.PrintStream; import java.text.DecimalFormat; diff --git a/src/test/java/takehome/BasketTest.java b/src/test/java/takehome/BasketTest.java @@ -1,73 +0,0 @@ -package takehome; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; -import org.junit.jupiter.api.Test; - -import java.time.LocalDate; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -class BasketTest { - - public static final Item SOUP = new Item("soup", 0.65); - public static final Item BREAD = new Item("bread", 0.80); - - @Test - public void getAmounts() { - Basket basket = createBasket(); - assertThat(basket.getItems(), is(items())); - } - - @Test - public void getTotal() { - Basket basket = createBasket(); - assertThat(basket.getTotal(), is(2.25)); - } - - @Test - public void getAmount() { - Basket basket = createBasket(); - assertThat(basket.getAmount(BREAD), is(2)); - } - - @Test - public void getTotalWithDiscounts() { - Discount discount = new Discount(0.40, SOUP, BREAD, BREAD); - Discount[] discounts = { discount }; - Basket basket = createBasket(); - - assertThat(basket.getTotal(discounts), is(1.85)); - } - - @Test - public void getTotalWithInvalidDiscount() { - LocalDate today = LocalDate.now(); - LocalDate tomorrow = today.plusDays(1); - LocalDate yesterday = today.minusDays(1); - - Basket basket = createBasket(); - basket.setPurchaseDate(tomorrow); - Discount[] discounts = { - new Discount(0.40, yesterday, today, SOUP, BREAD, BREAD) - }; - - assertThat(basket.getTotal(discounts), is(2.25)); - } - - private Basket createBasket() { - Map<Item, Integer> amounts = new HashMap<>(); - amounts.put(SOUP, 1); - amounts.put(BREAD, 2); - - return new Basket(amounts); - } - - private Multiset<Item> items() { - return HashMultiset.create(Arrays.asList(SOUP, BREAD, BREAD)); - } -} -\ No newline at end of file diff --git a/src/test/java/takehome/DiscountTest.java b/src/test/java/takehome/DiscountTest.java @@ -1,118 +0,0 @@ -package takehome; - -import org.junit.jupiter.api.Test; - -import java.time.LocalDate; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -class DiscountTest { - - public static final Item APPLE = new Item("apple", 0.10); - public static final Item SOUP = new Item("soup", 0.65); - public static final Item BREAD = new Item("bread", 0.80); - - public static final Discount APPLE_DISCOUNT = new Discount(0.01, APPLE); - public static final Discount BREAD_DISCOUNT = new Discount(0.40, SOUP, SOUP, BREAD); - - public static final LocalDate TODAY = LocalDate.now(); - public static final LocalDate TOMORROW = TODAY.plusDays(1); - public static final LocalDate YESTERDAY = TODAY.minusDays(1); - - @Test - void getAmount() { - assertThat(APPLE_DISCOUNT.getAmount(), is(0.01)); - } - - @Test - void noDiscount() { - Basket basket = createBasketWithApples(0); - assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0d)); - } - - @Test - void oneDiscount() { - Basket basket = createBasketWithApples(1); - assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0.01)); - } - - @Test - void multipleDiscounts() { - Basket basket = createBasketWithApples(2); - assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0.02)); - } - - @Test - void multipleItemsEmptyBasket() { - Basket basket = createBasketWithSoupBread(0, 0); - assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0d)); - } - - @Test - void multipleItemsNoDiscount() { - Basket basket = createBasketWithSoupBread(1, 1); - assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0d)); - } - - @Test - void multipleItemsOneDiscount() { - Basket basket = createBasketWithSoupBread(2, 1); - assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0.40)); - } - - @Test - void multipleItemsMultipleDiscounts() { - Basket basket = createBasketWithSoupBread(4, 2); - assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0.80)); - } - - @Test - void isInvalidBeforeStartDate() { - Discount discount = discountByDate(TODAY, TOMORROW); - assertThat(discount.isValid(YESTERDAY), is(false)); - } - - @Test - void isValidOnStartDate() { - Discount discount = discountByDate(TODAY, TOMORROW); - assertThat(discount.isValid(TODAY), is(true)); - } - - @Test - void isValidOnEndDate() { - Discount discount = discountByDate(TODAY, TOMORROW); - assertThat(discount.isValid(TOMORROW), is(true)); - } - - @Test - void isValidBetweenStartEndDates() { - Discount discount = discountByDate(YESTERDAY, TOMORROW); - assertThat(discount.isValid(TODAY), is(true)); - } - - @Test - void isInvalidAfterEndDate() { - Discount discount = discountByDate(YESTERDAY, TODAY); - assertThat(discount.isValid(TOMORROW), is(false)); - } - - private Discount discountByDate(LocalDate startDate, LocalDate endDate) { - return new Discount(0.01, startDate, endDate, APPLE); - } - - private Basket createBasketWithApples(int amount) { - Map<Item, Integer> amounts = new HashMap<>(); - amounts.put(APPLE, amount); - return new Basket(amounts); - } - - private Basket createBasketWithSoupBread(int soupAmount, int breadAmount) { - Map<Item, Integer> amounts = new HashMap<>(); - amounts.put(SOUP, soupAmount); - amounts.put(BREAD, breadAmount); - return new Basket(amounts); - } -} -\ No newline at end of file diff --git a/src/test/java/takehome/ItemTest.java b/src/test/java/takehome/ItemTest.java @@ -1,26 +0,0 @@ -package takehome; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -class ItemTest { - - public static final Item ITEM = new Item("soup", 0.65); - - @Test - public void getName() { - assertThat(ITEM.getName(), is("soup")); - } - - @Test - public void getCost() { - assertThat(ITEM.getCost(), is(0.65)); - } - - @Test - public void getTotal() { - assertThat(ITEM.getTotal(2), is(1.30)); - } -} -\ No newline at end of file diff --git a/src/test/java/takehome/model/BasketTest.java b/src/test/java/takehome/model/BasketTest.java @@ -0,0 +1,73 @@ +package takehome.model; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class BasketTest { + + public static final Item SOUP = new Item("soup", 0.65); + public static final Item BREAD = new Item("bread", 0.80); + + @Test + public void getAmounts() { + Basket basket = createBasket(); + assertThat(basket.getItems(), is(items())); + } + + @Test + public void getTotal() { + Basket basket = createBasket(); + assertThat(basket.getTotal(), is(2.25)); + } + + @Test + public void getAmount() { + Basket basket = createBasket(); + assertThat(basket.getAmount(BREAD), is(2)); + } + + @Test + public void getTotalWithDiscounts() { + Discount discount = new Discount(0.40, SOUP, BREAD, BREAD); + Discount[] discounts = { discount }; + Basket basket = createBasket(); + + assertThat(basket.getTotal(discounts), is(1.85)); + } + + @Test + public void getTotalWithInvalidDiscount() { + LocalDate today = LocalDate.now(); + LocalDate tomorrow = today.plusDays(1); + LocalDate yesterday = today.minusDays(1); + + Basket basket = createBasket(); + basket.setPurchaseDate(tomorrow); + Discount[] discounts = { + new Discount(0.40, yesterday, today, SOUP, BREAD, BREAD) + }; + + assertThat(basket.getTotal(discounts), is(2.25)); + } + + private Basket createBasket() { + Map<Item, Integer> amounts = new HashMap<>(); + amounts.put(SOUP, 1); + amounts.put(BREAD, 2); + + return new Basket(amounts); + } + + private Multiset<Item> items() { + return HashMultiset.create(Arrays.asList(SOUP, BREAD, BREAD)); + } +} +\ No newline at end of file diff --git a/src/test/java/takehome/model/DiscountTest.java b/src/test/java/takehome/model/DiscountTest.java @@ -0,0 +1,118 @@ +package takehome.model; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class DiscountTest { + + public static final Item APPLE = new Item("apple", 0.10); + public static final Item SOUP = new Item("soup", 0.65); + public static final Item BREAD = new Item("bread", 0.80); + + public static final Discount APPLE_DISCOUNT = new Discount(0.01, APPLE); + public static final Discount BREAD_DISCOUNT = new Discount(0.40, SOUP, SOUP, BREAD); + + public static final LocalDate TODAY = LocalDate.now(); + public static final LocalDate TOMORROW = TODAY.plusDays(1); + public static final LocalDate YESTERDAY = TODAY.minusDays(1); + + @Test + void getAmount() { + assertThat(APPLE_DISCOUNT.getAmount(), is(0.01)); + } + + @Test + void noDiscount() { + Basket basket = createBasketWithApples(0); + assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0d)); + } + + @Test + void oneDiscount() { + Basket basket = createBasketWithApples(1); + assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0.01)); + } + + @Test + void multipleDiscounts() { + Basket basket = createBasketWithApples(2); + assertThat(APPLE_DISCOUNT.getDiscount(basket), is(0.02)); + } + + @Test + void multipleItemsEmptyBasket() { + Basket basket = createBasketWithSoupBread(0, 0); + assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0d)); + } + + @Test + void multipleItemsNoDiscount() { + Basket basket = createBasketWithSoupBread(1, 1); + assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0d)); + } + + @Test + void multipleItemsOneDiscount() { + Basket basket = createBasketWithSoupBread(2, 1); + assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0.40)); + } + + @Test + void multipleItemsMultipleDiscounts() { + Basket basket = createBasketWithSoupBread(4, 2); + assertThat(BREAD_DISCOUNT.getDiscount(basket), is(0.80)); + } + + @Test + void isInvalidBeforeStartDate() { + Discount discount = discountByDate(TODAY, TOMORROW); + assertThat(discount.isValid(YESTERDAY), is(false)); + } + + @Test + void isValidOnStartDate() { + Discount discount = discountByDate(TODAY, TOMORROW); + assertThat(discount.isValid(TODAY), is(true)); + } + + @Test + void isValidOnEndDate() { + Discount discount = discountByDate(TODAY, TOMORROW); + assertThat(discount.isValid(TOMORROW), is(true)); + } + + @Test + void isValidBetweenStartEndDates() { + Discount discount = discountByDate(YESTERDAY, TOMORROW); + assertThat(discount.isValid(TODAY), is(true)); + } + + @Test + void isInvalidAfterEndDate() { + Discount discount = discountByDate(YESTERDAY, TODAY); + assertThat(discount.isValid(TOMORROW), is(false)); + } + + private Discount discountByDate(LocalDate startDate, LocalDate endDate) { + return new Discount(0.01, startDate, endDate, APPLE); + } + + private Basket createBasketWithApples(int amount) { + Map<Item, Integer> amounts = new HashMap<>(); + amounts.put(APPLE, amount); + return new Basket(amounts); + } + + private Basket createBasketWithSoupBread(int soupAmount, int breadAmount) { + Map<Item, Integer> amounts = new HashMap<>(); + amounts.put(SOUP, soupAmount); + amounts.put(BREAD, breadAmount); + return new Basket(amounts); + } +} +\ No newline at end of file diff --git a/src/test/java/takehome/model/ItemTest.java b/src/test/java/takehome/model/ItemTest.java @@ -0,0 +1,26 @@ +package takehome.model; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class ItemTest { + + public static final Item ITEM = new Item("soup", 0.65); + + @Test + public void getName() { + assertThat(ITEM.getName(), is("soup")); + } + + @Test + public void getCost() { + assertThat(ITEM.getCost(), is(0.65)); + } + + @Test + public void getTotal() { + assertThat(ITEM.getTotal(2), is(1.30)); + } +} +\ No newline at end of file