diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..09b9815b9 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,82 @@ +## 로직 분류 +### 도메인 로직 +- [x] 자판기가 보유하고 있는 금액을 저장한다. + - [x] 10원 단위인지 예외 처리 한다. +- [x] 보유하고 있는 금액으로 동전을 무작위로 생성한다. +- [x] 상품 목록과 가격과 수량을 저장한다. + - [x] 상품명이 공백인 경우 예외 처리 한다. + - [x] 상품 가격이 100원 미만일 경우 예외 처리 한다. + - [x] 상품 가격이 10원으로 나누어떨어지지 않을 경우 예외처리한다. + - [x] 상품 수량이 0 이하일 경우 예외 처리 한다. +- [x] 투입 금액을 저장한다. + - [x] 10원 단위인지 예외 처리 한다. +- [x] 구입할 상품명을 저장한다. + - [x] 구입할 상품명이 없는 경우 예외 처리 한다. + - 구입할 상품명이 공백인지 검사한다. +- 구입할 상품명이 상품 목록에 있는지 예외처리한다. +- 구입할 상품명이 상품 목록에 있으면 투입 금액에서 상품의 가격만큼 뺀다. +- 위의 과정을 반복한다. +- 잔돈을 반환해야 할 경우(남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우) 잔돈을 반환한다. + +### UI 로직 +- [x] 자판기가 보유하고 있는 금액을 입력하라는 안내를 출력한다. +- [x] 자판기가 보유하고 있는 금액의 입력을 받는다. + - [x] 숫자인지 예외 처리 한다. +- [x] 무작위로 생성된 동전을 출력한다. +- [x] 상품명과 가격과 수량을 입력하라는 안내를 출력한다. +- [x] 상품명과 가격과 수량을 입력하라는 안내를 출력한다. +- [x] 상품명과 가격과 수량을 입력받는다. + - [x] 형식에 맞는지 예외 처리 한다. (가격과 수량이 숫자인지) (int의 범위인지) +- [x] 투입 금액을 입력하라는 안내를 출력한다. +- [x] 투입 금액을 입력 받는다. + - [x] 숫자인지 예외 처리한다. +- 투입 금액 안내를 출력한다. +- 구입할 상품명을 입력하라는 안내를 출력한다. +- 구입할 상품명을 입력받는다. +- 반환된 잔돈을 출력한다. + +## 기능 구현 목록 +- 자판기가 보유하고 있는 금액을 입력하라는 안내를 출력한다. +- 자판기가 보유하고 있는 금액의 입력을 받는다. + - 숫자인지 예외 처리 한다. +- 자판기가 보유하고 있는 금액을 저장한다. + - 10원 단위인지 예외 처리 한다. +- 보유하고 있는 금액으로 동전을 무작위로 생성한다. +- 무작위로 생성된 동전을 출력한다. +- 상품명과 가격과 수량을 입력하라는 안내를 출력한다. +- 상품명과 가격과 수량을 입력받는다. + - 형식에 맞는지 예외 처리 한다. (가격과 수량이 숫자인지) (int의 범위인지) +- 상품 목록과 가격과 수량을 저장한다. + - 상품명이 이미 존재하는 경우 예외 처리 한다. + - 상품명이 공백인 경우 예외 처리 한다. + - 상품 가격이 100원 미만일 경우 예외 처리 한다. + - 상품 가격이 10원으로 나누어떨어지지 않을 경우 예외처리한다. +- 투입 금액을 입력하라는 안내를 출력한다. +- 투입 금액을 입력 받는다. + - 숫자인지 예외 처리한다. +- 투입 금액을 저장한다. + - 10원 단위인지 예외 처리 한다. +- 투입 금액 안내를 출력한다. +- 구입할 상품명을 입력하라는 안내를 출력한다. +- 구입할 상품명을 입력받는다. +- 구입할 상품명을 저장한다. + - 구입할 상품명이 공백인지 검사한다. +- 구입할 상품명이 상품 목록에 있는지 예외처리한다. +- 구입할 상품명이 상품 목록에 있으면 투입 금액에서 상품의 가격만큼 뺀다. +- 위의 과정을 반복한다. +- 잔돈을 반환해야 할 경우(남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우) 잔돈을 반환한다. +- 반환된 잔돈을 출력한다. + + +## 프로그램 진행 과정 +- 자판기가 보유하고 있는 금액을 입력받는다. +- 자판기가 보유하고 있는 금액으로 동전을 무작위로 생성한다. +- 자판기가 보유한 동전을 출력한다. +- 상품명과 가격, 수량을 입력받는다. +- 투입 금액을 입력 받는다. + - 투입 금액으로 동전을 생성하지 않는다. +- 투입금액을 안내한다 +- 구매할 상품을 입력받는다. +- 투입 금액이 상품의 가격 중 최소값보다 적거나, 모든 상품이 소진된 경우 바로 잔돈을 반환한다. + - 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액만 반환한다. +- 투입 금액이 상품의 가격 중 최소값보다 큰 경우 위의 과정을 반복한다. \ No newline at end of file diff --git a/src/main/java/constant/ErrorLog.java b/src/main/java/constant/ErrorLog.java new file mode 100644 index 000000000..9a52c4387 --- /dev/null +++ b/src/main/java/constant/ErrorLog.java @@ -0,0 +1,25 @@ +package constant; + +public enum ErrorLog { + ERROR_MARK("[ERROR]"), + TOO_LOW_PRICE("가격이 100원 미만입니다."), + SPACE(" "), + NOT_IN_PRODUCT_LIST("구매 상품이 보유 목록에 없습니다."), + ONLY_SPACE("상품명은 공백일 수 없습니다."), + ZERO_NUMBER("0이 될 수 없습니다."), + NOT_DIVISIBLE("10원 단위가 아닙니다."), + NOT_ENOUGH_MONEY("투입 금액이 부족합니다."), + INVALID_FORM("입력이 형식에 맞지 않습니다."), + NOT_NUMBER_INPUT("입력이 숫자가 아닙니다."); + + private final String log; + ErrorLog(String log) { + this.log = log; + } + + public String getLog() { + return ERROR_MARK.log + + SPACE.log + + log; + } +} diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java new file mode 100644 index 000000000..1aa1760d5 --- /dev/null +++ b/src/main/java/controller/Controller.java @@ -0,0 +1,78 @@ +package controller; + +import dto.HoldingSumRequestDto; +import dto.MoneyRequestDto; +import dto.ProductNameRequestDto; +import dto.ProductsRequestDto; +import service.VendingMachineService; +import view.InputView; +import view.OutputView; + +public class Controller { + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + private final VendingMachineService vendingMachineService = new VendingMachineService(); + + public void control() { + initHoldingSum(); + saveProductsInfo(); + inputMoney(); + buyProduct(); + } + + private void initHoldingSum() { + while (true) { + try { + HoldingSumRequestDto holdingSumRequestDto = inputView.readHolingSum(); + outputView.printCoins(vendingMachineService.changeHoldingSumToCoins(holdingSumRequestDto)); + return; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + private void saveProductsInfo() { + while (true) { + try { + ProductsRequestDto productsRequestDto = inputView.readProducts(); + vendingMachineService.saveProductsInfo(productsRequestDto); + return; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + private void inputMoney() { + while (true) { + try { + MoneyRequestDto moneyRequestDto = inputView.readMoney(); + vendingMachineService.saveMoney(moneyRequestDto); + return; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + + private void buyProduct() { + while (!vendingMachineService.isEnd()) { + inputProductName(); + } + outputView.printEnd(vendingMachineService.conveyCurrentMoney(), vendingMachineService.calculateChange()); + } + + private void inputProductName() { + while (true) { + try { + ProductNameRequestDto productNameRequestDto = inputView.readProductName( + vendingMachineService.conveyCurrentMoney()); + vendingMachineService.purchaseProduct(productNameRequestDto); + return; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } +} diff --git a/src/main/java/dto/CoinsResponseDto.java b/src/main/java/dto/CoinsResponseDto.java new file mode 100644 index 000000000..d63480ea4 --- /dev/null +++ b/src/main/java/dto/CoinsResponseDto.java @@ -0,0 +1,15 @@ +package dto; + +import java.util.HashMap; + +public class CoinsResponseDto { + private final HashMap coins; + + public CoinsResponseDto(HashMap coins) { + this.coins = coins; + } + + public HashMap getCoins() { + return coins; + } +} diff --git a/src/main/java/dto/HoldingSumRequestDto.java b/src/main/java/dto/HoldingSumRequestDto.java new file mode 100644 index 000000000..fe4858397 --- /dev/null +++ b/src/main/java/dto/HoldingSumRequestDto.java @@ -0,0 +1,13 @@ +package dto; + +public class HoldingSumRequestDto { + private final int holdingSum; + + public HoldingSumRequestDto(int holdingSum) { + this.holdingSum = holdingSum; + } + + public int getHoldingSum() { + return holdingSum; + } +} diff --git a/src/main/java/dto/MoneyRequestDto.java b/src/main/java/dto/MoneyRequestDto.java new file mode 100644 index 000000000..ac7c39bfa --- /dev/null +++ b/src/main/java/dto/MoneyRequestDto.java @@ -0,0 +1,13 @@ +package dto; + +public class MoneyRequestDto { + private final int money; + + public MoneyRequestDto(int money) { + this.money = money; + } + + public int getMoney() { + return money; + } +} diff --git a/src/main/java/dto/MoneyResponseDto.java b/src/main/java/dto/MoneyResponseDto.java new file mode 100644 index 000000000..c7fa6497a --- /dev/null +++ b/src/main/java/dto/MoneyResponseDto.java @@ -0,0 +1,13 @@ +package dto; + +public class MoneyResponseDto { + private final int money; + + public MoneyResponseDto(int money) { + this.money = money; + } + + public int getMoney() { + return money; + } +} diff --git a/src/main/java/dto/ProductNameRequestDto.java b/src/main/java/dto/ProductNameRequestDto.java new file mode 100644 index 000000000..3ada629f6 --- /dev/null +++ b/src/main/java/dto/ProductNameRequestDto.java @@ -0,0 +1,13 @@ +package dto; + +public class ProductNameRequestDto { + private final String productName; + + public ProductNameRequestDto(String productName) { + this.productName = productName; + } + + public String getProductName() { + return productName; + } +} diff --git a/src/main/java/dto/ProductsRequestDto.java b/src/main/java/dto/ProductsRequestDto.java new file mode 100644 index 000000000..e753c7bf2 --- /dev/null +++ b/src/main/java/dto/ProductsRequestDto.java @@ -0,0 +1,15 @@ +package dto; + +import java.util.List; + +public class ProductsRequestDto { + List products; + + public ProductsRequestDto(List products) { + this.products = products; + } + + public List getProducts() { + return products; + } +} diff --git a/src/main/java/service/VendingMachineService.java b/src/main/java/service/VendingMachineService.java new file mode 100644 index 000000000..8a668565d --- /dev/null +++ b/src/main/java/service/VendingMachineService.java @@ -0,0 +1,49 @@ +package service; + +import dto.CoinsResponseDto; +import dto.HoldingSumRequestDto; +import dto.MoneyRequestDto; +import dto.MoneyResponseDto; +import dto.ProductNameRequestDto; +import dto.ProductsRequestDto; +import vendingmachine.CoinChanger; +import vendingmachine.Coins; +import vendingmachine.Money; +import vendingmachine.Products; + +public class VendingMachineService { + private Money money; + private Products products; + private Coins coins; + + public CoinsResponseDto changeHoldingSumToCoins(HoldingSumRequestDto holdingSumRequestDto) { + int holdingSum = holdingSumRequestDto.getHoldingSum(); + coins = new Coins(new CoinChanger(holdingSum).changeToCoin()); + return coins.toCoinsResponseDto(); + } + + public void saveProductsInfo(ProductsRequestDto productsRequestDto) { + products = new Products(productsRequestDto.getProducts()); + } + + public void saveMoney(MoneyRequestDto moneyRequestDto) { + money = new Money(moneyRequestDto.getMoney()); + } + + public MoneyResponseDto conveyCurrentMoney() { + return money.toMoneyResponseDto(); + } + + public void purchaseProduct(ProductNameRequestDto productNameRequestDto) { + String productName = productNameRequestDto.getProductName(); + money.subtract(products.purchase(productName, money.getMoney())); + } + + public boolean isEnd() { + return products.noStock() || money.noMoney(products.minimumPrice()); + } + + public CoinsResponseDto calculateChange() { + return coins.calculateChanges(money.getMoney()); + } +} diff --git a/src/main/java/util/Validator.java b/src/main/java/util/Validator.java new file mode 100644 index 000000000..2b98892fa --- /dev/null +++ b/src/main/java/util/Validator.java @@ -0,0 +1,45 @@ +package util; + +import java.util.List; + +import constant.ErrorLog; +import vendingmachine.Coin; + +public class Validator { + public static void validatePositiveInteger(String string) { + if (!string.matches("^[0-9]{1,9}$")) { + throw new IllegalArgumentException(ErrorLog.NOT_NUMBER_INPUT.getLog()); + } + } + + public static List validateProductFormSize(List productInfo) { + if (productInfo.size() != 3) { + throw new IllegalArgumentException(ErrorLog.INVALID_FORM.getLog()); + } + return productInfo; + } + + public static void validateDivisibleByMinimumMonetaryUnit(int money) { + if (money % Coin.COIN_10.getAmount() != 0) { + throw new IllegalArgumentException(ErrorLog.NOT_DIVISIBLE.getLog()); + } + } + + public static void validateProductForm(String string) { + if (!string.matches("^\\[\\S+,\\d{1,9}+,\\d{1,9}\\]$")) { + throw new IllegalArgumentException(ErrorLog.INVALID_FORM.getLog()); + } + } + + public static void validateEnoughMoney(int money) { + if (money < 100) { + throw new IllegalArgumentException(ErrorLog.TOO_LOW_PRICE.getLog()); + } + } + + public static void validateNotZero(int number) { + if (number == 0) { + throw new IllegalArgumentException(ErrorLog.ZERO_NUMBER.getLog()); + } + } +} diff --git a/src/main/java/vendingmachine/Application.java b/src/main/java/vendingmachine/Application.java index 9d3be447b..0a250fb0a 100644 --- a/src/main/java/vendingmachine/Application.java +++ b/src/main/java/vendingmachine/Application.java @@ -1,7 +1,9 @@ package vendingmachine; +import controller.Controller; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + new Controller().control(); } } diff --git a/src/main/java/vendingmachine/Coin.java b/src/main/java/vendingmachine/Coin.java index c76293fbc..6e6237203 100644 --- a/src/main/java/vendingmachine/Coin.java +++ b/src/main/java/vendingmachine/Coin.java @@ -12,5 +12,7 @@ public enum Coin { this.amount = amount; } - // 추가 기능 구현 + public int getAmount() { + return amount; + } } diff --git a/src/main/java/vendingmachine/CoinChanger.java b/src/main/java/vendingmachine/CoinChanger.java new file mode 100644 index 000000000..1324b8d02 --- /dev/null +++ b/src/main/java/vendingmachine/CoinChanger.java @@ -0,0 +1,42 @@ +package vendingmachine; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.stream.Collectors; + +import camp.nextstep.edu.missionutils.Randoms; +import util.Validator; + +public class CoinChanger { + EnumMap coins = new EnumMap<>(Coin.class); + private int holdingSum; + + public CoinChanger(int holdingSum) { + Validator.validateDivisibleByMinimumMonetaryUnit(holdingSum); + this.holdingSum = holdingSum; + } + + public EnumMap changeToCoin() { + init(); + do { + change(); + } while (holdingSum != 0); + return coins; + } + + private void init() { + for (Coin coin : Coin.values()) { + coins.put(coin, 0); + } + } + + private void change() { + int amount = Randoms.pickNumberInList( + Arrays.stream(Coin.values()).mapToInt(Coin::getAmount).boxed().collect(Collectors.toList())); + if (holdingSum >= amount) { + holdingSum -= amount; + coins.forEach(((coin, integer) -> {if (coin.getAmount() == amount) coins.put(coin, integer + 1); + })); + } + } +} diff --git a/src/main/java/vendingmachine/Coins.java b/src/main/java/vendingmachine/Coins.java new file mode 100644 index 000000000..1bb450af9 --- /dev/null +++ b/src/main/java/vendingmachine/Coins.java @@ -0,0 +1,48 @@ +package vendingmachine; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +import dto.CoinsResponseDto; + +public class Coins { + private final EnumMap coins; + + public Coins(EnumMap coins) { + this.coins = coins; + } + + public CoinsResponseDto toCoinsResponseDto() { + HashMap coinsToDto = new HashMap<>(); + coins.forEach((coin, integer) -> coinsToDto.put(coin.getAmount(), integer)); + return new CoinsResponseDto(coinsToDto); + } + + public CoinsResponseDto calculateChanges(int money) { + EnumMap change = new EnumMap<>(Coin.class); + List coins = makeCoins(change); + for (Coin coin : coins) { + int portion = Math.min(this.coins.get(coin), money / coin.getAmount()); + if (portion != 0) { + change.put(coin, portion); + } + money -= coin.getAmount() * portion; + } + return changeToDto(change); + } + + private CoinsResponseDto changeToDto(EnumMap change) { + HashMap coinsToDto = new HashMap<>(); + change.forEach((coin, integer) -> coinsToDto.put(coin.getAmount(), integer)); + return new CoinsResponseDto(coinsToDto); + } + + private List makeCoins(EnumMap change) { + return Arrays.stream(Coin.values()) + .sorted((coin1, coin2) -> coin2.getAmount() - coin1.getAmount()) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/vendingmachine/Money.java b/src/main/java/vendingmachine/Money.java new file mode 100644 index 000000000..526bcd06a --- /dev/null +++ b/src/main/java/vendingmachine/Money.java @@ -0,0 +1,28 @@ +package vendingmachine; + +import dto.MoneyResponseDto; +import util.Validator; + +public class Money { + private int money; + + public Money(int money) { + Validator.validateDivisibleByMinimumMonetaryUnit(money); + this.money = money; + } + + public MoneyResponseDto toMoneyResponseDto() { + return new MoneyResponseDto(money); + } + + public boolean noMoney(int price) { + return money < price; + } + + public void subtract(int price) { + money -= price; + } + public int getMoney() { + return money; + } +} diff --git a/src/main/java/vendingmachine/Products.java b/src/main/java/vendingmachine/Products.java new file mode 100644 index 000000000..04a4b258f --- /dev/null +++ b/src/main/java/vendingmachine/Products.java @@ -0,0 +1,78 @@ +package vendingmachine; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import constant.ErrorLog; +import util.Validator; + +public class Products { + private final HashMap, Integer> products = new HashMap<>(); + + public Products(List productsInfo) { + List> products = new ArrayList<>(); + productsInfo.forEach( + product -> products.add(Validator.validateProductFormSize( + Arrays.stream(product.substring(1, product.length() - 1).split(",")).collect(Collectors.toList())))); + putProductInfo(products); + } + + private void putProductInfo(List> products) { + products.forEach(info -> { + HashMap productInfo = new HashMap<>(); + int price = Integer.parseInt(info.get(1)); + int number = Integer.parseInt(info.get(2)); + validateProductInfo(price, number); + productInfo.put(info.get(0), price); + this.products.put(productInfo, number); + }); + } + + private void validateProductInfo(int price, int number) { + Validator.validateEnoughMoney(price); + Validator.validateDivisibleByMinimumMonetaryUnit(price); + Validator.validateNotZero(number); + } + + public int purchase(String product, int money) { + AtomicInteger price = new AtomicInteger(); + validatePurchasing(product, money); + products.forEach((productInfo, number) -> { + if (productInfo.containsKey(product)) { + Validator.validateNotZero(number); + products.replace(productInfo, number - 1); + price.set(productInfo.get(product)); + } + }); + return price.intValue(); + } + + private void validatePurchasing(String product, int money) { + if (products.keySet().stream().noneMatch(productInfo -> productInfo.containsKey(product))) { + throw new IllegalArgumentException(ErrorLog.NOT_IN_PRODUCT_LIST.getLog()); + } + products.keySet().forEach(info -> { + if (info.containsKey(product) && info.get(product) > money) + throw new IllegalArgumentException(ErrorLog.NOT_ENOUGH_MONEY.getLog()); + }); + } + + public boolean noStock() { + return products.values().stream().allMatch(number -> number == 0); + } + + public int minimumPrice() { + List prices = new ArrayList<>(); + products.keySet().forEach(productInfo -> { + if (products.get(productInfo) != 0) { + prices.add(productInfo.values().stream().iterator().next()); + } + }); + return Collections.min(prices); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 000000000..cc3df6937 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,45 @@ +package view; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import camp.nextstep.edu.missionutils.Console; +import dto.HoldingSumRequestDto; +import dto.MoneyRequestDto; +import dto.MoneyResponseDto; +import dto.ProductNameRequestDto; +import dto.ProductsRequestDto; +import util.Validator; + +public class InputView { + public HoldingSumRequestDto readHolingSum() { + System.out.println(ViewConstant.ASKING_INPUT_HOLDING_SUM); + String holdingSum = Console.readLine(); + Validator.validatePositiveInteger(holdingSum); + return new HoldingSumRequestDto(Integer.parseInt(holdingSum)); + } + + public ProductsRequestDto readProducts() { + System.out.println(); + System.out.println(ViewConstant.ASKING_INPUT_PRODUCT_MESSAGE); + List products = Arrays.stream(Console.readLine().split(";")).collect(Collectors.toList()); + products.forEach(Validator::validateProductForm); + return new ProductsRequestDto(products); + } + + public MoneyRequestDto readMoney() { + System.out.println(); + System.out.println(ViewConstant.ASKING_INPUT_MONEY); + String money = Console.readLine(); + Validator.validatePositiveInteger(money); + return new MoneyRequestDto(Integer.parseInt(money)); + } + + public ProductNameRequestDto readProductName(MoneyResponseDto moneyResponseDto) { + System.out.println(); + System.out.printf(ViewConstant.CURRENT_MONEY, moneyResponseDto.getMoney()); + System.out.println(ViewConstant.ASKING_INPUT_PRODUCT_NAME); + return new ProductNameRequestDto(Console.readLine()); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 000000000..bb8860111 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,28 @@ +package view; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import dto.CoinsResponseDto; +import dto.MoneyResponseDto; + +public class OutputView { + public void printCoins(CoinsResponseDto coinsResponseDto) { + System.out.println(); + System.out.println(ViewConstant.COINS_MESSAGE); + List coins = new ArrayList<>(coinsResponseDto.getCoins().keySet()); + coins.stream() + .sorted(Comparator.reverseOrder()) + .forEach(amount -> System.out.printf(("%d원 - %d개\n"), amount, coinsResponseDto.getCoins().get(amount))); + } + + public void printEnd(MoneyResponseDto moneyResponseDto, CoinsResponseDto coinsResponseDto) { + System.out.printf(ViewConstant.CURRENT_MONEY, moneyResponseDto.getMoney()); + System.out.println(ViewConstant.CHANGE); + List coins = new ArrayList<>(coinsResponseDto.getCoins().keySet()); + coins.stream() + .sorted(Comparator.reverseOrder()) + .forEach(amount -> System.out.printf(("%d원 - %d개\n"), amount, coinsResponseDto.getCoins().get(amount))); + } +} diff --git a/src/main/java/view/ViewConstant.java b/src/main/java/view/ViewConstant.java new file mode 100644 index 000000000..8aae87f19 --- /dev/null +++ b/src/main/java/view/ViewConstant.java @@ -0,0 +1,11 @@ +package view; + +public class ViewConstant { + public static final String ASKING_INPUT_HOLDING_SUM = "자판기가 보유하고 있는 금액을 입력해주세요."; + public static final String COINS_MESSAGE = "자판기가 보유한 동전"; + public static final String ASKING_INPUT_PRODUCT_MESSAGE = "상품명과 가격, 수량을 입력해 주세요."; + public static final String ASKING_INPUT_MONEY = "투입 금액을 입력해 주세요."; + public static final String CURRENT_MONEY = "투입 금액: %d원\n"; + public static final String ASKING_INPUT_PRODUCT_NAME = "구매할 상품명을 입력해 주세요."; + public static final String CHANGE = "잔돈"; +} diff --git a/src/test/java/service/VendingMachineServiceTest.java b/src/test/java/service/VendingMachineServiceTest.java new file mode 100644 index 000000000..9fdb84da2 --- /dev/null +++ b/src/test/java/service/VendingMachineServiceTest.java @@ -0,0 +1,17 @@ +package service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import dto.HoldingSumRequestDto; + +class VendingMachineServiceTest { + + @DisplayName("투입 금액이 10원 단위인지 확인한다.") + @Test + void changeHoldingSumToCoins() { + + } +} \ No newline at end of file diff --git a/src/test/java/util/ValidatorTest.java b/src/test/java/util/ValidatorTest.java new file mode 100644 index 000000000..b31003a73 --- /dev/null +++ b/src/test/java/util/ValidatorTest.java @@ -0,0 +1,14 @@ +package util; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class ValidatorTest { + + @Test + void validateProductForm() { + assertThatThrownBy(() -> Validator.validateProductForm("[d,123,123]")).isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/vendingmachine/CoinChangerTest.java b/src/test/java/vendingmachine/CoinChangerTest.java new file mode 100644 index 000000000..8f3128599 --- /dev/null +++ b/src/test/java/vendingmachine/CoinChangerTest.java @@ -0,0 +1,27 @@ +package vendingmachine; + +import static org.assertj.core.api.Assertions.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CoinChangerTest { + + @DisplayName("보유 금액이 10원 단위가 아닐 경우 예외를 발생한다.") + @Test + void validateMoney() { + assertThatThrownBy(() -> new CoinChanger(5757)).isInstanceOf( + IllegalArgumentException.class); + } + + @DisplayName("보유 금액으로 동전을 랜덤하게 반환한다.") + @Test + void changeToCoins() { + CoinChanger coinChanger = new CoinChanger(1000); + AtomicInteger sum = new AtomicInteger(); + coinChanger.changeToCoin().forEach((coin, integer) -> sum.addAndGet(coin.getAmount() * integer)); + assertThat(sum.intValue()).isEqualTo(1000); + } +} \ No newline at end of file diff --git a/src/test/java/view/InputViewTest.java b/src/test/java/view/InputViewTest.java new file mode 100644 index 000000000..afbb22cd5 --- /dev/null +++ b/src/test/java/view/InputViewTest.java @@ -0,0 +1,13 @@ +package view; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class InputViewTest { + + @Test + void readProducts() { + readProducts(); + } +} \ No newline at end of file