diff --git a/docs/README.md b/docs/README.md index e69de29bb2d..7386e1cc252 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,14 @@ +### 기능 요구사항 + +[ ✅ ] 사용자는 구입금액을 입력한다. +- 구입금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. + +[ ✅ ] 구입금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다. + +[ ✅ ] 당첨번호를 입력한다. + +[ ✅ ] 보너스번호를 입력한다. + +[ ✅ ] 당첨통계를 출력한다. + +[ ✅ ] 수익률을 계산한다. \ No newline at end of file diff --git a/src/main/java/controller/LottosController.java b/src/main/java/controller/LottosController.java new file mode 100644 index 00000000000..99efa992cfa --- /dev/null +++ b/src/main/java/controller/LottosController.java @@ -0,0 +1,35 @@ +package controller; + +import domain.*; +import dto.LottoDto; +import service.LottosService; +import service.PurchaseService; +import view.InputView; +import view.OutputView; + +import java.util.List; + +public class LottosController { + private final LottosService lottosService; + private Lottos lottos; + + public LottosController(){ + lottosService = new LottosService(); + } + + public Lottos start(final PurchaseAmount purchaseAmount){ + Lottos purchaseLottos = generateLottos(purchaseAmount); + lottos = purchaseLottos; + printPurchaseLottos(purchaseLottos, purchaseAmount.getQuantity()); + return lottos; + } + + private Lottos generateLottos(final PurchaseAmount purchaseAmount){ + return lottosService.createLottos(purchaseAmount); + } + + private void printPurchaseLottos(final Lottos purchaseLottos, final int numberOfPurchased){ + List printPurchaseLottos = lottosService.getPurchaseLottos(purchaseLottos); + OutputView.printPurchaseLottos(printPurchaseLottos, numberOfPurchased); + } +} diff --git a/src/main/java/controller/PurchaseController.java b/src/main/java/controller/PurchaseController.java new file mode 100644 index 00000000000..1a2dd3828ed --- /dev/null +++ b/src/main/java/controller/PurchaseController.java @@ -0,0 +1,28 @@ +package controller; + +import domain.PurchaseAmount; +import service.PurchaseService; +import view.InputView; +import view.OutputView; + +public class PurchaseController { + private final PurchaseService purchaseService; + + public PurchaseController(){ + purchaseService = new PurchaseService(); + } + + public PurchaseAmount generatePurchaseAmount(){ + try{ + int purchaseAmount = InputView.inputPurchaseAmount(); + return createPurchaseAmount(purchaseAmount); + } catch (IllegalArgumentException e){ + OutputView.printMessage(e.getMessage()); + return generatePurchaseAmount(); + } + } + + private PurchaseAmount createPurchaseAmount(final int purchaseAmount){ + return purchaseService.createPurchaseAmount(purchaseAmount); + } +} diff --git a/src/main/java/controller/WinningController.java b/src/main/java/controller/WinningController.java new file mode 100644 index 00000000000..28989ef5dc8 --- /dev/null +++ b/src/main/java/controller/WinningController.java @@ -0,0 +1,61 @@ +package controller; + +import domain.*; +import dto.WinningResultDto; +import service.WinningService; +import view.InputView; +import view.OutputView; + +import java.util.List; + +public class WinningController { + private final WinningService winningService; + + public WinningController(){ + winningService = new WinningService(); + } + + public void generateWinngingAndBonus(final Lottos lottos, final int purchaseAmount){ + WinningNumbers winningNumbers = generateWinngingNumbers(); + BonusNumber bonusNumber = generateBonusNumber(); + printWinningStaticsAndProfit(winningNumbers, bonusNumber, lottos, purchaseAmount); + } + + private WinningNumbers generateWinngingNumbers(){ + try{ + List winningNumbers = InputView.inputWinngingNumbers(); + return createWinngingNumbers(winningNumbers); + } catch (IllegalArgumentException e){ + OutputView.printMessage(e.getMessage()); + return generateWinngingNumbers(); + } + } + + private BonusNumber generateBonusNumber(){ + try{ + int number = InputView.inputBonusNumber(); + return createBonusNumber(number); + } catch (IllegalArgumentException e){ + OutputView.printMessage(e.getMessage()); + return generateBonusNumber(); + } + } + + private WinningNumbers createWinngingNumbers(final List winningNumbers){ + return winningService.createWinningNumbers(winningNumbers); + } + + private BonusNumber createBonusNumber(final int bonusNumber){ + return winningService.createBonusNumber(bonusNumber); + } + + private void printWinningStaticsAndProfit(final WinningNumbers winningNumbers, final BonusNumber bonusNumber, final Lottos lottos, final int purchaseAmount){ + generateWinningResult(winningNumbers, bonusNumber); + WinningResultDto winningResultDto = winningService.calculateProfitAndRateOfProfit(lottos.getLottos(), purchaseAmount); + OutputView.printWinningStatics(winningResultDto); + } + + private WinningResult generateWinningResult(final WinningNumbers winningNumbers, final BonusNumber bonusNumber){ + return winningService.createWinningResult(winningNumbers, bonusNumber); + } +} diff --git a/src/main/java/domain/BonusNumber.java b/src/main/java/domain/BonusNumber.java new file mode 100644 index 00000000000..117266fb77a --- /dev/null +++ b/src/main/java/domain/BonusNumber.java @@ -0,0 +1,17 @@ +package domain; + +public class BonusNumber { + private final int bonusNumber; + + private BonusNumber(final int number) { + bonusNumber = number; + } + + public static BonusNumber create(final int number){ + return new BonusNumber(number); + } + + public int getBonusNumber(){ + return bonusNumber; + } +} diff --git a/src/main/java/domain/Lotto.java b/src/main/java/domain/Lotto.java new file mode 100644 index 00000000000..c1a7d3c419d --- /dev/null +++ b/src/main/java/domain/Lotto.java @@ -0,0 +1,47 @@ +package domain; + +import util.exception.DuplicateException; +import util.exception.SizeOverException; + +import java.util.*; + +import static util.message.ExceptionMessage.DUPLICATE_MESSAGE; +import static util.message.ExceptionMessage.SIZE_OVER_MESSAGE; + +public class Lotto { + private final List numbers; + + public Lotto(List numbers) { + validate(numbers); + List numberList = sort(numbers); + this.numbers = numberList; + } + + public List getNumbers(){ + return numbers; + } + + private void validate(List numbers) { + validateSize(numbers); + validateDuplicate(numbers); + } + + private void validateSize(List numbers){ + if (numbers.size() != 6) { + throw new SizeOverException(String.format(SIZE_OVER_MESSAGE.getValue(), "로또")); + } + } + + private void validateDuplicate(List numbers){ + Set lottos = new HashSet<>(numbers); + if(numbers.size() != lottos.size()){ + throw new DuplicateException(String.format(DUPLICATE_MESSAGE.getValue())); + } + } + + private List sort(List numbers){ + List numberList = new ArrayList<>(numbers); + Collections.sort(numberList); + return numberList; + } +} diff --git a/src/main/java/domain/Lottos.java b/src/main/java/domain/Lottos.java new file mode 100644 index 00000000000..1cfb6af9256 --- /dev/null +++ b/src/main/java/domain/Lottos.java @@ -0,0 +1,40 @@ +package domain; + +import util.constants.LottosConstants; +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.ArrayList; +import java.util.List; + +public class Lottos { + private final List lottos; + + public Lottos(int numberOfPurchased){ + lottos = generateLottos(numberOfPurchased); + } + + public static Lottos create(final int numberOfPurchased){ + return new Lottos(numberOfPurchased); + } + + public List getLottos(){ + return lottos; + } + + private List generateLottos(int numberOfPurchased){ + List lottos = new ArrayList<>(); + while(numberOfPurchased-- > 0){ + lottos.add(generateRandomNumbers()); + } + return lottos; + } + + private Lotto generateRandomNumbers(){ + List numbers = Randoms.pickUniqueNumbersInRange( + LottosConstants.MIN_VALUE.getValue(), + LottosConstants.MAX_VALUE.getValue(), + LottosConstants.LOTTO_SIZE.getValue()); + + return new Lotto(numbers); + } +} diff --git a/src/main/java/domain/PurchaseAmount.java b/src/main/java/domain/PurchaseAmount.java new file mode 100644 index 00000000000..fbd9411a544 --- /dev/null +++ b/src/main/java/domain/PurchaseAmount.java @@ -0,0 +1,39 @@ +package domain; + +import util.constants.Constants; + +import static util.message.ExceptionMessage.UNIT_MESSAGE; + +public class PurchaseAmount { + private final int amount; + private final int quantity; + + private PurchaseAmount(final int purchaseAmount) { + validateDivisibleBy1000(purchaseAmount); + this.amount = purchaseAmount; + this.quantity = calculatequantity(); + } + + public static PurchaseAmount create(final int purchaseAmount){ + return new PurchaseAmount(purchaseAmount); + } + + public int getQuantity(){ + return quantity; + } + + public int getAmount(){ + return amount; + } + + private int calculatequantity(){ + return amount / Constants.ONE_THOUSAND.getValue(); + } + + private static int validateDivisibleBy1000(final int amount){ + if(amount % Constants.ONE_THOUSAND.getValue() != Constants.ZERO.getValue()){ + throw new IllegalArgumentException(String.format(UNIT_MESSAGE.getValue(), Constants.ONE_THOUSAND.getValue())); + } + return amount; + } +} diff --git a/src/main/java/domain/Rank.java b/src/main/java/domain/Rank.java new file mode 100644 index 00000000000..7f1474e6adb --- /dev/null +++ b/src/main/java/domain/Rank.java @@ -0,0 +1,59 @@ +package domain; + +import util.constants.Constants; + +public enum Rank { + FIFTH(3, 5_000, "3개 일치 (5,000원) - "), + FOURTH(4, 50_000, "4개 일치 (50,000원) - "), + THIRD(5, 1_500_000, "5개 일치 (1,500,000원) - "), + SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치 (30,000,000원) - "), + FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원) - "); + + private int countOfMatch; + private int prize; + private String message; + + Rank(int countOfMatch, int prize, String message){ + this.countOfMatch = countOfMatch; + this.prize = prize; + this.message = message; + } + + public int getCountOfMatch(){ + return countOfMatch; + } + + public int getPrize(){ + return prize; + } + + public String getMessage(){ + return message; + } + + public static Rank calculateRank(int countOfMatchNumbers, boolean isMatchBonus){ + for(Rank rank : values()){ + if(rank.matches(countOfMatchNumbers, isMatchBonus)){ + return rank; + } + } + return null; + } + + private boolean matches(int countOfMatchNumbers, boolean isMatchBonus){ + if(this == SECOND){ + return checkSecond(countOfMatchNumbers, isMatchBonus); + } + return checkRemaining(countOfMatchNumbers, isMatchBonus); + } + + private boolean checkSecond(int countOfMatchNumbers, boolean isMatchBonus){ + return this.countOfMatch == countOfMatchNumbers && isMatchBonus; + } + + private boolean checkRemaining(int countOfMatchNumbers, boolean isMatchBonus){ + return this.countOfMatch == countOfMatchNumbers && !isMatchBonus; + } + + +} diff --git a/src/main/java/domain/WinningNumbers.java b/src/main/java/domain/WinningNumbers.java new file mode 100644 index 00000000000..5f51bb4fa4a --- /dev/null +++ b/src/main/java/domain/WinningNumbers.java @@ -0,0 +1,33 @@ +package domain; + +import util.exception.DuplicateException; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static util.message.ExceptionMessage.DUPLICATE_MESSAGE; + +public class WinningNumbers { + private final List numbers; + + private WinningNumbers(final List inputWinningNumbers) { + validateDuplicate(inputWinningNumbers); + numbers = inputWinningNumbers; + } + + public static WinningNumbers create(final List inputWinningNumbers){ + return new WinningNumbers(inputWinningNumbers); + } + + public List getNumbers(){ + return numbers; + } + + private void validateDuplicate(final List inputWinningNumbers){ + Set numbers = new HashSet<>(inputWinningNumbers); + if(numbers.size() != inputWinningNumbers.size()){ + throw new DuplicateException(String.format(DUPLICATE_MESSAGE.getValue())); + } + } +} diff --git a/src/main/java/domain/WinningResult.java b/src/main/java/domain/WinningResult.java new file mode 100644 index 00000000000..120aabcb26e --- /dev/null +++ b/src/main/java/domain/WinningResult.java @@ -0,0 +1,72 @@ +package domain; + +import java.util.HashMap; +import java.util.List; + +public class WinningResult { + private final WinningNumbers winningNumbers; + private final BonusNumber bonusNumber; + private final HashMap winningResult; + private double totalPrize; + private double rateOfProfit; + + private WinningResult(WinningNumbers winningNumbers, BonusNumber bonusNumber){ + this.winningNumbers = winningNumbers; + this.bonusNumber = bonusNumber; + this.winningResult = new HashMap<>(); + initWinningResult(); + } + + public static WinningResult create(WinningNumbers winningNumbers, BonusNumber bonusNumber){ + return new WinningResult(winningNumbers, bonusNumber); + } + + public double getRateOfProfit(){ + return rateOfProfit; + } + + public HashMap getWinningResult(){ + return winningResult; + } + + private void initWinningResult(){ + for (Rank rank : Rank.values()) { + winningResult.put(rank, 0); + } + } + + public void calculateProfit(List lottos){ + for(Lotto lotto : lottos){ + calculate(getMatchNumbers(lotto, winningNumbers), isMatchBonusNumber(lotto, bonusNumber)); + } + } + + public void calculateRateOfProfit(int amount){ + rateOfProfit = (totalPrize / (double) amount) * 100; + } + + private void calculate(int countOfMatchNumber, boolean isMatchBonus){ + Rank rank = Rank.calculateRank(countOfMatchNumber, isMatchBonus); + if(rank != null){ + winningResult.put(rank, winningResult.get(rank) + 1); + addTotalPrize(rank.getPrize()); + } + } + + private void addTotalPrize(int prize){ + totalPrize += prize; + } + + private int getMatchNumbers(Lotto lotto, WinningNumbers winningNumbers){ + List lottoNumbers = lotto.getNumbers(); + List winningNums = winningNumbers.getNumbers(); + long matchedCount = lottoNumbers.stream() + .filter(winningNums::contains) + .count(); + return (int) matchedCount; + } + + private boolean isMatchBonusNumber(Lotto lotto, BonusNumber bonusNumber){ + return lotto.getNumbers().contains(bonusNumber.getBonusNumber()); + } +} diff --git a/src/main/java/dto/LottoDto.java b/src/main/java/dto/LottoDto.java new file mode 100644 index 00000000000..94696e90e81 --- /dev/null +++ b/src/main/java/dto/LottoDto.java @@ -0,0 +1,26 @@ +package dto; + +import domain.Lotto; + +import java.util.List; + +public class LottoDto { + private final List numbers; + + private LottoDto(List numbers) { + this.numbers = numbers; + } + + public static LottoDto create(List numbers) { + return new LottoDto(numbers); + } + + public List getNumbers() { + return numbers; + } + + @Override + public String toString() { + return numbers.toString(); + } +} diff --git a/src/main/java/dto/WinningResultDto.java b/src/main/java/dto/WinningResultDto.java new file mode 100644 index 00000000000..128286c8e0a --- /dev/null +++ b/src/main/java/dto/WinningResultDto.java @@ -0,0 +1,36 @@ +package dto; + +import domain.Rank; +import domain.WinningResult; + +import java.util.List; +import java.util.Map; + +public class WinningResultDto { + private final Map winningResult; + private final double rateOfProfit; + private static final String COUNT = "개\n"; + + private WinningResultDto(final WinningResult winningResult) { + this.winningResult = winningResult.getWinningResult(); + rateOfProfit = winningResult.getRateOfProfit(); + } + + public static WinningResultDto create(final WinningResult winningResult) { + return new WinningResultDto(winningResult); + } + + public String formatRateOfReturn(){ + double value = Math.round(rateOfProfit * 10.0) / 10.0; + return String.format("%.1f", value); + } + + public String generateResultString() { + StringBuilder resultString = new StringBuilder(); + for (Rank rank : Rank.values()) { + int count = winningResult.getOrDefault(rank, 0); + resultString.append(rank.getMessage()).append(count).append(COUNT); + } + return resultString.toString(); + } +} diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922ba44..d4c6dc7e2dc 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,24 @@ package lotto; +import controller.LottosController; +import controller.PurchaseController; +import controller.WinningController; +import domain.Lottos; +import domain.PurchaseAmount; + public class Application { + + private static final LottosController lottosController = new LottosController(); + private static final PurchaseController purchaseController = new PurchaseController(); + + private static final WinningController winningController = new WinningController(); public static void main(String[] args) { - // TODO: 프로그램 구현 + initLottos(); + } + + private static void initLottos(){ + PurchaseAmount purchaseAmount = purchaseController.generatePurchaseAmount(); + Lottos lottos = lottosController.start(purchaseAmount); + winningController.generateWinngingAndBonus(lottos, purchaseAmount.getAmount()); } } diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java deleted file mode 100644 index 519793d1f73..00000000000 --- a/src/main/java/lotto/Lotto.java +++ /dev/null @@ -1,20 +0,0 @@ -package lotto; - -import java.util.List; - -public class Lotto { - private final List numbers; - - public Lotto(List numbers) { - validate(numbers); - this.numbers = numbers; - } - - private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException(); - } - } - - // TODO: 추가 기능 구현 -} diff --git a/src/main/java/service/LottosService.java b/src/main/java/service/LottosService.java new file mode 100644 index 00000000000..7dc962368bb --- /dev/null +++ b/src/main/java/service/LottosService.java @@ -0,0 +1,20 @@ +package service; + +import domain.*; +import dto.LottoDto; + +import java.util.List; +import java.util.stream.Collectors; + +public class LottosService { + public Lottos createLottos(final PurchaseAmount purchaseAmount){ + return Lottos.create(purchaseAmount.getQuantity()); + } + + public List getPurchaseLottos(final Lottos purchaseLottos){ + List lottos = purchaseLottos.getLottos(); + return lottos.stream() + .map(lotto -> LottoDto.create(lotto.getNumbers())) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/service/PurchaseService.java b/src/main/java/service/PurchaseService.java new file mode 100644 index 00000000000..fd7796bc4b5 --- /dev/null +++ b/src/main/java/service/PurchaseService.java @@ -0,0 +1,9 @@ +package service; + +import domain.PurchaseAmount; + +public class PurchaseService { + public PurchaseAmount createPurchaseAmount(final int purchaseAmount){ + return PurchaseAmount.create(purchaseAmount); + } +} diff --git a/src/main/java/service/WinningService.java b/src/main/java/service/WinningService.java new file mode 100644 index 00000000000..cfc24cc09aa --- /dev/null +++ b/src/main/java/service/WinningService.java @@ -0,0 +1,41 @@ +package service; + +import domain.BonusNumber; +import domain.Lotto; +import domain.WinningNumbers; +import domain.WinningResult; +import dto.WinningResultDto; + +import java.util.List; + +public class WinningService { + + private WinningResult winningResult; + + public WinningNumbers createWinningNumbers(final List winningNumbers){ + return WinningNumbers.create(winningNumbers); + } + + public BonusNumber createBonusNumber(final int bonusNumber){ + return BonusNumber.create(bonusNumber); + } + + public WinningResult createWinningResult(final WinningNumbers winningNumbers, final BonusNumber bonusNumber){ + winningResult = WinningResult.create(winningNumbers, bonusNumber); + return winningResult; + } + + public WinningResultDto calculateProfitAndRateOfProfit(final List lottos, final int purchaseAmount){ + calculateProfit(lottos); + calculateRateOfProfit(purchaseAmount); + return WinningResultDto.create(winningResult); + } + + private void calculateProfit(final List lottos){ + winningResult.calculateProfit(lottos); + } + + private void calculateRateOfProfit(final int purchaseAmount){ + winningResult.calculateRateOfProfit(purchaseAmount); + } +} diff --git a/src/main/java/util/EnumUtil.java b/src/main/java/util/EnumUtil.java new file mode 100644 index 00000000000..e0c0bcb600a --- /dev/null +++ b/src/main/java/util/EnumUtil.java @@ -0,0 +1,6 @@ +package util; + +public interface EnumUtil { + T1 getKey(); + T2 getValue(); +} diff --git a/src/main/java/util/constants/Constants.java b/src/main/java/util/constants/Constants.java new file mode 100644 index 00000000000..fffc700ea56 --- /dev/null +++ b/src/main/java/util/constants/Constants.java @@ -0,0 +1,25 @@ +package util.constants; + +import util.EnumUtil; + +public enum Constants implements EnumUtil { + ONE_THOUSAND(1000), + ZERO(0), + WINNING_MIN_COUNT(3); + + private final int number; + + Constants(final int number){ + this.number = number; + } + + @Override + public String getKey() { + return name(); + } + + @Override + public Integer getValue() { + return number; + } +} diff --git a/src/main/java/util/constants/LottosConstants.java b/src/main/java/util/constants/LottosConstants.java new file mode 100644 index 00000000000..7eb2b154ef2 --- /dev/null +++ b/src/main/java/util/constants/LottosConstants.java @@ -0,0 +1,25 @@ +package util.constants; + +import util.EnumUtil; + +public enum LottosConstants implements EnumUtil { + MIN_VALUE(1), + MAX_VALUE(45), + LOTTO_SIZE(6); + + private final int number; + + LottosConstants(final int number){ + this.number = number; + } + + @Override + public String getKey() { + return name(); + } + + @Override + public Integer getValue() { + return number; + } +} diff --git a/src/main/java/util/exception/DuplicateException.java b/src/main/java/util/exception/DuplicateException.java new file mode 100644 index 00000000000..a6180ea4617 --- /dev/null +++ b/src/main/java/util/exception/DuplicateException.java @@ -0,0 +1,7 @@ +package util.exception; + +public class DuplicateException extends IllegalArgumentException { + public DuplicateException(final String message) { + super(message); + } +} diff --git a/src/main/java/util/exception/SizeOverException.java b/src/main/java/util/exception/SizeOverException.java new file mode 100644 index 00000000000..3fbcf8fbe22 --- /dev/null +++ b/src/main/java/util/exception/SizeOverException.java @@ -0,0 +1,7 @@ +package util.exception; + +public class SizeOverException extends IllegalArgumentException{ + public SizeOverException(final String message) { + super(message); + } +} diff --git a/src/main/java/util/message/ExceptionMessage.java b/src/main/java/util/message/ExceptionMessage.java new file mode 100644 index 00000000000..459f37770c4 --- /dev/null +++ b/src/main/java/util/message/ExceptionMessage.java @@ -0,0 +1,33 @@ +package util.message; + +import util.EnumUtil; + +public enum ExceptionMessage implements EnumUtil { + BLANK_MESSAGE("입력은 빈 값이 들어올 수 없습니다.") + , LENGTH_MESSAGE("%d글자를 초과하였습니다.") + , INPUT_MESSAGE("입력 중에 예기치 못한 오류가 발생하였습니다. 예외 메시지: %s") + , TYPE_MESSAGE("숫자만 입력할 수 있습니다.") + , UNIT_MESSAGE("%d원 단위로 입력해 주세요.") + , RANGE_MESSAGE("%d 이상의 값을 입력해 주세요.") + , RANGE_START_BETWEEND_END("%d와 %d 사이의 값을 입력해주세요.") + , DUPLICATE_MESSAGE("중복된 값이 있습니다.") + , NO_RESOURCE_MESSAGE("%s(이)가 존재하지 않습니다.") + , SIZE_OVER_MESSAGE("%s크기를 초과하였습니다."); + + private final String message; + private static final String ERROR_TAG = "[ERROR] "; + + ExceptionMessage(final String message) { + this.message = ERROR_TAG + message; + } + + @Override + public String getKey() { + return name(); + } + + @Override + public String getValue() { + return message; + } +} diff --git a/src/main/java/util/message/InputMessage.java b/src/main/java/util/message/InputMessage.java new file mode 100644 index 00000000000..967f5f348c3 --- /dev/null +++ b/src/main/java/util/message/InputMessage.java @@ -0,0 +1,25 @@ +package util.message; + +import util.EnumUtil; + +public enum InputMessage implements EnumUtil { + GET_PURCHSE_AMOUNT("구입금액을 입력해 주세요."), + GET_WINNING_NUMBERS("\n당첨 번호를 입력해 주세요."), + GET_BONUS_NUMBER("\n보너스 번호를 입력해 주세요."); + private final String message; + + InputMessage(final String message){ + this.message = message; + } + + + @Override + public String getKey() { + return name(); + } + + @Override + public String getValue() { + return message; + } +} diff --git a/src/main/java/util/message/OutputMessage.java b/src/main/java/util/message/OutputMessage.java new file mode 100644 index 00000000000..c1c4592a02d --- /dev/null +++ b/src/main/java/util/message/OutputMessage.java @@ -0,0 +1,27 @@ +package util.message; + +import util.EnumUtil; + +public enum OutputMessage implements EnumUtil{ + LOTTO_PURCHASE_COUNT("\n%d개를 구매했습니다."), + WINNING_STATICS("\n당첨통계\n" + "---"), + TOTAL_RATE_OF_PROFIT_START("총 수익률은 "), + TOTAL_RATE_OF_PROFIT_END("%입니다."); + + private final String message; + + OutputMessage(final String message){ + this.message = message; + } + + + @Override + public String getKey() { + return name(); + } + + @Override + public String getValue() { + return message; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000000..20d83ccdee6 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,30 @@ +package view; + +import camp.nextstep.edu.missionutils.Console; +import view.validator.BonusValidator; +import view.validator.PurchaseAmountValidator; +import view.validator.WinningNumbersValidator; + +import java.util.List; + +import static util.message.InputMessage.*; + +public class InputView { + public static int inputPurchaseAmount(){ + System.out.println(GET_PURCHSE_AMOUNT.getValue()); + String input = Console.readLine(); + return PurchaseAmountValidator.validate(input); + } + + public static List inputWinngingNumbers(){ + System.out.println(GET_WINNING_NUMBERS.getValue()); + String input = Console.readLine(); + return WinningNumbersValidator.validate(input); + } + + public static int inputBonusNumber(){ + System.out.println(GET_BONUS_NUMBER.getValue()); + String input = Console.readLine(); + return BonusValidator.validate(input); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000000..e1e650cddfa --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,26 @@ +package view; + +import dto.LottoDto; +import dto.WinningResultDto; +import util.message.OutputMessage; + +import java.util.List; + +public class OutputView { + public static void printMessage(String message) { + System.out.println(message); + } + + public static void printPurchaseLottos(final List lottoDtos, final int numberOfPurchased){ + System.out.println(String.format(OutputMessage.LOTTO_PURCHASE_COUNT.getValue(), numberOfPurchased)); + for (LottoDto lotto : lottoDtos) { + System.out.println(lotto); + } + } + + public static void printWinningStatics(final WinningResultDto winningResultDto){ + System.out.println(OutputMessage.WINNING_STATICS.getValue()); + System.out.print(winningResultDto.generateResultString()); + System.out.println(OutputMessage.TOTAL_RATE_OF_PROFIT_START.getValue() + winningResultDto.formatRateOfReturn() + OutputMessage.TOTAL_RATE_OF_PROFIT_END.getValue()); + } +} diff --git a/src/main/java/view/validator/BonusValidator.java b/src/main/java/view/validator/BonusValidator.java new file mode 100644 index 00000000000..db262df3cc5 --- /dev/null +++ b/src/main/java/view/validator/BonusValidator.java @@ -0,0 +1,18 @@ +package view.validator; + +import static util.message.ExceptionMessage.RANGE_START_BETWEEND_END; + +public class BonusValidator extends Validator{ + public static int validate(String input){ + validateBlank(input); + int number = validateType(input); + return validateRange(1,45, number); + } + + protected static int validateRange(final int start, final int end, final int number) { + if (number < start || number > end) { + throw new IllegalArgumentException(String.format(RANGE_START_BETWEEND_END.getValue(), start, end)); + } + return number; + } +} diff --git a/src/main/java/view/validator/PurchaseAmountValidator.java b/src/main/java/view/validator/PurchaseAmountValidator.java new file mode 100644 index 00000000000..ce9248d89e5 --- /dev/null +++ b/src/main/java/view/validator/PurchaseAmountValidator.java @@ -0,0 +1,9 @@ +package view.validator; + +public class PurchaseAmountValidator extends Validator{ + public static int validate(String input) { + validateBlank(input); + int amount = validateType(input); + return validateRange(amount, 0); + } +} diff --git a/src/main/java/view/validator/Validator.java b/src/main/java/view/validator/Validator.java new file mode 100644 index 00000000000..620f2585083 --- /dev/null +++ b/src/main/java/view/validator/Validator.java @@ -0,0 +1,28 @@ +package view.validator; + +import static util.message.ExceptionMessage.*; + +public class Validator { + protected static void validateBlank(final String input) { + if (input == null || input.trim().isEmpty()) { + throw new IllegalArgumentException(BLANK_MESSAGE.getValue()); + } + } + + protected static int validateType(final String input) { + int count; + try { + count = Integer.parseInt(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(TYPE_MESSAGE.getValue()); + } + return count; + } + + protected static int validateRange(final int input, final int range) { + if (input <= range) { + throw new IllegalArgumentException(String.format(RANGE_MESSAGE.getValue(), range)); + } + return input; + } +} diff --git a/src/main/java/view/validator/WinningNumbersValidator.java b/src/main/java/view/validator/WinningNumbersValidator.java new file mode 100644 index 00000000000..a2564e8c7fb --- /dev/null +++ b/src/main/java/view/validator/WinningNumbersValidator.java @@ -0,0 +1,59 @@ +package view.validator; + +import util.constants.LottosConstants; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import static util.message.ExceptionMessage.*; + +public class WinningNumbersValidator extends Validator{ + + private static final String COMMA = ","; + public static List validate(String input) { + validateBlank(input); + return validateNumbers(input); + } + + private static List validateNumbers(String input){ + String[] inputs = input.split(COMMA); + validateSize(inputs); + List numbers = validateNumeric(inputs); + validateRange(1,45, numbers); + return numbers; + } + + private static void validateSize(String[] inputs){ + if(inputs.length != LottosConstants.LOTTO_SIZE.getValue()){ + throw new IllegalArgumentException(String.format(SIZE_OVER_MESSAGE.getValue(), "로또")); + } + } + + private static List validateNumeric(String[] inputs){ + List numbers = new ArrayList<>(); + for(String number : inputs){ + if(!isNumeric(number.trim())){ + throw new IllegalArgumentException(TYPE_MESSAGE.getValue()); + } + numbers.add(changeStringToInt(number)); + } + return numbers; + } + + private static int changeStringToInt(String number){ + return Integer.parseInt(number); + } + + private static boolean isNumeric(String str){ + return Pattern.matches("\\d+", str); + } + + protected static void validateRange(final int start, final int end, final List numbers) { + for(int number : numbers){ + if (number < start || number > end) { + throw new IllegalArgumentException(String.format(RANGE_START_BETWEEND_END.getValue(), start, end)); + } + } + } +} diff --git a/src/test/java/domain/BonusNumberTest.java b/src/test/java/domain/BonusNumberTest.java new file mode 100644 index 00000000000..c48a663e686 --- /dev/null +++ b/src/test/java/domain/BonusNumberTest.java @@ -0,0 +1,21 @@ +package domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThatCode; + +public class BonusNumberTest { + @ParameterizedTest + @DisplayName("보너스번호을 올바르게 입력한 경우 예외가 발생하지 않는다.") + @CsvSource("40") + void givenNormalBonus_thenSuccess(final int bonusNumber) { + Assertions.assertThat(BonusNumber.create(bonusNumber)) + .isInstanceOf(BonusNumber.class); + + assertThatCode(() -> BonusNumber.create(bonusNumber)) + .doesNotThrowAnyException(); + } +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/domain/LottoTest.java similarity index 84% rename from src/test/java/lotto/LottoTest.java rename to src/test/java/domain/LottoTest.java index 9f5dfe7eb83..3a0bd1b661b 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/domain/LottoTest.java @@ -1,5 +1,6 @@ -package lotto; +package domain; +import domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -18,10 +19,7 @@ void createLottoByOverSize() { @DisplayName("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.") @Test void createLottoByDuplicatedNumber() { - // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 5))) .isInstanceOf(IllegalArgumentException.class); } - - // 아래에 추가 테스트 작성 가능 } \ No newline at end of file diff --git a/src/test/java/domain/LottosTest.java b/src/test/java/domain/LottosTest.java new file mode 100644 index 00000000000..68553cc37cc --- /dev/null +++ b/src/test/java/domain/LottosTest.java @@ -0,0 +1,45 @@ +package domain; + +import util.constants.LottosConstants; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static provider.TestProvider.createTestPurchaseLottos; + +public class LottosTest { + + private Lottos testLottos; + private int numberOfPurchased; + + @BeforeEach + void init(){ + numberOfPurchased = 3; + testLottos = createTestPurchaseLottos(numberOfPurchased); + } + + @DisplayName("구매한 만큼 로또 목록을 생성한다. - 3개의 로또가 모두 서로 다른 숫자로 이루어졌는지 확인한다.") + @Test + void createRandomLottoNumbers() { + List generatedLottos = testLottos.getLottos(); + + assertNotNull(generatedLottos); + assertEquals(numberOfPurchased, generatedLottos.size()); + + for (Lotto lotto : generatedLottos) { + validateLotto(lotto); + } + } + + private void validateLotto(Lotto lotto) { + assertNotNull(lotto); + List numbers = lotto.getNumbers(); + + assertNotNull(numbers); + assertEquals(LottosConstants.LOTTO_SIZE.getValue(), numbers.size()); + } +} diff --git a/src/test/java/domain/PurchaseAmountTest.java b/src/test/java/domain/PurchaseAmountTest.java new file mode 100644 index 00000000000..2356da0e5df --- /dev/null +++ b/src/test/java/domain/PurchaseAmountTest.java @@ -0,0 +1,35 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; +import util.constants.Constants; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static util.message.ExceptionMessage.*; +import static util.message.ExceptionMessage.UNIT_MESSAGE; + +public class PurchaseAmountTest { + @ParameterizedTest + @DisplayName("구입금액을 올바르게 입력한 경우 예외가 발생하지 않는다.") + @CsvSource("4000") + void givenNormalAmount_thenSuccess(final int purchaseAmount) { + assertThat(PurchaseAmount.create(purchaseAmount)) + .isInstanceOf(PurchaseAmount.class); + + assertThatCode(() -> PurchaseAmount.create(purchaseAmount)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest + @DisplayName("구입금액이 1000으로 나누어 떨어지지 않는 경우 예외가 발생한다.") + @ValueSource(strings = {"4565", "1223"}) + void givenNonDivisibleBy1000_thenFail(final int purchaseAmount) { + assertThatThrownBy(() -> PurchaseAmount.create(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(UNIT_MESSAGE.getValue(), Constants.ONE_THOUSAND.getValue())); + } +} diff --git a/src/test/java/domain/RankTest.java b/src/test/java/domain/RankTest.java new file mode 100644 index 00000000000..99535dc2883 --- /dev/null +++ b/src/test/java/domain/RankTest.java @@ -0,0 +1,51 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class RankTest { + @DisplayName("당첨 번호 개수와 보너스 당첨 여부에 따른 등수를 검증한다. 6개가 일치하였다면, 1등.") + @Test + void checkFirst() { + assertThat(Rank.calculateRank(6, false)) + .isEqualTo(Rank.FIRST); + } + + @DisplayName("당첨 번호 개수와 보너스 당첨 여부에 따른 등수를 검증한다. 5개가 일치하면서 보너스번호까지 맞추었다면, 2등.") + @Test + void checkSecond(){ + assertThat(Rank.calculateRank(5, true)) + .isEqualTo(Rank.SECOND); + } + + @DisplayName("당첨 번호 개수와 보너스 당첨 여부에 따른 등수를 검증한다. 5개가 일치하면서 보너스번호는 맞추지 못했다면, 3등.") + @Test + void checkThird(){ + assertThat(Rank.calculateRank(5, false)) + .isEqualTo(Rank.THIRD); + } + + @DisplayName("당첨 번호 개수와 보너스 당첨 여부에 따른 등수를 검증한다. 4개가 일치하면, 4등.") + @Test + void checkFourth(){ + assertThat(Rank.calculateRank(4, false)) + .isEqualTo(Rank.FOURTH); + } + + @DisplayName("당첨 번호 개수와 보너스 당첨 여부에 따른 등수를 검증합니다. 3개가 일치하면, 5등입니다.") + @Test + void checkFifth(){ + assertThat(Rank.calculateRank(3, false)) + .isEqualTo(Rank.FIFTH); + } + + @DisplayName("1등부터 5등이 아닌 나머지 등수를 검증합니다.") + @Test + void checkNonTopFiveRanks(){ + Rank result = Rank.calculateRank(2, false); + assertNull(result); + } +} diff --git a/src/test/java/domain/WinningNumbersTest.java b/src/test/java/domain/WinningNumbersTest.java new file mode 100644 index 00000000000..5c6f1f7d528 --- /dev/null +++ b/src/test/java/domain/WinningNumbersTest.java @@ -0,0 +1,41 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; +import util.constants.Constants; +import util.exception.DuplicateException; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static provider.TestProvider.createTestPurchaseLottos; +import static provider.TestProvider.createTestWinningNumbers; +import static util.message.ExceptionMessage.UNIT_MESSAGE; + +public class WinningNumbersTest { + + @DisplayName("당첨번호를 올바르게 입력한 경우 예외가 발생하지 않는다.") + @Test + void givenNormalWinningNumbers_thenSuccess() { + assertThat(WinningNumbers.create(new ArrayList<>(List.of(1,2,3,4,5,6)))) + .isInstanceOf(WinningNumbers.class); + + assertThatCode(() -> WinningNumbers.create(List.of(1,2,3,4,5,6))) + .doesNotThrowAnyException(); + } + + @DisplayName("당첨번호를 중복으로 입력한 경우 예외가 발생하지 않는다.") + @Test + void givenDuplicateWinningNumbers_thenFail() { + assertThatThrownBy(() -> WinningNumbers.create(new ArrayList<>(List.of(1,2,3,4,5,5)))) + .isInstanceOf(IllegalArgumentException.class); + } +} + + diff --git a/src/test/java/domain/WinningResultTest.java b/src/test/java/domain/WinningResultTest.java new file mode 100644 index 00000000000..1580dadf784 --- /dev/null +++ b/src/test/java/domain/WinningResultTest.java @@ -0,0 +1,45 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static provider.TestProvider.*; + +public class WinningResultTest { + + private WinningNumbers winningNumbers; + private BonusNumber bonusNumber; + private WinningResult winningResult; + + @BeforeEach + void init(){ + List winnings = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6)); + bonusNumber = createTestBonusNumber(7); + winningNumbers = createTestWinningNumbers(winnings); + winningResult = createWinningResult(winningNumbers, bonusNumber); + } + @DisplayName("주어진 로또목록과 당첨번호를 토대로 당첨내역이 올바르게 반환하는지 검증한다.") + @Test + void checkGetWinningResult() { + + List lottos = new ArrayList<>(); + lottos.add(new Lotto(List.of(1, 2, 3, 4, 5, 6))); + lottos.add(new Lotto(List.of(1, 2, 3, 4, 5, 7))); + + winningResult.calculateProfit(lottos); + + HashMap result = winningResult.getWinningResult(); + + assertEquals(1, result.get(Rank.FIRST)); + assertEquals(1, result.get(Rank.SECOND)); + assertEquals(0, result.get(Rank.THIRD)); + assertEquals(0, result.get(Rank.FOURTH)); + assertEquals(0, result.get(Rank.FIFTH)); + } +} diff --git a/src/test/java/provider/TestProvider.java b/src/test/java/provider/TestProvider.java new file mode 100644 index 00000000000..ab02a64903c --- /dev/null +++ b/src/test/java/provider/TestProvider.java @@ -0,0 +1,26 @@ +package provider; + +import domain.BonusNumber; +import domain.Lottos; +import domain.WinningNumbers; +import domain.WinningResult; + +import java.util.List; + +public class TestProvider { + public static Lottos createTestPurchaseLottos(final int numberOfPurchased) { + return Lottos.create(numberOfPurchased); + } + + public static WinningNumbers createTestWinningNumbers(final List numbers){ + return WinningNumbers.create(numbers); + } + + public static BonusNumber createTestBonusNumber(final int number){ + return BonusNumber.create(number); + } + + public static WinningResult createWinningResult(final WinningNumbers winningNumbers, final BonusNumber bonusNumber){ + return WinningResult.create(winningNumbers, bonusNumber); + } +} diff --git a/src/test/java/validator/BonusValidatorTest.java b/src/test/java/validator/BonusValidatorTest.java new file mode 100644 index 00000000000..a3495578b51 --- /dev/null +++ b/src/test/java/validator/BonusValidatorTest.java @@ -0,0 +1,51 @@ +package validator; + +import domain.PurchaseAmount; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import util.constants.Constants; +import view.validator.BonusValidator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static util.message.ExceptionMessage.*; + +public class BonusValidatorTest { + + @ParameterizedTest + @DisplayName("보너스번호를 ") + @ValueSource(strings = {"4565", "1223"}) + void givenNonRangeBonus_thenFail(final int purchaseAmount) { + assertThatThrownBy(() -> PurchaseAmount.create(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(UNIT_MESSAGE.getValue(), Constants.ONE_THOUSAND.getValue())); + } + + @ParameterizedTest + @DisplayName("보너스번호를 빈값으로 입력한 경우 예외가 발생한다.") + @ValueSource(strings = {"", " ", " ", " ", " ", "\n", "\t", "\r"}) + void givenBlankAmount_thenFail(final String bonus) { + assertThatThrownBy(() -> BonusValidator.validate(bonus)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(BLANK_MESSAGE.getValue())); + } + + @ParameterizedTest + @DisplayName("보너스번호를 숫자가 아닌 형태로 입력한 경우 예외가 발생한다.") + @ValueSource(strings = {"abc", "12bd"}) + void givenNonNumeric_thenFail(final String bonus) { + assertThatThrownBy(() -> BonusValidator.validate(bonus)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(TYPE_MESSAGE.getValue())); + } + + @ParameterizedTest + @DisplayName("보너스번호를 범위에 벗어나면 예외가 발생한다.") + @ValueSource(strings = {"-1", "49"}) + void givenLessZero_thenFail(final String purchaseAmount) { + assertThatThrownBy(() -> BonusValidator.validate(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(RANGE_START_BETWEEND_END.getValue(), 1, 45)); + } +} diff --git a/src/test/java/validator/PurchaseAmountValidatorTest.java b/src/test/java/validator/PurchaseAmountValidatorTest.java new file mode 100644 index 00000000000..e5e24390f5a --- /dev/null +++ b/src/test/java/validator/PurchaseAmountValidatorTest.java @@ -0,0 +1,39 @@ +package validator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import util.constants.Constants; +import view.validator.PurchaseAmountValidator; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static util.message.ExceptionMessage.*; + +public class PurchaseAmountValidatorTest { + @ParameterizedTest + @DisplayName("구입금액을 빈값으로 입력한 경우 예외가 발생한다.") + @ValueSource(strings = {"", " ", " ", " ", " ", "\n", "\t", "\r"}) + void givenBlankAmount_thenFail(final String purchaseAmount) { + assertThatThrownBy(() -> PurchaseAmountValidator.validate(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(BLANK_MESSAGE.getValue())); + } + + @ParameterizedTest + @DisplayName("구입금액을 숫자가 아닌 형태로 입력한 경우 예외가 발생한다.") + @ValueSource(strings = {"abc", "12bd"}) + void givenNonNumeric_thenFail(final String purchaseAmount) { + assertThatThrownBy(() -> PurchaseAmountValidator.validate(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(TYPE_MESSAGE.getValue())); + } + + @ParameterizedTest + @DisplayName("구입금액이 0이하인경우 예외가 발생한다.") + @ValueSource(strings = {"-1", "0"}) + void givenLessZero_thenFail(final String purchaseAmount) { + assertThatThrownBy(() -> PurchaseAmountValidator.validate(purchaseAmount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(RANGE_MESSAGE.getValue(), Constants.ZERO.getValue())); + } +} diff --git a/src/test/java/validator/WinningNumbersValidators.java b/src/test/java/validator/WinningNumbersValidators.java new file mode 100644 index 00000000000..0d6deb5dcb4 --- /dev/null +++ b/src/test/java/validator/WinningNumbersValidators.java @@ -0,0 +1,40 @@ +package validator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import view.validator.WinningNumbersValidator; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static util.message.ExceptionMessage.*; + +public class WinningNumbersValidators { + + @DisplayName("당첨 번호의 개수가 6개가 넘어가면 예외가 발생한다.") + @ParameterizedTest + @CsvSource({"1,2,3,4,5,6,7"}) + void createWinningNumbersByOverSize(final String numbers) { + assertThatThrownBy(() -> WinningNumbersValidator.validate(numbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage((String.format(SIZE_OVER_MESSAGE.getValue(), "로또"))); + } + + @DisplayName("당첨 번호에 문자가 있으면 예외가 발생한다.") + @Test + void createWinningNumbersNumericVer1() { + String numbers = "1,,d,fd,fdf,dfef"; + assertThatThrownBy(() -> WinningNumbersValidator.validate(numbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(String.format(TYPE_MESSAGE.getValue()));; + } + + @DisplayName("당첨 번호가 범위를 벗어나면 예외가 발생한다.") + @Test + void createWinningNumbersRange() { + String numbers = "1,3,45,100,1,0"; + assertThatThrownBy(() -> WinningNumbersValidator.validate(numbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage((String.format(RANGE_START_BETWEEND_END.getValue(), 1, 45))); + } +}