diff --git a/README.md b/README.md new file mode 100644 index 00000000..fcd17d8f --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +## Lotto + +- 크기가 6인 int List : numbers + - [x] 1 ~ 45 사이의 숫자 + - [x] 중복되지 않아야 함 + - [x] 크기가 6이어야 함 + +- [x] 로또 금액을 입력 받아야 함 +- [x] 1000원 단위로 입력 +- [x] 최소 1000원 이상 +- [x] 로또 번호는 랜덤으로 설정 +- [x] 숫자들끼리 중복되지 않도록 +- [x] 1 ~ 45 사이 +- [x] 출력 시 숫자들이 오름차순으로 정렬 + +- [x] 당첨 번호를 입력 받는다 +- 당첨 결과를 계산한다. + - [x] 일치한 개수에 따라 순위와 당첨금이 결정된다. + - [x] 수익률을 계산한다 +- [x] 당첨 통계를 출력한다. diff --git a/src/main/java/LottoApplication.java b/src/main/java/LottoApplication.java new file mode 100644 index 00000000..ec24db46 --- /dev/null +++ b/src/main/java/LottoApplication.java @@ -0,0 +1,13 @@ +import model.LottoGame; +import view.InputView; +import view.OutputView; + +public class LottoApplication { + + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + LottoGame lottoGame = new LottoGame(inputView, outputView); + lottoGame.run(); + } +} diff --git a/src/main/java/model/Lotto.java b/src/main/java/model/Lotto.java new file mode 100644 index 00000000..4e694b47 --- /dev/null +++ b/src/main/java/model/Lotto.java @@ -0,0 +1,47 @@ +package model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record Lotto(List numbers) { + + public static final int LOTTO_SIZE = 6; + + public Lotto(List numbers) { + validate(numbers); + List modifiable = new ArrayList<>(numbers); + Collections.sort(modifiable); + this.numbers = modifiable; + } + + public static Lotto from(List numbers) { + List lottoNumbers = numbers.stream() + .map(LottoNumber::new) + .toList(); + return new Lotto(lottoNumbers); + } + + private void validate(List numbers) { + validateSize(numbers); + validateDuplication(numbers); + } + + private void validateSize(List numbers) { + if (numbers.size() != LOTTO_SIZE) { + throw new IllegalArgumentException("로또는 6개의 숫자로 이루어져야 합니다."); + } + } + + private void validateDuplication(List numbers) { + long duplicatedSize = numbers.stream().distinct().count(); + if (numbers.size() != duplicatedSize) { + throw new IllegalArgumentException("로또는 중복되지 않는 6개의 숫자로 이루어져야 합니다."); + } + } + + @Override + public List numbers() { + return List.copyOf(numbers); + } +} diff --git a/src/main/java/model/LottoGame.java b/src/main/java/model/LottoGame.java new file mode 100644 index 00000000..95c59941 --- /dev/null +++ b/src/main/java/model/LottoGame.java @@ -0,0 +1,80 @@ +package model; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import view.InputView; +import view.OutputView; +import view.dto.LottoResponse; +import view.dto.LottoStatisticsResponse; + +public class LottoGame { + + private final InputView inputView; + private final OutputView outputView; + + public LottoGame(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + LottoPrice price = LottoPrice.valueOf(inputView.readLottoPrice()); + int lottoAmount = price.divideByUnit(); + final int manualLottoCount = inputView.readManualLottoCount(); + final int automaticLottoCount = lottoAmount - manualLottoCount; + + if (lottoAmount < manualLottoCount) { + throw new IllegalArgumentException("로또 구매 금액이 부족합니다."); + } + + List lottos = publishLotto(manualLottoCount, automaticLottoCount); + printPublishedResult(lottos, manualLottoCount, automaticLottoCount); + + WinningLotto winningLotto = readWinningLotto(); + + ResultStatistics resultStatistics = calculateResultStatistics(lottos, winningLotto); + LottoStatisticsResponse response = LottoStatisticsResponse.from(resultStatistics); + outputView.printResultStatistics(response); + } + + private List publishLotto(int manualLottoCount, int automaticLottoCount) { + List lottos = new ArrayList<>(); + + inputView.readManualLottoNumbers(manualLottoCount).stream() + .map(manualLottoNumber -> { + List numbers = Stream.of(manualLottoNumber.replace(" ", "").split(",")) + .map(Integer::parseInt) + .toList(); + return Lotto.from(numbers); + }) + .forEach(lottos::add); + + IntStream.range(0, automaticLottoCount) + .mapToObj(i -> RandomLottoGenerator.generateLotto()) + .forEach(lottos::add); + + return lottos; + } + + private void printPublishedResult(List lottos, int manualLottoCount, int automaticLottoCount) { + List results = lottos.stream().map(LottoResponse::from).toList(); + outputView.printLotto(results, manualLottoCount, automaticLottoCount); + } + + private WinningLotto readWinningLotto() { + List winningNumbers = inputView.readWinningNumbers().stream() + .map(LottoNumber::valueOf) + .toList(); + final LottoNumber bonusNumber = new LottoNumber(inputView.readBonusNumber()); + return new WinningLotto(new Lotto(winningNumbers), bonusNumber); + } + + private ResultStatistics calculateResultStatistics(List lottos, WinningLotto winningLotto) { + List ranks = lottos.stream() + .map(winningLotto::match) + .toList(); + return ResultStatistics.from(ranks); + } +} diff --git a/src/main/java/model/LottoNumber.java b/src/main/java/model/LottoNumber.java new file mode 100644 index 00000000..f0826f52 --- /dev/null +++ b/src/main/java/model/LottoNumber.java @@ -0,0 +1,30 @@ +package model; + +public record LottoNumber(int number) implements Comparable { + + public static final int MIN_VALUE = 1; + public static final int MAX_VALUE = 45; + + public LottoNumber { + validateRange(number); + } + + public static LottoNumber valueOf(String number) { + try { + return new LottoNumber(Integer.parseInt(number)); + } catch (NumberFormatException exception) { + throw new IllegalArgumentException("로또 번호는 숫자여야 합니다."); + } + } + + private void validateRange(int number) { + if (number < MIN_VALUE || number > MAX_VALUE) { + throw new IllegalArgumentException("로또 번호는 1부터 45 사이여야 합니다."); + } + } + + @Override + public int compareTo(LottoNumber other) { + return Integer.compare(number, other.number); + } +} diff --git a/src/main/java/model/LottoPrice.java b/src/main/java/model/LottoPrice.java new file mode 100644 index 00000000..c3514ccc --- /dev/null +++ b/src/main/java/model/LottoPrice.java @@ -0,0 +1,40 @@ +package model; + +public record LottoPrice(int price) { + + public static final int MIN_PRICE = 0; + public static final int PRICE_UNIT = 1_000; + + public LottoPrice { + validate(price); + } + + public static LottoPrice valueOf(String price) { + try { + return new LottoPrice(Integer.parseInt(price)); + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException("로또 금액은 숫자여야 합니다."); + } + } + + private void validate(int price) { + validateRange(price); + validateUnit(price); + } + + private void validateRange(int price) { + if (price < MIN_PRICE) { + throw new IllegalArgumentException("로또 금액은 0원 보다 작을 수 없습니다."); + } + } + + private void validateUnit(int price) { + if (price % PRICE_UNIT != 0) { + throw new IllegalArgumentException("로또 금액은 1000원 단위여야 합니다."); + } + } + + public int divideByUnit() { + return price() / PRICE_UNIT; + } +} diff --git a/src/main/java/model/RandomLottoGenerator.java b/src/main/java/model/RandomLottoGenerator.java new file mode 100644 index 00000000..01d311ea --- /dev/null +++ b/src/main/java/model/RandomLottoGenerator.java @@ -0,0 +1,24 @@ +package model; + +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class RandomLottoGenerator { + + public static final Random RANDOM = new Random(); + + public static Lotto generateLotto() { + Set numbers = new HashSet<>(); + while (numbers.size() < Lotto.LOTTO_SIZE) { + int randomNumber = RANDOM.nextInt(LottoNumber.MIN_VALUE, LottoNumber.MAX_VALUE); + numbers.add(randomNumber); + } + + List lottoNumbers = numbers.stream() + .map(LottoNumber::new) + .toList(); + return new Lotto(lottoNumbers); + } +} diff --git a/src/main/java/model/Rank.java b/src/main/java/model/Rank.java new file mode 100644 index 00000000..48ed7f69 --- /dev/null +++ b/src/main/java/model/Rank.java @@ -0,0 +1,44 @@ +package model; + +import java.util.Arrays; + +public enum Rank { + + _LAST_PRIZE(0, false, 0), + _5TH_PRIZE(3, false, 5_000), + _4TH_PRIZE(4, false, 50_000), + _3RD_PRIZE(5, false, 1_500_000), + _2ND_PRIZE(5, true, 30_000_000), + _1ST_PRIZE(6, false, 2_000_000_000), + ; + + private final int matchCount; + private final boolean containsBonus; + private final int prize; + + Rank(final int matchCount, final boolean containsBonus, final int prize) { + this.matchCount = matchCount; + this.containsBonus = containsBonus; + this.prize = prize; + } + + public static Rank of(int matchCount, boolean matchBonus) { + return Arrays.stream(Rank.values()) + .filter(rank -> rank.matchCount == matchCount) + .filter(rank -> rank.containsBonus == matchBonus) + .findFirst() + .orElse(_LAST_PRIZE); + } + + public int matchCount() { + return matchCount; + } + + public boolean containsBonus() { + return containsBonus; + } + + public int prize() { + return prize; + } +} diff --git a/src/main/java/model/ResultStatistics.java b/src/main/java/model/ResultStatistics.java new file mode 100644 index 00000000..bfc3f989 --- /dev/null +++ b/src/main/java/model/ResultStatistics.java @@ -0,0 +1,33 @@ +package model; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ResultStatistics { + + private final Map ranksByCount; + private final int purchaseAmount; + + private ResultStatistics(Map ranksByCount, int purchaseAmount) { + this.ranksByCount = ranksByCount; + this.purchaseAmount = purchaseAmount; + } + + public static ResultStatistics from(List ranks) { + Map ranksByCount = ranks.stream() + .collect(Collectors.toMap(rank -> rank, rank -> 1, Integer::sum)); + return new ResultStatistics(ranksByCount, ranks.size() * LottoPrice.PRICE_UNIT); + } + + public int countOf(Rank rank) { + return ranksByCount.getOrDefault(rank, 0); + } + + public double calculateProfitRate() { + int totalWinningPrize = ranksByCount.entrySet().stream() + .mapToInt(entry -> entry.getKey().prize() * entry.getValue()) + .sum(); + return ((float) (totalWinningPrize * 100) / purchaseAmount) / 100.0; + } +} diff --git a/src/main/java/model/WinningLotto.java b/src/main/java/model/WinningLotto.java new file mode 100644 index 00000000..753b1fc3 --- /dev/null +++ b/src/main/java/model/WinningLotto.java @@ -0,0 +1,36 @@ +package model; + +import static model.Rank._2ND_PRIZE; + +import java.util.List; + +public record WinningLotto(Lotto lotto, LottoNumber bonusNumber) { + + public WinningLotto { + validate(lotto, bonusNumber); + } + + public static WinningLotto from(List numbers, int bonusNumber) { + return new WinningLotto(Lotto.from(numbers), new LottoNumber(bonusNumber)); + } + + private void validate(Lotto lotto, LottoNumber bonusNumber) { + validateDuplication(lotto, bonusNumber); + } + + private void validateDuplication(Lotto lotto, LottoNumber bonusNumber) { + if (lotto.numbers().contains(bonusNumber)) { + throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다."); + } + } + + public Rank match(Lotto other) { + int matchCount = (int) other.numbers().stream() + .filter(lotto.numbers()::contains) + .count(); + if (matchCount == _2ND_PRIZE.matchCount()) { + return Rank.of(matchCount, other.numbers().contains(bonusNumber)); + } + return Rank.of(matchCount, false); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..149f194a --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,40 @@ +package view; + +import java.util.List; +import java.util.Scanner; +import java.util.stream.Stream; + +public class InputView { + + public static final Scanner SCANNER = new Scanner(System.in); + + public String readLottoPrice() { + System.out.println("구입금액을 입력해 주세요."); + return SCANNER.nextLine(); + } + + public int readManualLottoCount() { + System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); + return Integer.parseInt(SCANNER.nextLine()); + } + + public List readManualLottoNumbers(int count) { + System.out.println("수동으로 구매할 번호를 입력해 주세요."); + return Stream.generate(SCANNER::nextLine) + .limit(count) + .toList(); + } + + public List readWinningNumbers() { + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + String input = SCANNER.nextLine(); + return Stream.of(input.replace(" ", "").split(",")) + .filter(it -> !it.isBlank()) + .toList(); + } + + public int readBonusNumber() { + System.out.println("보너스 볼을 입력해 주세요."); + return Integer.parseInt(SCANNER.nextLine()); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..475b12c1 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,48 @@ +package view; + +import java.util.List; +import model.Rank; +import view.dto.LottoResponse; +import view.dto.LottoStatisticsResponse; + +public class OutputView { + + private static final String LOTTO_PURCHASED_FORMAT = "수동으로 %d장, 자동으로 %d개를 구매했습니다."; + private static final String MATCH_RESULT_FORMAT = "%d개 일치 (%d원)- %d개"; + private static final String MATCH_RESULT_2ND_PRIZE_FORMAT = "%d개 일치, 보너스 볼 일치(%d원)- %d개"; + private static final String PROFIT_RATE_FORMAT = "총 수익률은 %.2f입니다."; + + public void printLotto(List lottos, int manualLottoCount, int automaticLottoCount) { + printLinebreak(); + System.out.printf(LOTTO_PURCHASED_FORMAT, manualLottoCount, automaticLottoCount); + printLinebreak(); + lottos.stream() + .map(LottoResponse::numbers) + .forEach(System.out::println); + } + + private void printLinebreak() { + System.out.print(System.lineSeparator()); + } + + public void printResultStatistics(LottoStatisticsResponse response) { + printLinebreak(); + System.out.println("당첨 통계"); + System.out.println("---------"); + response.countOfRank().keySet().stream() + .filter(rank -> rank != Rank._LAST_PRIZE) + .sorted() + .forEach(rank -> { + int count = response.countOfRank().get(rank); + if (rank == Rank._2ND_PRIZE) { + System.out.printf(MATCH_RESULT_2ND_PRIZE_FORMAT, rank.matchCount(), rank.prize(), count); + printLinebreak(); + return; + } + System.out.printf(MATCH_RESULT_FORMAT, rank.matchCount(), rank.prize(), count); + printLinebreak(); + }); + + System.out.printf(PROFIT_RATE_FORMAT, response.profitRate()); + } +} diff --git a/src/main/java/view/dto/LottoResponse.java b/src/main/java/view/dto/LottoResponse.java new file mode 100644 index 00000000..b9622387 --- /dev/null +++ b/src/main/java/view/dto/LottoResponse.java @@ -0,0 +1,17 @@ +package view.dto; + +import java.util.List; +import model.Lotto; +import model.LottoNumber; + +public record LottoResponse( + List numbers +) { + + public static LottoResponse from(Lotto lottos) { + List numbers = lottos.numbers().stream() + .map(LottoNumber::number) + .toList(); + return new LottoResponse(numbers); + } +} diff --git a/src/main/java/view/dto/LottoStatisticsResponse.java b/src/main/java/view/dto/LottoStatisticsResponse.java new file mode 100644 index 00000000..0a745efa --- /dev/null +++ b/src/main/java/view/dto/LottoStatisticsResponse.java @@ -0,0 +1,23 @@ +package view.dto; + +import java.util.HashMap; +import java.util.Map; +import model.Rank; +import model.ResultStatistics; + +public record LottoStatisticsResponse( + Map countOfRank, + double profitRate +) { + + public static LottoStatisticsResponse from(ResultStatistics resultStatistics) { + Map ranksByCount = new HashMap<>(); + for (Rank rank : Rank.values()) { + ranksByCount.put(rank, resultStatistics.countOf(rank)); + } + return new LottoStatisticsResponse( + ranksByCount, + resultStatistics.calculateProfitRate() + ); + } +} diff --git a/src/test/java/model/LottoNumberTest.java b/src/test/java/model/LottoNumberTest.java new file mode 100644 index 00000000..c35bf79c --- /dev/null +++ b/src/test/java/model/LottoNumberTest.java @@ -0,0 +1,20 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +@SuppressWarnings("NonAsciiCharacters") +class LottoNumberTest { + + @Test + void 로또_번호는_1부터_45까지_이어야_한다() { + // given + int number = 46; + + // when & then + assertThatThrownBy(() -> new LottoNumber(number)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 번호는 1부터 45 사이여야 합니다."); + } +} diff --git a/src/test/java/model/LottoPriceTest.java b/src/test/java/model/LottoPriceTest.java new file mode 100644 index 00000000..e0ca87bc --- /dev/null +++ b/src/test/java/model/LottoPriceTest.java @@ -0,0 +1,52 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@SuppressWarnings("NonAsciiCharacters") +class LottoPriceTest { + + @ParameterizedTest + @ValueSource(ints = {0, 1000, 2000, 3000, 4000, 5000}) + void 로또_금액은_0원_혹은_1000원_단위이어야_한다(int price) { + // when & then + Assertions.assertThatCode(() -> new LottoPrice(price)).doesNotThrowAnyException(); + } + + @Test + void 로또_금액은_0원_보다_작을_수_없다() { + // given + int price = -1000; + + // when & then + assertThatThrownBy(() -> new LottoPrice(price)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 금액은 0원 보다 작을 수 없습니다."); + } + + @Test + void 로또_금액은_1000원_단위여야_한다() { + // given + int price = 1234; + + // when & then + assertThatThrownBy(() -> new LottoPrice(price)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 금액은 1000원 단위여야 합니다."); + } + + @Test + void 로또_금액은_숫자여야_한다() { + // given + String price = "천원"; + + // when & then + assertThatThrownBy(() -> LottoPrice.valueOf(price)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 금액은 숫자여야 합니다."); + } +} diff --git a/src/test/java/model/LottoTest.java b/src/test/java/model/LottoTest.java new file mode 100644 index 00000000..6274d05e --- /dev/null +++ b/src/test/java/model/LottoTest.java @@ -0,0 +1,60 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +@SuppressWarnings("NonAsciiCharacters") +class LottoTest { + + @Nested + class 로또_생성_시 { + + @Test + void 로또는_중복되지_않는_6개의_숫자로_이루어져있다() { + // given + List numbers = List.of(1, 2, 3, 4, 5, 6); + + // when & then + assertThatCode(() -> Lotto.from(numbers)).doesNotThrowAnyException(); + } + + @Test + void 로또는_6개의_숫자로_이루어져야_한다() { + // given + List numbers = List.of(1, 2, 3, 4, 5); + + // when & then + assertThatThrownBy(() -> Lotto.from(numbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또는 6개의 숫자로 이루어져야 합니다."); + } + + @Test + void 로또는_중복되지_않는_6개의_숫자로_이루어져야_한다() { + // given + List numbers = List.of(1, 2, 3, 4, 5, 5); + + // when & then + assertThatThrownBy(() -> Lotto.from(numbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또는 중복되지 않는 6개의 숫자로 이루어져야 합니다."); + } + + @Test + void 로또의_숫자들은_오름차순으로_정렬되어_있다() { + // given + List numbers = List.of(6, 5, 4, 3, 2, 1); + + // when + var lotto = Lotto.from(numbers); + + // then + assertThat(lotto.numbers()).isSorted(); + } + } +} diff --git a/src/test/java/model/RankTest.java b/src/test/java/model/RankTest.java new file mode 100644 index 00000000..d91a272e --- /dev/null +++ b/src/test/java/model/RankTest.java @@ -0,0 +1,35 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@SuppressWarnings("NonAsciiCharacters") +class RankTest { + + @ParameterizedTest + @MethodSource("matchCountWithRank") + void 당첨_숫자의_개수와_보너스_볼_여부에_따라_순위가_결정된다(int matchCount, boolean matchBonus, Rank rank) { + // when + Rank actual = Rank.of(matchCount, matchBonus); + + // then + assertThat(actual).isEqualTo(rank); + } + + static Stream matchCountWithRank() { + return Stream.of( + Arguments.of(6, false, Rank._1ST_PRIZE), + Arguments.of(5, true, Rank._2ND_PRIZE), + Arguments.of(5, false, Rank._3RD_PRIZE), + Arguments.of(4, false, Rank._4TH_PRIZE), + Arguments.of(3, false, Rank._5TH_PRIZE), + Arguments.of(2, false, Rank._LAST_PRIZE), + Arguments.of(1, false, Rank._LAST_PRIZE), + Arguments.of(1, false, Rank._LAST_PRIZE) + ); + } +} diff --git a/src/test/java/model/ResultStatisticsTest.java b/src/test/java/model/ResultStatisticsTest.java new file mode 100644 index 00000000..b8882062 --- /dev/null +++ b/src/test/java/model/ResultStatisticsTest.java @@ -0,0 +1,50 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +@SuppressWarnings("NonAsciiCharacters") +class ResultStatisticsTest { + + @Test + void 순위_목록을_통해_당첨_결과가_생성된다() { + // given + List ranks = List.of( + Rank._5TH_PRIZE, + Rank._5TH_PRIZE, + Rank._LAST_PRIZE, + Rank._LAST_PRIZE, + Rank._3RD_PRIZE + ); + + // when + var resultStatistics = ResultStatistics.from(ranks); + + // then + assertThat(resultStatistics.countOf(Rank._5TH_PRIZE)).isEqualTo(2); + assertThat(resultStatistics.countOf(Rank._LAST_PRIZE)).isEqualTo(2); + assertThat(resultStatistics.countOf(Rank._3RD_PRIZE)).isEqualTo(1); + } + + + @Test + void 수익률을_계산한다() { + // given + List ranks = List.of( + Rank._5TH_PRIZE, + Rank._5TH_PRIZE, + Rank._LAST_PRIZE, + Rank._LAST_PRIZE, + Rank._LAST_PRIZE + ); + ResultStatistics resultStatistics = ResultStatistics.from(ranks); + + // when + double profitRate = resultStatistics.calculateProfitRate(); + + // then + assertThat(profitRate).isEqualTo(2); + } +} diff --git a/src/test/java/model/WinningLottoTest.java b/src/test/java/model/WinningLottoTest.java new file mode 100644 index 00000000..e386a669 --- /dev/null +++ b/src/test/java/model/WinningLottoTest.java @@ -0,0 +1,36 @@ +package model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@SuppressWarnings("NonAsciiCharacters") +@DisplayNameGeneration(ReplaceUnderscores.class) +class WinningLottoTest { + + @ParameterizedTest + @MethodSource("lottoAndWinningLotto") + void 당첨_로또와_비교하여_순위를_결정한다(Lotto lotto, WinningLotto winningLotto, Rank expected) { + // given & when + final Rank actual = winningLotto.match(lotto); + + // then + assertThat(actual).isEqualTo(expected); + } + + static Stream lottoAndWinningLotto() { + return Stream.of( + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 3, 4, 5, 6), 7), Rank._1ST_PRIZE), + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 3, 4, 5, 8), 6), Rank._2ND_PRIZE), + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 3, 4, 5, 8), 9), Rank._3RD_PRIZE), + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 3, 4, 7, 8), 9), Rank._4TH_PRIZE), + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 3, 7, 8, 9), 10), Rank._5TH_PRIZE), + Arguments.of(Lotto.from(List.of(1, 2, 3, 4, 5, 6)), WinningLotto.from(List.of(1, 2, 7, 8, 9, 10), 11), Rank._LAST_PRIZE)); + } +}