diff --git a/src/main/java/io/suhan/lotto/Main.java b/src/main/java/io/suhan/lotto/Main.java index 5e912401..f25bfe0f 100644 --- a/src/main/java/io/suhan/lotto/Main.java +++ b/src/main/java/io/suhan/lotto/Main.java @@ -1,6 +1,6 @@ package io.suhan.lotto; -import io.suhan.lotto.model.lotto.LottoController; +import io.suhan.lotto.controller.LottoController; public class Main { public static void main(String[] args) { diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoController.java b/src/main/java/io/suhan/lotto/controller/LottoController.java similarity index 57% rename from src/main/java/io/suhan/lotto/model/lotto/LottoController.java rename to src/main/java/io/suhan/lotto/controller/LottoController.java index a2120886..ec42c126 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/LottoController.java +++ b/src/main/java/io/suhan/lotto/controller/LottoController.java @@ -1,11 +1,17 @@ -package io.suhan.lotto.model.lotto; +package io.suhan.lotto.controller; + +import static io.suhan.lotto.model.executor.PurchaseExecutor.PRICE_PER_LOTTO; import io.suhan.lotto.model.executor.DrawExecutor; import io.suhan.lotto.model.executor.PurchaseExecutor; +import io.suhan.lotto.model.lotto.Lotto; +import io.suhan.lotto.model.lotto.LottoFactory; +import io.suhan.lotto.model.lotto.LottoNumber; +import io.suhan.lotto.model.lotto.LottoRegistry; +import io.suhan.lotto.model.lotto.LottoStatistics; import io.suhan.lotto.view.InputView; import io.suhan.lotto.view.OutputView; import java.util.Set; -import java.util.stream.Collectors; public class LottoController { private final LottoRegistry registry; @@ -16,7 +22,7 @@ public LottoController() { public void run() { try { - int balance = InputView.getBalance(); + int balance = InputView.getValidBalance(); executePurchase(balance); executeDraw(balance); @@ -26,7 +32,13 @@ public void run() { } private void executePurchase(int balance) { - PurchaseExecutor purchaseExecutor = new PurchaseExecutor(registry, balance); + int manualCount = InputView.getValidManualCount(); + + if (PRICE_PER_LOTTO * manualCount > balance) { + throw new IllegalArgumentException("금액이 부족합니다."); + } + + PurchaseExecutor purchaseExecutor = new PurchaseExecutor(registry, balance, manualCount); purchaseExecutor.execute(); OutputView.printPurchaseResult(registry.getLottos()); @@ -35,7 +47,9 @@ private void executePurchase(int balance) { private void executeDraw(int balance) { Lotto winningLotto = createWinningLotto(); - DrawExecutor drawExecutor = new DrawExecutor(registry, winningLotto); + LottoNumber bonusNumber = InputView.getValidBonusNumber(); + + DrawExecutor drawExecutor = new DrawExecutor(registry, winningLotto, bonusNumber); drawExecutor.execute(); LottoStatistics statistics = new LottoStatistics(drawExecutor.getResults()); @@ -44,11 +58,8 @@ private void executeDraw(int balance) { } private Lotto createWinningLotto() { - Set wonNumbers = InputView.getWonNumbers() - .stream() - .map(LottoNumber::new) - .collect(Collectors.toSet()); + Set wonNumbers = LottoFactory.toLottoNumbers(InputView.getValidWonNumbers()); - return new Lotto(wonNumbers); + return Lotto.of(wonNumbers); } } diff --git a/src/main/java/io/suhan/lotto/model/DrawResult.java b/src/main/java/io/suhan/lotto/model/DrawResult.java index 98d5875d..d234dbd5 100644 --- a/src/main/java/io/suhan/lotto/model/DrawResult.java +++ b/src/main/java/io/suhan/lotto/model/DrawResult.java @@ -2,16 +2,22 @@ public class DrawResult { private final int matchedCount; + private final Rank rank; - private DrawResult(int matchedCount) { + private DrawResult(int matchedCount, boolean bonusMatched) { this.matchedCount = matchedCount; + this.rank = Rank.of(matchedCount, bonusMatched); } - public static DrawResult of(int matchedCount) { - return new DrawResult(matchedCount); + public static DrawResult of(int matchedCount, boolean bonusMatched) { + return new DrawResult(matchedCount, bonusMatched); } public int getMatchedCount() { return matchedCount; } + + public Rank getRank() { + return rank; + } } diff --git a/src/main/java/io/suhan/lotto/model/NumberPool.java b/src/main/java/io/suhan/lotto/model/NumberPool.java index cccbafcf..32b82b2f 100644 --- a/src/main/java/io/suhan/lotto/model/NumberPool.java +++ b/src/main/java/io/suhan/lotto/model/NumberPool.java @@ -2,6 +2,7 @@ import io.suhan.lotto.model.lotto.Lotto; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class NumberPool { @@ -39,6 +40,6 @@ private List generateNumbersInRange(int from, int to) { } public List getNumbers() { - return numbers; + return Collections.unmodifiableList(numbers); } } diff --git a/src/main/java/io/suhan/lotto/model/Rank.java b/src/main/java/io/suhan/lotto/model/Rank.java new file mode 100644 index 00000000..b00f1d31 --- /dev/null +++ b/src/main/java/io/suhan/lotto/model/Rank.java @@ -0,0 +1,48 @@ +package io.suhan.lotto.model; + +import java.util.Arrays; + +public enum Rank { + FIRST(6, false, 2000000000, "6개 일치"), + SECOND(5, true, 30000000, "5개 일치, 보너스 볼 일치"), + THIRD(5, false, 1500000, "5개 일치"), + FOURTH(4, false, 50000, "4개 일치"), + FIFTH(3, false, 5000, "3개 일치"), + NONE(0, false, 0, ""); // fallback + + private final int matchedCount; + private final boolean bonusRequired; + private final int prize; + private final String description; + + Rank(int matchedCount, boolean bonusRequired, int prize, String description) { + this.matchedCount = matchedCount; + this.bonusRequired = bonusRequired; + this.prize = prize; + this.description = description; + } + + public static Rank of(int matchedCount, boolean bonusMatched) { + return Arrays.stream(Rank.values()) + .filter((rank) -> rank.getMatchedCount() == matchedCount) + .filter((rank) -> rank.isBonusRequired() == bonusMatched) + .findFirst() + .orElse(Rank.NONE); + } + + public int getMatchedCount() { + return matchedCount; + } + + public boolean isBonusRequired() { + return bonusRequired; + } + + public int getPrize() { + return prize; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/io/suhan/lotto/model/executor/DrawExecutor.java b/src/main/java/io/suhan/lotto/model/executor/DrawExecutor.java index 30644164..3be35276 100644 --- a/src/main/java/io/suhan/lotto/model/executor/DrawExecutor.java +++ b/src/main/java/io/suhan/lotto/model/executor/DrawExecutor.java @@ -12,19 +12,26 @@ public class DrawExecutor implements Executor { private final LottoRegistry registry; private final Lotto winningLotto; + private final LottoNumber bonusNumber; private final List results; - public DrawExecutor(LottoRegistry registry, Lotto winningLotto) { + public DrawExecutor(LottoRegistry registry, Lotto winningLotto, LottoNumber bonusNumber) { this.registry = registry; this.winningLotto = winningLotto; + this.bonusNumber = bonusNumber; this.results = new ArrayList<>(); } @Override public void execute() { + if (winningLotto.getNumbers().contains(bonusNumber)) { + throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다."); + } + for (Lotto lotto : registry.getLottos()) { int matchedCount = calculateMatchedCount(lotto, winningLotto); - results.add(DrawResult.of(matchedCount)); + boolean bonusMatched = isBonusMatched(matchedCount, lotto); + results.add(DrawResult.of(matchedCount, bonusMatched)); } } @@ -35,6 +42,14 @@ private int calculateMatchedCount(Lotto lotto, Lotto winningLotto) { return numbers.size(); } + private boolean isBonusMatched(int matchedCount, Lotto lotto) { + if (matchedCount != Lotto.LOTTO_SIZE - 1) { + return false; + } + + return lotto.getNumbers().contains(bonusNumber); + } + public List getResults() { return results; } diff --git a/src/main/java/io/suhan/lotto/model/executor/PurchaseExecutor.java b/src/main/java/io/suhan/lotto/model/executor/PurchaseExecutor.java index d8815ccf..1cf1ab49 100644 --- a/src/main/java/io/suhan/lotto/model/executor/PurchaseExecutor.java +++ b/src/main/java/io/suhan/lotto/model/executor/PurchaseExecutor.java @@ -1,25 +1,47 @@ package io.suhan.lotto.model.executor; +import io.suhan.lotto.model.lotto.Lotto; import io.suhan.lotto.model.lotto.LottoFactory; import io.suhan.lotto.model.lotto.LottoRegistry; +import io.suhan.lotto.model.lotto.LottoType; +import io.suhan.lotto.view.InputView; +import java.util.List; +import java.util.Set; public class PurchaseExecutor implements Executor { public static final int PRICE_PER_LOTTO = 1000; private final LottoRegistry registry; - private final int balance; + private int balance; + private final int manualCount; - public PurchaseExecutor(LottoRegistry registry, int balance) { + public PurchaseExecutor(LottoRegistry registry, int balance, int manualCount) { this.registry = registry; this.balance = balance; + this.manualCount = manualCount; } @Override public void execute() { - int count = getAvailableCount(balance); + if (manualCount > 0) { + purchaseManualNumbers(); + } + + int autoCount = getAvailableCount(balance); + + for (int i = 0; i < autoCount; i++) { + registry.add(LottoFactory.createLotto(LottoType.AUTOMATIC)); + } + } + + private void purchaseManualNumbers() { + List> manualNumbersList = InputView.getValidManualNumbers(manualCount); + + for (Set numbers : manualNumbersList) { + Lotto lotto = Lotto.of(LottoType.MANUAL, LottoFactory.toLottoNumbers(numbers)); - for (int i = 0; i < count; i++) { - registry.add(LottoFactory.createLotto()); + registry.add(lotto); + balance -= PRICE_PER_LOTTO; } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/Lotto.java b/src/main/java/io/suhan/lotto/model/lotto/Lotto.java index 66314e87..84a6e894 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/Lotto.java +++ b/src/main/java/io/suhan/lotto/model/lotto/Lotto.java @@ -1,5 +1,6 @@ package io.suhan.lotto.model.lotto; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Set; @@ -9,22 +10,36 @@ public class Lotto { public static final int LOTTO_NUMBER_MIN = 1; public static final int LOTTO_NUMBER_MAX = 45; + private final LottoType type; private final Set numbers; - public Lotto(Set numbers) { + private Lotto(LottoType type, Set numbers) { if (numbers.size() != LOTTO_SIZE) { throw new IllegalArgumentException("로또 번호는 " + LOTTO_SIZE + "개여야 합니다."); } + this.type = type; this.numbers = new HashSet<>(numbers); } + public static Lotto of(Set numbers) { + return new Lotto(LottoType.AUTOMATIC, numbers); + } + + public static Lotto of(LottoType type, Set numbers) { + return new Lotto(type, numbers); + } + @Override public String toString() { - return numbers.stream().sorted(Comparator.comparingInt(LottoNumber::getValue)).toList().toString(); + return numbers.stream().sorted(Comparator.comparingInt(LottoNumber::value)).toList().toString(); + } + + public LottoType getType() { + return type; } public Set getNumbers() { - return numbers; + return Collections.unmodifiableSet(numbers); } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoFactory.java b/src/main/java/io/suhan/lotto/model/lotto/LottoFactory.java index 2b506878..c439efa9 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/LottoFactory.java +++ b/src/main/java/io/suhan/lotto/model/lotto/LottoFactory.java @@ -3,18 +3,17 @@ import io.suhan.lotto.model.NumberPool; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class LottoFactory { - public static Lotto createLotto() { + public static Lotto createLotto(LottoType type) { NumberPool pool = NumberPool.of(Lotto.LOTTO_NUMBER_MIN, Lotto.LOTTO_NUMBER_MAX); - return createLotto(pool); + return createLotto(type, pool); } - private static Lotto createLotto(NumberPool pool) { + public static Lotto createLotto(LottoType type, NumberPool pool) { List poolNumbers = new ArrayList<>(pool.getNumbers()); // copy Collections.shuffle(poolNumbers); @@ -23,6 +22,16 @@ private static Lotto createLotto(NumberPool pool) { .map(LottoNumber::new) .collect(Collectors.toSet()); - return new Lotto(numbers); + return Lotto.of(type, numbers); + } + + public static Set toLottoNumbers(Set numbers) { + return numbers.stream() + .map(LottoNumber::new) + .collect(Collectors.toSet()); + } + + public static int getManualLottosCount(List lottos) { + return lottos.stream().filter((lotto) -> lotto.getType() == LottoType.MANUAL).toList().size(); } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoNumber.java b/src/main/java/io/suhan/lotto/model/lotto/LottoNumber.java index 605bf203..e7d53da9 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/LottoNumber.java +++ b/src/main/java/io/suhan/lotto/model/lotto/LottoNumber.java @@ -1,34 +1,14 @@ package io.suhan.lotto.model.lotto; -public class LottoNumber { - private final int value; - - public LottoNumber(int value) { +public record LottoNumber(int value) { + public LottoNumber { if (value < Lotto.LOTTO_NUMBER_MIN || value > Lotto.LOTTO_NUMBER_MAX) { throw new IllegalArgumentException("로또 번호는 " + Lotto.LOTTO_NUMBER_MIN + "~" + Lotto.LOTTO_NUMBER_MAX + " 사이여야 합니다."); } - - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof LottoNumber number)) return false; - return value == number.value; - } - - @Override - public int hashCode() { - return Integer.hashCode(value); } @Override public String toString() { return String.valueOf(value); } - - public int getValue() { - return value; - } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoRegistry.java b/src/main/java/io/suhan/lotto/model/lotto/LottoRegistry.java index 141fe029..c50a26c8 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/LottoRegistry.java +++ b/src/main/java/io/suhan/lotto/model/lotto/LottoRegistry.java @@ -1,6 +1,7 @@ package io.suhan.lotto.model.lotto; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class LottoRegistry { @@ -15,6 +16,6 @@ public void add(Lotto lotto) { } public List getLottos() { - return lottos; + return Collections.unmodifiableList(lottos); } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoStatistics.java b/src/main/java/io/suhan/lotto/model/lotto/LottoStatistics.java index 611e45fe..9268743f 100644 --- a/src/main/java/io/suhan/lotto/model/lotto/LottoStatistics.java +++ b/src/main/java/io/suhan/lotto/model/lotto/LottoStatistics.java @@ -1,23 +1,18 @@ package io.suhan.lotto.model.lotto; import io.suhan.lotto.model.DrawResult; +import io.suhan.lotto.model.Rank; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class LottoStatistics { - private static final Map winningsMap = Map.of( - 3, 5000, - 4, 50000, - 5, 1500000, - 6, 2000000000 - ); - - private final Map countMap; + private final Map countMap; private final long totalWinnings; public LottoStatistics(List results) { - this.countMap = calculateMatchedCounts(results); + this.countMap = calculateRankCounts(results); this.totalWinnings = calculateTotalWinnings(); } @@ -25,12 +20,12 @@ public double calculateRevenue(int totalSpent) { return (double) totalWinnings / totalSpent; } - private Map calculateMatchedCounts(List results) { - Map map = new HashMap<>(); + private Map calculateRankCounts(List results) { + Map map = new HashMap<>(); for (DrawResult result : results) { - int matchedCount = result.getMatchedCount(); - map.put(matchedCount, map.getOrDefault(matchedCount, 0L) + 1); + Rank rank = result.getRank(); + map.put(rank, map.getOrDefault(rank, 0L) + 1); } return map; @@ -39,21 +34,14 @@ private Map calculateMatchedCounts(List results) { private long calculateTotalWinnings() { long sum = 0; - for (Map.Entry entry : countMap.entrySet()) { - int matchedCount = entry.getKey(); - long count = entry.getValue(); - - sum += winningsMap.getOrDefault(matchedCount, 0) * count; + for (Map.Entry entry : countMap.entrySet()) { + sum += entry.getKey().getPrize() * entry.getValue(); } return sum; } - public Map getWinningsMap() { - return winningsMap; - } - - public Map getCountMap() { - return countMap; + public Map getCountMap() { + return Collections.unmodifiableMap(countMap); } } diff --git a/src/main/java/io/suhan/lotto/model/lotto/LottoType.java b/src/main/java/io/suhan/lotto/model/lotto/LottoType.java new file mode 100644 index 00000000..197e061d --- /dev/null +++ b/src/main/java/io/suhan/lotto/model/lotto/LottoType.java @@ -0,0 +1,6 @@ +package io.suhan.lotto.model.lotto; + +public enum LottoType { + MANUAL, + AUTOMATIC; +} diff --git a/src/main/java/io/suhan/lotto/view/InputView.java b/src/main/java/io/suhan/lotto/view/InputView.java index 8e3e4d54..a8e854c8 100644 --- a/src/main/java/io/suhan/lotto/view/InputView.java +++ b/src/main/java/io/suhan/lotto/view/InputView.java @@ -1,12 +1,19 @@ package io.suhan.lotto.view; +import static io.suhan.lotto.model.executor.PurchaseExecutor.PRICE_PER_LOTTO; +import static io.suhan.lotto.model.lotto.Lotto.LOTTO_SIZE; + +import io.suhan.lotto.model.lotto.LottoNumber; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Scanner; import java.util.Set; import java.util.stream.Collectors; public class InputView { private static final Scanner scanner = new Scanner(System.in); + private static final String INPUT_DELIMITER = ","; public static int getBalance() { System.out.println("구입할 금액을 입력해주세요."); @@ -17,8 +24,105 @@ public static int getBalance() { public static Set getWonNumbers() { System.out.println("\n지난 주 당첨 번호를 입력해 주세요."); - return Arrays.stream(scanner.next().split(",")) + return parseNumbers(scanner.next()); + } + + public static int getBonusNumber() { + System.out.println("\n보너스 볼을 입력해주세요."); + + return scanner.nextInt(); + } + + public static int getManualCount() { + System.out.println("\n수동으로 구매할 로또 수를 입력해주세요."); + + return scanner.nextInt(); + } + + public static List> getManualNumbers(int count) { + System.out.println("\n수동으로 구매할 번호를 입력해 주세요."); + List> numbers = new ArrayList<>(); + + for (int i = 0; i < count; i++) { + numbers.add(parseNumbers(scanner.next())); + } + + return numbers; + } + + public static int getValidBalance() { + while (true) { + try { + int balance = getBalance(); + + if (balance < PRICE_PER_LOTTO) { + throw new IllegalArgumentException("금액은 " + PRICE_PER_LOTTO + "원 보다 크거나 같아야 합니다."); + } + + return balance; + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + public static Set getValidWonNumbers() { + while (true) { + try { + return getWonNumbers(); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + public static LottoNumber getValidBonusNumber() { + while (true) { + try { + int number = getBonusNumber(); + + return new LottoNumber(number); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + public static int getValidManualCount() { + while (true) { + try { + int manualCount = InputView.getManualCount(); + + if (manualCount < 0) { + throw new IllegalArgumentException("로또 수는 0 또는 양수만 입력할 수 있습니다."); + } + + return manualCount; + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + public static List> getValidManualNumbers(int count) { + while (true) { + try { + return getManualNumbers(count); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + } + + private static Set parseNumbers(String input) { + Set numbers = Arrays.stream(input.split(INPUT_DELIMITER)) .map(Integer::parseInt) .collect(Collectors.toSet()); + + if (numbers.size() != LOTTO_SIZE) { + throw new IllegalArgumentException("로또 번호는 " + LOTTO_SIZE + "개여야 합니다."); + } + + return numbers; } } diff --git a/src/main/java/io/suhan/lotto/view/OutputView.java b/src/main/java/io/suhan/lotto/view/OutputView.java index 28780cde..889a5258 100644 --- a/src/main/java/io/suhan/lotto/view/OutputView.java +++ b/src/main/java/io/suhan/lotto/view/OutputView.java @@ -1,26 +1,36 @@ package io.suhan.lotto.view; +import io.suhan.lotto.model.Rank; import io.suhan.lotto.model.lotto.Lotto; +import io.suhan.lotto.model.lotto.LottoFactory; import io.suhan.lotto.model.lotto.LottoStatistics; import java.util.List; public class OutputView { public static void printPurchaseResult(List lottos) { - System.out.println("\n" + lottos.size() + "개를 구매했습니다."); + int manualCount = LottoFactory.getManualLottosCount(lottos); + int autoCount = lottos.size() - manualCount; + + System.out.println("\n수동으로 " + manualCount + "장, 자동으로 " + autoCount + "장을 구매했습니다."); printLottos(lottos); } public static void printStatistics(LottoStatistics statistics, int totalSpent) { - System.out.println("\n당첨 통계"); System.out.println("---------"); - // 3개 ~ 6개 일치 - for (int i = 3; i <= 6; i++) { - long count = statistics.getCountMap().getOrDefault(i, 0L); - int winnings = statistics.getWinningsMap().get(i); + Rank[] ranks = Rank.values(); + + // print in reverse order + for (int i = ranks.length - 1; i >= 0; i--) { + Rank rank = ranks[i]; + + if (rank == Rank.NONE) { + continue; + } - System.out.printf("%d개 일치 (%d원)- %d개\n", i, winnings, count); + long count = statistics.getCountMap().getOrDefault(rank, 0L); + System.out.printf("%s (%d원)- %d개\n", rank.getDescription(), rank.getPrize(), count); } double revenue = statistics.calculateRevenue(totalSpent); diff --git a/src/test/java/io/suhan/lotto/model/NumberPoolTest.java b/src/test/java/io/suhan/lotto/model/NumberPoolTest.java index 320782ac..23145ac5 100644 --- a/src/test/java/io/suhan/lotto/model/NumberPoolTest.java +++ b/src/test/java/io/suhan/lotto/model/NumberPoolTest.java @@ -13,25 +13,39 @@ public class NumberPoolTest { @Test void 특정_범위를_가진_Pool을_생성할_수_있다() { - NumberPool pool = NumberPool.of(1, 10); + // given + int from = 1; + int to = 10; - assertThat(pool.getNumbers()).hasSize(10); + // when + NumberPool pool = NumberPool.of(from, to); + + // then + assertThat(pool.getNumbers()).hasSize(to - from + 1); } @Test void from은_to보다_클_수_없다() { + // given + int from = 2; + int to = 1; String expectedMessage = "from 값은 to 값보다 작아야 합니다."; - assertThatThrownBy(() -> NumberPool.of(2, 1)) + // when and then + assertThatThrownBy(() -> NumberPool.of(from, to)) .isInstanceOf(IllegalArgumentException.class) .hasMessage(expectedMessage); } @Test void 범위의_크기는_LOTTO_SIZE보다_커야_한다() { + // given + int from = Lotto.LOTTO_NUMBER_MIN; + int to = Lotto.LOTTO_NUMBER_MIN + Lotto.LOTTO_SIZE - 2; String expectedMessage = "범위의 크기는 " + Lotto.LOTTO_SIZE + " 보다 커야 합니다."; - assertThatThrownBy(() -> NumberPool.of(Lotto.LOTTO_NUMBER_MIN, Lotto.LOTTO_NUMBER_MIN + Lotto.LOTTO_SIZE - 2)) + // when and then + assertThatThrownBy(() -> NumberPool.of(from, to)) .isInstanceOf(IllegalArgumentException.class) .hasMessage(expectedMessage); } diff --git a/src/test/java/io/suhan/lotto/model/executor/DrawExecutorTest.java b/src/test/java/io/suhan/lotto/model/executor/DrawExecutorTest.java index 03f9914b..0ce230c9 100644 --- a/src/test/java/io/suhan/lotto/model/executor/DrawExecutorTest.java +++ b/src/test/java/io/suhan/lotto/model/executor/DrawExecutorTest.java @@ -1,11 +1,17 @@ package io.suhan.lotto.model.executor; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + import io.suhan.lotto.model.DrawResult; import io.suhan.lotto.model.lotto.Lotto; import io.suhan.lotto.model.lotto.LottoFactory; +import io.suhan.lotto.model.lotto.LottoNumber; import io.suhan.lotto.model.lotto.LottoRegistry; +import io.suhan.lotto.model.lotto.LottoType; import java.util.List; +import java.util.Set; import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; @@ -13,21 +19,48 @@ @SuppressWarnings("NonAsciiCharacters") @DisplayNameGeneration(ReplaceUnderscores.class) public class DrawExecutorTest { + private LottoRegistry registry; + private Lotto winningLotto; + + @BeforeEach + void setUp() { + registry = new LottoRegistry(); + Set numbers = Set.of( + new LottoNumber(1), new LottoNumber(2), new LottoNumber(3), + new LottoNumber(4), new LottoNumber(5), new LottoNumber(6) + ); + winningLotto = Lotto.of(numbers); + } + @Test void 당첨번호와_로또를_비교할_수_있다() { - LottoRegistry registry = new LottoRegistry(); - - Lotto winningLotto = LottoFactory.createLotto(); + // given registry.add(winningLotto); + LottoNumber bonusNumber = new LottoNumber(7); + DrawExecutor executor = new DrawExecutor(registry, winningLotto, bonusNumber); - DrawExecutor executor = new DrawExecutor(registry, winningLotto); + // when executor.execute(); - List results = executor.getResults(); + // then SoftAssertions.assertSoftly((softly) -> { softly.assertThat(results).hasSize(1); softly.assertThat(results.get(0).getMatchedCount()).isEqualTo(Lotto.LOTTO_SIZE); }); } + + @Test + void 보너스_번호는_당첨번호와_중복될_수_없다() { + // given + Lotto lotto = LottoFactory.createLotto(LottoType.AUTOMATIC); + registry.add(lotto); + LottoNumber bonusNumber = new LottoNumber(6); + + // when and then + assertThatThrownBy(() -> { + DrawExecutor executor = new DrawExecutor(registry, winningLotto, bonusNumber); + executor.execute(); + }).isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/io/suhan/lotto/model/executor/PurchaseExecutorTest.java b/src/test/java/io/suhan/lotto/model/executor/PurchaseExecutorTest.java index 822482ad..a162a99b 100644 --- a/src/test/java/io/suhan/lotto/model/executor/PurchaseExecutorTest.java +++ b/src/test/java/io/suhan/lotto/model/executor/PurchaseExecutorTest.java @@ -13,13 +13,17 @@ public class PurchaseExecutorTest { @Test void 금액에_맞는_로또를_구매할_수_있다() { + // given LottoRegistry registry = new LottoRegistry(); - int balance = 5000; + int count = 5; + int balance = PRICE_PER_LOTTO * count; - PurchaseExecutor executor = new PurchaseExecutor(registry, balance); + PurchaseExecutor executor = new PurchaseExecutor(registry, balance, 0); + + // when executor.execute(); - int expectedSize = balance / PRICE_PER_LOTTO; - assertThat(registry.getLottos()).hasSize(expectedSize); + // then + assertThat(registry.getLottos()).hasSize(count); } } diff --git a/src/test/java/io/suhan/lotto/model/lotto/LottoNumberTest.java b/src/test/java/io/suhan/lotto/model/lotto/LottoNumberTest.java index 46f18e54..913b600c 100644 --- a/src/test/java/io/suhan/lotto/model/lotto/LottoNumberTest.java +++ b/src/test/java/io/suhan/lotto/model/lotto/LottoNumberTest.java @@ -12,15 +12,22 @@ public class LottoNumberTest { @Test void 유효한_번호를_생성할_수_있다() { - LottoNumber number = new LottoNumber(Lotto.LOTTO_NUMBER_MIN); + // given + int validNumber = Lotto.LOTTO_NUMBER_MIN; - assertThat(Lotto.LOTTO_NUMBER_MIN).isEqualTo(number.getValue()); + // when + LottoNumber lottoNumber = new LottoNumber(validNumber); + + // then + assertThat(lottoNumber.value()).isEqualTo(validNumber); } @Test void 번호는_범위를_벗어날_수_없다() { + // given String expectedMessage = "로또 번호는 " + Lotto.LOTTO_NUMBER_MIN + "~" + Lotto.LOTTO_NUMBER_MAX + " 사이여야 합니다."; + // when and then SoftAssertions.assertSoftly((softly) -> { softly.assertThatThrownBy(() -> new LottoNumber(Lotto.LOTTO_NUMBER_MIN - 1)) .isInstanceOf(IllegalArgumentException.class) diff --git a/src/test/java/io/suhan/lotto/model/lotto/LottoTest.java b/src/test/java/io/suhan/lotto/model/lotto/LottoTest.java index ea435a5d..529dfcd7 100644 --- a/src/test/java/io/suhan/lotto/model/lotto/LottoTest.java +++ b/src/test/java/io/suhan/lotto/model/lotto/LottoTest.java @@ -11,14 +11,14 @@ public class LottoTest { @Test void 로또는_6개의_숫자를_가진다() { - Lotto lotto = LottoFactory.createLotto(); + Lotto lotto = LottoFactory.createLotto(LottoType.AUTOMATIC); assertThat(lotto.getNumbers()).hasSize(Lotto.LOTTO_SIZE); } @Test void 로또는_중복된_숫자를_가질_수_없다() { - Lotto lotto = LottoFactory.createLotto(); + Lotto lotto = LottoFactory.createLotto(LottoType.AUTOMATIC); assertThat(lotto.getNumbers()).doesNotHaveDuplicates(); }