From 88b578e1c304301e668dca5a033136135411b23e Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 16:15:26 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=84=20=EB=8B=B4=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Money.java | 32 ++++++++++++++++++++++++++++++ src/test/java/lotto/MoneyTest.java | 22 ++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/test/java/lotto/Money.java create mode 100644 src/test/java/lotto/MoneyTest.java diff --git a/src/test/java/lotto/Money.java b/src/test/java/lotto/Money.java new file mode 100644 index 0000000000..c7f2f65591 --- /dev/null +++ b/src/test/java/lotto/Money.java @@ -0,0 +1,32 @@ +package lotto; + +public class Money { + + private final int money; + + private Money(final int money) { + this.money = money; + } + + public static Money from(final int money) { + validate(money); + return new Money(money); + } + + private static void validate(final int money) { + validateNegative(money); + validateZero(money); + } + + private static void validateNegative(final int money) { + if (money < 0) { + throw new IllegalArgumentException("돈은 음수가 될 수 없습니다."); + } + } + + private static void validateZero(final int money) { + if (money == 0) { + throw new IllegalArgumentException("최소 1원 이상이어야 합니다."); + } + } +} diff --git a/src/test/java/lotto/MoneyTest.java b/src/test/java/lotto/MoneyTest.java new file mode 100644 index 0000000000..dba2f81d16 --- /dev/null +++ b/src/test/java/lotto/MoneyTest.java @@ -0,0 +1,22 @@ +package lotto; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +public class MoneyTest { + + @Test + void 돈은_음수가_될_수_없다() { + assertThatThrownBy(() ->Money.from(-1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("돈은 음수가 될 수 없습니다."); + } + + @Test + void 돈은_0원이_될_수_없다() { + assertThatThrownBy(() ->Money.from(0)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("최소 1원 이상이어야 합니다."); + } +} From 97b34d2433ef367fcce719f1daaa616832102129 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 16:17:25 +0900 Subject: [PATCH 02/14] =?UTF-8?q?refactor:=20Money=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Money.java | 19 +------------------ src/test/java/lotto/MoneyValidator.java | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 src/test/java/lotto/MoneyValidator.java diff --git a/src/test/java/lotto/Money.java b/src/test/java/lotto/Money.java index c7f2f65591..f57ba23d03 100644 --- a/src/test/java/lotto/Money.java +++ b/src/test/java/lotto/Money.java @@ -9,24 +9,7 @@ private Money(final int money) { } public static Money from(final int money) { - validate(money); + MoneyValidator.validate(money); return new Money(money); } - - private static void validate(final int money) { - validateNegative(money); - validateZero(money); - } - - private static void validateNegative(final int money) { - if (money < 0) { - throw new IllegalArgumentException("돈은 음수가 될 수 없습니다."); - } - } - - private static void validateZero(final int money) { - if (money == 0) { - throw new IllegalArgumentException("최소 1원 이상이어야 합니다."); - } - } } diff --git a/src/test/java/lotto/MoneyValidator.java b/src/test/java/lotto/MoneyValidator.java new file mode 100644 index 0000000000..64431dc6b4 --- /dev/null +++ b/src/test/java/lotto/MoneyValidator.java @@ -0,0 +1,21 @@ +package lotto; + +class MoneyValidator { + + static void validate(final int money) { + validateNegative(money); + validateZero(money); + } + + private static void validateNegative(final int money) { + if (money < 0) { + throw new IllegalArgumentException("돈은 음수가 될 수 없습니다."); + } + } + + private static void validateZero(final int money) { + if (money == 0) { + throw new IllegalArgumentException("최소 1원 이상이어야 합니다."); + } + } +} \ No newline at end of file From a124c3ebc31b35fa6bebb0a9e9baa13677bcfd23 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 16:45:23 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EB=A5=BC=20=EB=8B=B4=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoNumber.java | 21 +++++++++++++++++++++ src/test/java/lotto/LottoNumberTest.java | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/test/java/lotto/LottoNumber.java create mode 100644 src/test/java/lotto/LottoNumberTest.java diff --git a/src/test/java/lotto/LottoNumber.java b/src/test/java/lotto/LottoNumber.java new file mode 100644 index 0000000000..f5c8979452 --- /dev/null +++ b/src/test/java/lotto/LottoNumber.java @@ -0,0 +1,21 @@ +package lotto; + +public class LottoNumber { + + private final int value; + + private LottoNumber(final int value) { + this.value = value; + } + + public static LottoNumber from(final int value) { + validateNumberRange(value); + return new LottoNumber(value); + } + + private static void validateNumberRange(final int value) { + if (value < 1 || value > 45) { + throw new IllegalArgumentException("로또 번호는 1 ~ 45 사이의 숫자여야 합니다."); + } + } +} diff --git a/src/test/java/lotto/LottoNumberTest.java b/src/test/java/lotto/LottoNumberTest.java new file mode 100644 index 0000000000..253226dc9d --- /dev/null +++ b/src/test/java/lotto/LottoNumberTest.java @@ -0,0 +1,17 @@ +package lotto; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class LottoNumberTest { + + @ValueSource(ints = {0, 46}) + @ParameterizedTest + void 로또_번호는_1부터_45_사이의_숫자여야_한다(final int invalidLottoNumber) { + assertThatThrownBy(() -> LottoNumber.from(invalidLottoNumber)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 번호는 1 ~ 45 사이의 숫자여야 합니다."); + } +} From 62bbfc9e654b53b56e4b2868173fedf881e993ad Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 17:04:11 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=EB=A5=BC=20?= =?UTF-8?q?=EB=8B=B4=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Lotto.java | 40 +++++++++++++++++++++++++ src/test/java/lotto/LottoNumber.java | 19 ++++++++++++ src/test/java/lotto/LottoTest.java | 44 ++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 src/test/java/lotto/Lotto.java create mode 100644 src/test/java/lotto/LottoTest.java diff --git a/src/test/java/lotto/Lotto.java b/src/test/java/lotto/Lotto.java new file mode 100644 index 0000000000..c23d98fc8c --- /dev/null +++ b/src/test/java/lotto/Lotto.java @@ -0,0 +1,40 @@ +package lotto; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Lotto { + + private static final int LOTTO_NUMBER_COUNT = 6; + + private final List lottoNumbers; + + private Lotto(final List lottoNumbers) { + this.lottoNumbers = lottoNumbers; + } + + public static Lotto from(final List lottoNumbers) { + validate(lottoNumbers); + return new Lotto(lottoNumbers); + } + + private static void validate(final List lottoNumbers) { + validateLottoNumberCount(lottoNumbers); + validateLottoNumberDuplication(lottoNumbers); + } + + private static void validateLottoNumberCount(final List lottoNumbers) { + if (lottoNumbers.size() != LOTTO_NUMBER_COUNT) { + throw new IllegalArgumentException("로또 번호 개수는 6개여야 합니다."); + } + } + + private static void validateLottoNumberDuplication(final List lottoNumbers) { + final Set duplicatedLottoNumbers = new HashSet<>(lottoNumbers); + + if (duplicatedLottoNumbers.size() != LOTTO_NUMBER_COUNT) { + throw new IllegalArgumentException("로또는 중복된 번호가 존재할 수 없습니다."); + } + } +} diff --git a/src/test/java/lotto/LottoNumber.java b/src/test/java/lotto/LottoNumber.java index f5c8979452..0f438ca56c 100644 --- a/src/test/java/lotto/LottoNumber.java +++ b/src/test/java/lotto/LottoNumber.java @@ -1,5 +1,7 @@ package lotto; +import java.util.Objects; + public class LottoNumber { private final int value; @@ -18,4 +20,21 @@ private static void validateNumberRange(final int value) { throw new IllegalArgumentException("로또 번호는 1 ~ 45 사이의 숫자여야 합니다."); } } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final LottoNumber that = (LottoNumber) o; + return value == that.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } } diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java new file mode 100644 index 0000000000..b6fbd89567 --- /dev/null +++ b/src/test/java/lotto/LottoTest.java @@ -0,0 +1,44 @@ +package lotto; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class LottoTest { + + @MethodSource("provideLottoNumbers") + @ParameterizedTest + void 로또_번호_개수는_무조건_6개여야_한다(final List invalidLottoNumbers) { + assertThatThrownBy(() -> Lotto.from(invalidLottoNumbers)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 번호 개수는 6개여야 합니다."); + } + + @Test + void 로또는_중복된_번호가_존재할_수_없다() { + assertThatThrownBy(() -> Lotto.from(LottoTest.createLottoNumbers(1, 1, 3, 4, 5, 6))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또는 중복된 번호가 존재할 수 없습니다."); + } + + private static Stream provideLottoNumbers() { + return Stream.of( + arguments(createLottoNumbers(1, 2, 3, 4, 5)), + arguments(createLottoNumbers(1, 2, 3, 4, 5, 6, 7)) + ); + } + + private static List createLottoNumbers(final int... lottoNumbers) { + return Arrays.stream(lottoNumbers) + .mapToObj(LottoNumber::from) + .collect(Collectors.toList()); + } +} From 9add12f49a2b2c375a7d08fad26bd551b95a6292 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 17:06:14 +0900 Subject: [PATCH 05/14] =?UTF-8?q?refactor:=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Lotto.java | 25 +--------------------- src/test/java/lotto/LottoValidator.java | 28 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 src/test/java/lotto/LottoValidator.java diff --git a/src/test/java/lotto/Lotto.java b/src/test/java/lotto/Lotto.java index c23d98fc8c..544b125f44 100644 --- a/src/test/java/lotto/Lotto.java +++ b/src/test/java/lotto/Lotto.java @@ -1,13 +1,9 @@ package lotto; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class Lotto { - private static final int LOTTO_NUMBER_COUNT = 6; - private final List lottoNumbers; private Lotto(final List lottoNumbers) { @@ -15,26 +11,7 @@ private Lotto(final List lottoNumbers) { } public static Lotto from(final List lottoNumbers) { - validate(lottoNumbers); + LottoValidator.validate(lottoNumbers); return new Lotto(lottoNumbers); } - - private static void validate(final List lottoNumbers) { - validateLottoNumberCount(lottoNumbers); - validateLottoNumberDuplication(lottoNumbers); - } - - private static void validateLottoNumberCount(final List lottoNumbers) { - if (lottoNumbers.size() != LOTTO_NUMBER_COUNT) { - throw new IllegalArgumentException("로또 번호 개수는 6개여야 합니다."); - } - } - - private static void validateLottoNumberDuplication(final List lottoNumbers) { - final Set duplicatedLottoNumbers = new HashSet<>(lottoNumbers); - - if (duplicatedLottoNumbers.size() != LOTTO_NUMBER_COUNT) { - throw new IllegalArgumentException("로또는 중복된 번호가 존재할 수 없습니다."); - } - } } diff --git a/src/test/java/lotto/LottoValidator.java b/src/test/java/lotto/LottoValidator.java new file mode 100644 index 0000000000..b62cabd81e --- /dev/null +++ b/src/test/java/lotto/LottoValidator.java @@ -0,0 +1,28 @@ +package lotto; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LottoValidator { + + private static final int LOTTO_NUMBER_COUNT = 6; + static void validate(final List lottoNumbers) { + validateLottoNumberCount(lottoNumbers); + validateLottoNumberDuplication(lottoNumbers); + } + + static void validateLottoNumberCount(final List lottoNumbers) { + if (lottoNumbers.size() != LOTTO_NUMBER_COUNT) { + throw new IllegalArgumentException("로또 번호 개수는 6개여야 합니다."); + } + } + + static void validateLottoNumberDuplication(final List lottoNumbers) { + final Set duplicatedLottoNumbers = new HashSet(lottoNumbers); + + if (duplicatedLottoNumbers.size() != LOTTO_NUMBER_COUNT) { + throw new IllegalArgumentException("로또는 중복된 번호가 존재할 수 없습니다."); + } + } +} From 98e03110a3898296c293d239c5eb2f5c5eae8813 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 20:05:08 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=ED=8C=90?= =?UTF-8?q?=EB=A7=A4=ED=95=98=EB=8A=94=20=ED=8C=90=EB=A7=A4=EC=A0=90=20?= =?UTF-8?q?=EC=97=AD=ED=95=A0=EC=9D=84=20=ED=95=98=EB=8A=94=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoVendor.java | 23 +++++++++++++++++++++++ src/test/java/lotto/LottoVendorTest.java | 17 +++++++++++++++++ src/test/java/lotto/Money.java | 4 ++++ src/test/java/lotto/MoneyTest.java | 16 ++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/test/java/lotto/LottoVendor.java create mode 100644 src/test/java/lotto/LottoVendorTest.java diff --git a/src/test/java/lotto/LottoVendor.java b/src/test/java/lotto/LottoVendor.java new file mode 100644 index 0000000000..4b4e341f92 --- /dev/null +++ b/src/test/java/lotto/LottoVendor.java @@ -0,0 +1,23 @@ +package lotto; + +public class LottoVendor { + + private static final int LOTTO_PRICE = 1_000; + + private final Money money; + + private LottoVendor(final Money money) { + this.money = money; + } + + public static LottoVendor from(final Money money) { + validateMinimumAmount(money); + return new LottoVendor(money); + } + + private static void validateMinimumAmount(final Money money) { + if (!money.hasEnoughMoneyFor(LOTTO_PRICE)) { + throw new IllegalArgumentException("로또 한 장 가격은 1,000원입니다. 로또를 구매하시려면 1,000원 이상 입력해 주세요."); + } + } +} diff --git a/src/test/java/lotto/LottoVendorTest.java b/src/test/java/lotto/LottoVendorTest.java new file mode 100644 index 0000000000..b62b7ab634 --- /dev/null +++ b/src/test/java/lotto/LottoVendorTest.java @@ -0,0 +1,17 @@ +package lotto; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +public class LottoVendorTest { + + @Test + void 로또를_사려면_로또_한_장_가격의_돈은_줘야_한다() { + final Money money = Money.from(999); + + assertThatThrownBy(() -> LottoVendor.from(money)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("로또 한 장 가격은 1,000원입니다. 로또를 구매하시려면 1,000원 이상 입력해 주세요."); + } +} diff --git a/src/test/java/lotto/Money.java b/src/test/java/lotto/Money.java index f57ba23d03..3d774a3345 100644 --- a/src/test/java/lotto/Money.java +++ b/src/test/java/lotto/Money.java @@ -12,4 +12,8 @@ public static Money from(final int money) { MoneyValidator.validate(money); return new Money(money); } + + public boolean hasEnoughMoneyFor(final int price) { + return this.money >= price; + } } diff --git a/src/test/java/lotto/MoneyTest.java b/src/test/java/lotto/MoneyTest.java index dba2f81d16..c6d34bca15 100644 --- a/src/test/java/lotto/MoneyTest.java +++ b/src/test/java/lotto/MoneyTest.java @@ -1,8 +1,11 @@ package lotto; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class MoneyTest { @@ -19,4 +22,17 @@ public class MoneyTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("최소 1원 이상이어야 합니다."); } + + @CsvSource(value = { + "1, 2, false", + "2, 1, true" + }) + @ParameterizedTest + void 입력받은_가격보다_돈이_충분한지_판단한다(final int money, final int price, final boolean expected) { + final Money sut = Money.from(money); + + final boolean actual = sut.hasEnoughMoneyFor(price); + + assertThat(actual).isEqualTo(expected); + } } From 0581a332d2af93936b2e65cc2ac66c1d053dfa7b Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 20:40:37 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/lotto/LottoNumberAutoGenerator.java | 27 +++++++++++++++++++ src/test/java/lotto/LottoNumberGenerator.java | 8 ++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/java/lotto/LottoNumberAutoGenerator.java create mode 100644 src/test/java/lotto/LottoNumberGenerator.java diff --git a/src/test/java/lotto/LottoNumberAutoGenerator.java b/src/test/java/lotto/LottoNumberAutoGenerator.java new file mode 100644 index 0000000000..a769568cd8 --- /dev/null +++ b/src/test/java/lotto/LottoNumberAutoGenerator.java @@ -0,0 +1,27 @@ +package lotto; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class LottoNumberAutoGenerator implements LottoNumberGenerator { + + private static final List lottoNumbers; + + static { + lottoNumbers = IntStream.rangeClosed(LottoNumber.MIN_LOTTO_NUMBER, LottoNumber.MAX_LOTTO_NUMBER) + .boxed() + .collect(Collectors.toList()); + } + + @Override + public List generate() { + Collections.shuffle(lottoNumbers); + return lottoNumbers.stream() + .limit(6) + .sorted() + .map(LottoNumber::from) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/lotto/LottoNumberGenerator.java b/src/test/java/lotto/LottoNumberGenerator.java new file mode 100644 index 0000000000..76d6b9697e --- /dev/null +++ b/src/test/java/lotto/LottoNumberGenerator.java @@ -0,0 +1,8 @@ +package lotto; + +import java.util.List; + +public interface LottoNumberGenerator { + + List generate(); +} From f0ed79ad91a283dfb4f998836607a7e1366e0bde Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 20:41:36 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat:=20LottoVendor=20=EA=B0=80=20?= =?UTF-8?q?=EA=B5=AC=EB=A7=A4=20=EA=B0=80=EB=8A=A5=ED=95=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=EC=9D=98=20=EB=A1=9C=EB=98=90=EB=A5=BC=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8A=94=20=EC=97=AD=ED=95=A0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoNumber.java | 5 ++++- src/test/java/lotto/LottoVendor.java | 13 +++++++++++++ src/test/java/lotto/LottoVendorTest.java | 18 ++++++++++++++++++ src/test/java/lotto/Lottos.java | 16 ++++++++++++++++ src/test/java/lotto/Money.java | 4 ++++ src/test/java/lotto/MoneyTest.java | 9 +++++++++ 6 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/test/java/lotto/Lottos.java diff --git a/src/test/java/lotto/LottoNumber.java b/src/test/java/lotto/LottoNumber.java index 0f438ca56c..12b4b4ddd9 100644 --- a/src/test/java/lotto/LottoNumber.java +++ b/src/test/java/lotto/LottoNumber.java @@ -4,6 +4,9 @@ public class LottoNumber { + public static final int MIN_LOTTO_NUMBER = 1; + public static final int MAX_LOTTO_NUMBER = 45; + private final int value; private LottoNumber(final int value) { @@ -16,7 +19,7 @@ public static LottoNumber from(final int value) { } private static void validateNumberRange(final int value) { - if (value < 1 || value > 45) { + if (value < MIN_LOTTO_NUMBER || value > MAX_LOTTO_NUMBER) { throw new IllegalArgumentException("로또 번호는 1 ~ 45 사이의 숫자여야 합니다."); } } diff --git a/src/test/java/lotto/LottoVendor.java b/src/test/java/lotto/LottoVendor.java index 4b4e341f92..925c2322aa 100644 --- a/src/test/java/lotto/LottoVendor.java +++ b/src/test/java/lotto/LottoVendor.java @@ -1,5 +1,9 @@ package lotto; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + public class LottoVendor { private static final int LOTTO_PRICE = 1_000; @@ -20,4 +24,13 @@ private static void validateMinimumAmount(final Money money) { throw new IllegalArgumentException("로또 한 장 가격은 1,000원입니다. 로또를 구매하시려면 1,000원 이상 입력해 주세요."); } } + + public Lottos purchaseAutoLottos() { + final int purchasableCount = money.calculatePurchasableCount(LOTTO_PRICE); + final List purchasedAutoLottos = IntStream.rangeClosed(1, purchasableCount) + .mapToObj(i -> Lotto.from(new LottoNumberAutoGenerator().generate())) + .collect(Collectors.toList()); + + return new Lottos(purchasedAutoLottos); + } } diff --git a/src/test/java/lotto/LottoVendorTest.java b/src/test/java/lotto/LottoVendorTest.java index b62b7ab634..5a39268142 100644 --- a/src/test/java/lotto/LottoVendorTest.java +++ b/src/test/java/lotto/LottoVendorTest.java @@ -1,8 +1,11 @@ package lotto; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class LottoVendorTest { @@ -14,4 +17,19 @@ public class LottoVendorTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("로또 한 장 가격은 1,000원입니다. 로또를 구매하시려면 1,000원 이상 입력해 주세요."); } + + @CsvSource(value = { + "1000, 1", + "1500, 1", + "2000, 2" + }) + @ParameterizedTest + void 구매_가능한_개수만큼_로또를_반환한다(final int value, final int expected) { + final Money money = Money.from(value); + final LottoVendor sut = LottoVendor.from(money); + + final Lottos actual = sut.purchaseAutoLottos(); + + assertThat(actual.countPurchasedLottos()).isEqualTo(expected); + } } diff --git a/src/test/java/lotto/Lottos.java b/src/test/java/lotto/Lottos.java new file mode 100644 index 0000000000..023f7f3900 --- /dev/null +++ b/src/test/java/lotto/Lottos.java @@ -0,0 +1,16 @@ +package lotto; + +import java.util.List; + +public class Lottos { + + private final List lottos; + + public Lottos(final List lottos) { + this.lottos = lottos; + } + + public int countPurchasedLottos() { + return this.lottos.size(); + } +} diff --git a/src/test/java/lotto/Money.java b/src/test/java/lotto/Money.java index 3d774a3345..e4ee16f0c5 100644 --- a/src/test/java/lotto/Money.java +++ b/src/test/java/lotto/Money.java @@ -16,4 +16,8 @@ public static Money from(final int money) { public boolean hasEnoughMoneyFor(final int price) { return this.money >= price; } + + public int calculatePurchasableCount(final int price) { + return this.money / price; + } } diff --git a/src/test/java/lotto/MoneyTest.java b/src/test/java/lotto/MoneyTest.java index c6d34bca15..731270a839 100644 --- a/src/test/java/lotto/MoneyTest.java +++ b/src/test/java/lotto/MoneyTest.java @@ -35,4 +35,13 @@ public class MoneyTest { assertThat(actual).isEqualTo(expected); } + + @Test + void 입력받은_가격에_대해_구매_가능한_개수를_반환한다() { + final Money sut = Money.from(5000); + + final int actual = sut.calculatePurchasableCount(1000); + + assertThat(actual).isEqualTo(5); + } } From d82864a024d08b6d84239f866cf2233d4bd03fd5 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 20:49:53 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=EB=A5=BC=20=EB=8B=B4=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Lotto.java | 4 ++++ src/test/java/lotto/WinningLotto.java | 23 +++++++++++++++++++ src/test/java/lotto/WinningLottoTest.java | 27 +++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/test/java/lotto/WinningLotto.java create mode 100644 src/test/java/lotto/WinningLottoTest.java diff --git a/src/test/java/lotto/Lotto.java b/src/test/java/lotto/Lotto.java index 544b125f44..a929523233 100644 --- a/src/test/java/lotto/Lotto.java +++ b/src/test/java/lotto/Lotto.java @@ -14,4 +14,8 @@ public static Lotto from(final List lottoNumbers) { LottoValidator.validate(lottoNumbers); return new Lotto(lottoNumbers); } + + public boolean isContains(final LottoNumber lottoNumber) { + return lottoNumbers.contains(lottoNumber); + } } diff --git a/src/test/java/lotto/WinningLotto.java b/src/test/java/lotto/WinningLotto.java new file mode 100644 index 0000000000..92aa3b74db --- /dev/null +++ b/src/test/java/lotto/WinningLotto.java @@ -0,0 +1,23 @@ +package lotto; + +public class WinningLotto { + + private final Lotto winningLotto; + private final LottoNumber bonusLottoNumber; + + private WinningLotto(final Lotto winningLotto, final LottoNumber bonusLottoNumber) { + this.winningLotto = winningLotto; + this.bonusLottoNumber = bonusLottoNumber; + } + + public static WinningLotto of(final Lotto winningLotto, final LottoNumber bonusLottoNumber) { + validateDuplication(winningLotto, bonusLottoNumber); + return new WinningLotto(winningLotto, bonusLottoNumber); + } + + private static void validateDuplication(final Lotto winningLotto, final LottoNumber bonusLottoNumber) { + if (winningLotto.isContains(bonusLottoNumber)) { + throw new IllegalArgumentException("당첨 번호와 보너스 번호는 겹칠 수 없습니다."); + } + } +} diff --git a/src/test/java/lotto/WinningLottoTest.java b/src/test/java/lotto/WinningLottoTest.java new file mode 100644 index 0000000000..1a30a09d35 --- /dev/null +++ b/src/test/java/lotto/WinningLottoTest.java @@ -0,0 +1,27 @@ +package lotto; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +public class WinningLottoTest { + + @Test + void 보너스_번호는_당첨_로또_번호와_겹칠_수_없다() { + final Lotto lotto = Lotto.from(createLottoNumbers(1, 2, 3, 4, 5, 6)); + final LottoNumber lottoNumber = LottoNumber.from(1); + + assertThatThrownBy(() -> WinningLotto.of(lotto, lottoNumber)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("당첨 번호와 보너스 번호는 겹칠 수 없습니다."); + } + + private List createLottoNumbers(final int... lottoNumbers) { + return Arrays.stream(lottoNumbers) + .mapToObj(LottoNumber::from) + .collect(Collectors.toList()); + } +} From efc5b512cbc388959ed893e4be1a30906ea0fe7d Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 21:23:48 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=93=B1?= =?UTF-8?q?=EC=88=98=20=EA=B2=B0=EC=A0=95=ED=95=98=EB=8A=94=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoRank.java | 35 ++++++++++++++++++++++++++ src/test/java/lotto/LottoRankTest.java | 30 ++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/test/java/lotto/LottoRank.java create mode 100644 src/test/java/lotto/LottoRankTest.java diff --git a/src/test/java/lotto/LottoRank.java b/src/test/java/lotto/LottoRank.java new file mode 100644 index 0000000000..cb518c35b1 --- /dev/null +++ b/src/test/java/lotto/LottoRank.java @@ -0,0 +1,35 @@ +package lotto; + +import java.util.Arrays; + +public enum LottoRank { + + FIRST(6, 2000000000), + SECOND(5, 1500000), + THIRD(5, 50000), + FOURTH(4, 5000), + FIFTH(3, 0), + UNRANKED(0, 0) + ; + + private final int hitCount; + private final int reward; + + LottoRank(final int hitCount, final int reward) { + this.hitCount = hitCount; + this.reward = reward; + } + + public static LottoRank of(final int hitCount, final boolean hasBonusNumber) { + return Arrays.stream(LottoRank.values()) + .filter(lottoRank -> lottoRank.isSameHitCount(hitCount)) + .filter(lottoRank -> !lottoRank.equals(SECOND) || hasBonusNumber) + .findFirst() + .orElse(UNRANKED); + } + + private boolean isSameHitCount(final int hitCount) { + return this.hitCount == hitCount; + } +} + diff --git a/src/test/java/lotto/LottoRankTest.java b/src/test/java/lotto/LottoRankTest.java new file mode 100644 index 0000000000..0b95679122 --- /dev/null +++ b/src/test/java/lotto/LottoRankTest.java @@ -0,0 +1,30 @@ +package lotto; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class LottoRankTest { + + @CsvSource(value = { + "6, false, FIRST", + "5, true, SECOND", + "5, false, THIRD", + "4, true, FOURTH", + "4, false, FOURTH", + "3, true, FIFTH", + "3, false, FIFTH", + "2, true, UNRANKED", + "2, false, UNRANKED", + "1, true, UNRANKED", + "1, false, UNRANKED", + "0, false, UNRANKED" + }) + @ParameterizedTest + void 로또_번호_적중_횟수와_보너스_번호_유무에_따른_등수를_반환한다(final int hitCount, final boolean hasBonusNumber, final LottoRank expected) { + final LottoRank actual = LottoRank.of(hitCount, hasBonusNumber); + + assertThat(actual).isEqualTo(expected); + } +} From faec033e1ae52cabcb9f68386282af20f1e5968e Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 21:55:46 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EB=8B=B4=EB=8A=94=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/Lotto.java | 6 +++++ src/test/java/lotto/LottoResult.java | 21 +++++++++++++++ src/test/java/lotto/LottoTest.java | 12 ++++++++- src/test/java/lotto/Lottos.java | 4 +++ src/test/java/lotto/WinningLotto.java | 7 +++++ src/test/java/lotto/WinningLottoTest.java | 33 +++++++++++++++++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/test/java/lotto/LottoResult.java diff --git a/src/test/java/lotto/Lotto.java b/src/test/java/lotto/Lotto.java index a929523233..b8796a5253 100644 --- a/src/test/java/lotto/Lotto.java +++ b/src/test/java/lotto/Lotto.java @@ -18,4 +18,10 @@ public static Lotto from(final List lottoNumbers) { public boolean isContains(final LottoNumber lottoNumber) { return lottoNumbers.contains(lottoNumber); } + + public int calculateHitCount(final Lotto lotto) { + return (int) lottoNumbers.stream() + .filter(lotto::isContains) + .count(); + } } diff --git a/src/test/java/lotto/LottoResult.java b/src/test/java/lotto/LottoResult.java new file mode 100644 index 0000000000..1cf965364d --- /dev/null +++ b/src/test/java/lotto/LottoResult.java @@ -0,0 +1,21 @@ +package lotto; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.summingInt; + +import java.util.Map; + +public class LottoResult { + + private final Map rankResults; + + private LottoResult(final Map rankResults) { + this.rankResults = rankResults; + } + + public static LottoResult of(final Lottos lottos, final WinningLotto winningLotto) { + final Map rankResults = lottos.lottos().stream() + .collect(groupingBy(winningLotto::calculateRank, summingInt(value -> 1))); + return new LottoResult(rankResults); + } +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index b6fbd89567..14053aae25 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -1,5 +1,6 @@ package lotto; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -24,11 +25,20 @@ public class LottoTest { @Test void 로또는_중복된_번호가_존재할_수_없다() { - assertThatThrownBy(() -> Lotto.from(LottoTest.createLottoNumbers(1, 1, 3, 4, 5, 6))) + assertThatThrownBy(() -> Lotto.from(createLottoNumbers(1, 1, 3, 4, 5, 6))) .isInstanceOf(IllegalArgumentException.class) .hasMessage("로또는 중복된 번호가 존재할 수 없습니다."); } + @Test + void 로또_번호_적중_횟수를_계산한다() { + final Lotto sut = Lotto.from(createLottoNumbers(1, 2, 3, 4, 5, 6)); + + final int actual = sut.calculateHitCount(Lotto.from(createLottoNumbers(1, 2, 3, 4, 5, 7))); + + assertThat(actual).isEqualTo(5); + } + private static Stream provideLottoNumbers() { return Stream.of( arguments(createLottoNumbers(1, 2, 3, 4, 5)), diff --git a/src/test/java/lotto/Lottos.java b/src/test/java/lotto/Lottos.java index 023f7f3900..88ecbb979b 100644 --- a/src/test/java/lotto/Lottos.java +++ b/src/test/java/lotto/Lottos.java @@ -13,4 +13,8 @@ public Lottos(final List lottos) { public int countPurchasedLottos() { return this.lottos.size(); } + + public List lottos() { + return List.copyOf(this.lottos); + } } diff --git a/src/test/java/lotto/WinningLotto.java b/src/test/java/lotto/WinningLotto.java index 92aa3b74db..d825322cc7 100644 --- a/src/test/java/lotto/WinningLotto.java +++ b/src/test/java/lotto/WinningLotto.java @@ -20,4 +20,11 @@ private static void validateDuplication(final Lotto winningLotto, final LottoNum throw new IllegalArgumentException("당첨 번호와 보너스 번호는 겹칠 수 없습니다."); } } + + public LottoRank calculateRank(final Lotto lotto) { + final int hitCount = lotto.calculateHitCount(this.winningLotto); + final boolean hasBonusNumber = lotto.isContains(this.bonusLottoNumber); + + return LottoRank.of(hitCount, hasBonusNumber); + } } diff --git a/src/test/java/lotto/WinningLottoTest.java b/src/test/java/lotto/WinningLottoTest.java index 1a30a09d35..ee52c9fd04 100644 --- a/src/test/java/lotto/WinningLottoTest.java +++ b/src/test/java/lotto/WinningLottoTest.java @@ -1,11 +1,17 @@ package lotto; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.params.provider.Arguments.arguments; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class WinningLottoTest { @@ -19,6 +25,33 @@ public class WinningLottoTest { .hasMessage("당첨 번호와 보너스 번호는 겹칠 수 없습니다."); } + @MethodSource("provideLotto") + @ParameterizedTest + void 당첨_로또와_내가_구매한_로또를_가지고_등수를_확인한다(final int[] lottoNumbers, final LottoRank expected) { + final WinningLotto sut = WinningLotto.of(Lotto.from(createLottoNumbers(1, 2, 3, 4, 5, 6)), LottoNumber.from(7)); + + final LottoRank actual = sut.calculateRank(Lotto.from(createLottoNumbers(lottoNumbers))); + + assertThat(actual).isEqualTo(expected); + } + + public static Stream provideLotto() { + return Stream.of( + arguments(new int[]{1, 2, 3, 4, 5, 6}, LottoRank.FIRST), + arguments(new int[] {2, 3, 4, 5, 6, 7}, LottoRank.SECOND), + arguments(new int[] {2, 3, 4, 5, 6, 8}, LottoRank.THIRD), + arguments(new int[] {3, 4, 5, 6, 7, 8}, LottoRank.FOURTH), + arguments(new int[] {3, 4, 5, 6, 8, 9}, LottoRank.FOURTH), + arguments(new int[] {4, 5, 6, 7, 8, 9}, LottoRank.FIFTH), + arguments(new int[] {4, 5, 6, 8, 9, 10}, LottoRank.FIFTH), + arguments(new int[] {5, 6, 7, 8, 9, 10}, LottoRank.UNRANKED), + arguments(new int[] {5, 6, 8, 9, 10, 11}, LottoRank.UNRANKED), + arguments(new int[] {6, 7, 8, 9, 10, 11}, LottoRank.UNRANKED), + arguments(new int[] {6, 8, 9, 10, 11, 12}, LottoRank.UNRANKED), + arguments(new int[] {8, 9, 10, 11, 12, 13}, LottoRank.UNRANKED) + ); + } + private List createLottoNumbers(final int... lottoNumbers) { return Arrays.stream(lottoNumbers) .mapToObj(LottoNumber::from) From 0b508268e76c8908c666a9459f95e13fcefef3a7 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 22:07:32 +0900 Subject: [PATCH 12/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=88=98?= =?UTF-8?q?=EC=9D=B5=EB=A5=A0=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/LottoRank.java | 8 ++++++-- src/test/java/lotto/LottoResult.java | 20 ++++++++++++++++++++ src/test/java/lotto/LottoVendor.java | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/test/java/lotto/LottoRank.java b/src/test/java/lotto/LottoRank.java index cb518c35b1..4cd15777b2 100644 --- a/src/test/java/lotto/LottoRank.java +++ b/src/test/java/lotto/LottoRank.java @@ -13,9 +13,9 @@ public enum LottoRank { ; private final int hitCount; - private final int reward; + private final long reward; - LottoRank(final int hitCount, final int reward) { + LottoRank(final int hitCount, final long reward) { this.hitCount = hitCount; this.reward = reward; } @@ -31,5 +31,9 @@ public static LottoRank of(final int hitCount, final boolean hasBonusNumber) { private boolean isSameHitCount(final int hitCount) { return this.hitCount == hitCount; } + + public long reward() { + return this.reward; + } } diff --git a/src/test/java/lotto/LottoResult.java b/src/test/java/lotto/LottoResult.java index 1cf965364d..c877480157 100644 --- a/src/test/java/lotto/LottoResult.java +++ b/src/test/java/lotto/LottoResult.java @@ -18,4 +18,24 @@ public static LottoResult of(final Lottos lottos, final WinningLotto winningLott .collect(groupingBy(winningLotto::calculateRank, summingInt(value -> 1))); return new LottoResult(rankResults); } + + public double calculateProfitRate() { + final long totalReward = calculateTotalReward(); + final int purchaseAmount = calculatePurchaseAmount(); + + return totalReward / (double) purchaseAmount; + } + + private long calculateTotalReward() { + return this.rankResults.entrySet().stream() + .map(rankResult -> rankResult.getKey().reward() * rankResult.getValue()) + .reduce(0L, Long::sum); + } + + private int calculatePurchaseAmount() { + final int numberOfPurchases = this.rankResults.values().stream() + .mapToInt(i -> i) + .sum(); + return numberOfPurchases * LottoVendor.LOTTO_PRICE; + } } diff --git a/src/test/java/lotto/LottoVendor.java b/src/test/java/lotto/LottoVendor.java index 925c2322aa..3a4d1e02d8 100644 --- a/src/test/java/lotto/LottoVendor.java +++ b/src/test/java/lotto/LottoVendor.java @@ -6,7 +6,7 @@ public class LottoVendor { - private static final int LOTTO_PRICE = 1_000; + public static final int LOTTO_PRICE = 1_000; private final Money money; From acaff47c09b4dd90ab9a2d2c1a47148058b1c945 Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 22:57:32 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20STEP=201=20View=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/InputView.java | 37 +++++++++++++++++ src/test/java/lotto/Lotto.java | 4 ++ src/test/java/lotto/LottoApplication.java | 9 +++++ src/test/java/lotto/LottoController.java | 23 +++++++++++ src/test/java/lotto/LottoNumber.java | 4 ++ src/test/java/lotto/LottoRank.java | 8 ++++ src/test/java/lotto/LottoResult.java | 4 ++ src/test/java/lotto/OutputView.java | 48 +++++++++++++++++++++++ 8 files changed, 137 insertions(+) create mode 100644 src/test/java/lotto/InputView.java create mode 100644 src/test/java/lotto/LottoApplication.java create mode 100644 src/test/java/lotto/LottoController.java create mode 100644 src/test/java/lotto/OutputView.java diff --git a/src/test/java/lotto/InputView.java b/src/test/java/lotto/InputView.java new file mode 100644 index 0000000000..33f9991ed3 --- /dev/null +++ b/src/test/java/lotto/InputView.java @@ -0,0 +1,37 @@ +package lotto; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + + private static final Scanner SCANNER = new Scanner(System.in); + + public static int inputMoney() { + try { + System.out.println("구매금액을 입력해 주세요."); + return Integer.parseInt(SCANNER.nextLine()); + } catch (NumberFormatException e) { + throw new NumberFormatException("구매금액은 숫자로 입력해 주세요."); + } + } + + public static List inputWinningLottoNumbers() { + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + return Arrays.stream(SCANNER.nextLine().split(",")) + .map(Integer::parseInt) + .map(LottoNumber::from) + .collect(Collectors.toList()); + } + + public static int inputWinningBonus() { + try { + System.out.println("보너스 볼을 입력해 주세요."); + return Integer.parseInt(SCANNER.nextLine()); + } catch (NumberFormatException e) { + throw new NumberFormatException("구매금액은 숫자로 입력해 주세요."); + } + } +} diff --git a/src/test/java/lotto/Lotto.java b/src/test/java/lotto/Lotto.java index b8796a5253..a633b7433f 100644 --- a/src/test/java/lotto/Lotto.java +++ b/src/test/java/lotto/Lotto.java @@ -24,4 +24,8 @@ public int calculateHitCount(final Lotto lotto) { .filter(lotto::isContains) .count(); } + + public List lottoNumbers() { + return this.lottoNumbers; + } } diff --git a/src/test/java/lotto/LottoApplication.java b/src/test/java/lotto/LottoApplication.java new file mode 100644 index 0000000000..1289733da6 --- /dev/null +++ b/src/test/java/lotto/LottoApplication.java @@ -0,0 +1,9 @@ +package lotto; + +public class LottoApplication { + + public static void main(String[] args) { + final LottoController lottoController = new LottoController(); + lottoController.run(); + } +} diff --git a/src/test/java/lotto/LottoController.java b/src/test/java/lotto/LottoController.java new file mode 100644 index 0000000000..147ad539b2 --- /dev/null +++ b/src/test/java/lotto/LottoController.java @@ -0,0 +1,23 @@ +package lotto; + +public class LottoController { + + public void run() { + try { + final Money money = Money.from(InputView.inputMoney()); + final LottoVendor lottoVendor = LottoVendor.from(money); + final Lottos lottos = lottoVendor.purchaseAutoLottos(); + OutputView.printLottoPurchaseResult(lottos); + + final Lotto lotto = Lotto.from(InputView.inputWinningLottoNumbers()); + final LottoNumber bonusLottoNumber = LottoNumber.from(InputView.inputWinningBonus()); + final WinningLotto winningLotto = WinningLotto.of(lotto, bonusLottoNumber); + + final LottoResult lottoResult = LottoResult.of(lottos, winningLotto); + OutputView.printLottoResult(lottoResult); + } catch (IllegalArgumentException e) { + OutputView.printExceptionMessage(e); + run(); + } + } +} diff --git a/src/test/java/lotto/LottoNumber.java b/src/test/java/lotto/LottoNumber.java index 12b4b4ddd9..3816d6639f 100644 --- a/src/test/java/lotto/LottoNumber.java +++ b/src/test/java/lotto/LottoNumber.java @@ -24,6 +24,10 @@ private static void validateNumberRange(final int value) { } } + public int value() { + return this.value; + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/test/java/lotto/LottoRank.java b/src/test/java/lotto/LottoRank.java index 4cd15777b2..3e8d6aa049 100644 --- a/src/test/java/lotto/LottoRank.java +++ b/src/test/java/lotto/LottoRank.java @@ -32,6 +32,14 @@ private boolean isSameHitCount(final int hitCount) { return this.hitCount == hitCount; } + public boolean hasReward() { + return this.reward != 0; + } + + public int hitCount() { + return this.hitCount; + } + public long reward() { return this.reward; } diff --git a/src/test/java/lotto/LottoResult.java b/src/test/java/lotto/LottoResult.java index c877480157..74a2aba283 100644 --- a/src/test/java/lotto/LottoResult.java +++ b/src/test/java/lotto/LottoResult.java @@ -19,6 +19,10 @@ public static LottoResult of(final Lottos lottos, final WinningLotto winningLott return new LottoResult(rankResults); } + public int CountBy(final LottoRank lottoRank) { + return this.rankResults.getOrDefault(lottoRank, 0); + } + public double calculateProfitRate() { final long totalReward = calculateTotalReward(); final int purchaseAmount = calculatePurchaseAmount(); diff --git a/src/test/java/lotto/OutputView.java b/src/test/java/lotto/OutputView.java new file mode 100644 index 0000000000..82811d998e --- /dev/null +++ b/src/test/java/lotto/OutputView.java @@ -0,0 +1,48 @@ +package lotto; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + + public static void printExceptionMessage(final Exception e) { + System.out.println(e.getMessage()); + } + + public static void printLottoPurchaseResult(final Lottos lottos) { + System.out.printf("%d개를 구매했습니다.\n", lottos.countPurchasedLottos()); + lottos.lottos() + .forEach(lotto -> { + final String lottoNumbers = lotto.lottoNumbers().stream() + .map(LottoNumber::value) + .map(String::valueOf) + .collect(Collectors.joining(", ")); + System.out.printf("[%s]\n", lottoNumbers); + }); + } + + public static void printLottoResult(final LottoResult lottoResult) { + System.out.println("당첨 통계"); + System.out.println("---------"); + getLottoRanks().stream() + .filter(LottoRank::hasReward) + .forEach(lottoRank -> printRankResult(lottoRank, lottoResult.CountBy(lottoRank))); + System.out.printf("총 수익률은 %.2f입니다.\n", lottoResult.calculateProfitRate()); + } + + private static List getLottoRanks() { + final List lottoRanks = Arrays.asList(LottoRank.values()); + Collections.reverse(lottoRanks); + return lottoRanks; + } + + private static void printRankResult(final LottoRank lottoRank, final int rankCount) { + if (lottoRank == LottoRank.SECOND) { + System.out.printf("%d개 일치, 보너스 볼 일치 (%d원) - %d개\n", lottoRank.hitCount(), lottoRank.reward(), rankCount); + return; + } + System.out.printf("%d개 일치 (%d원) - %d개\n", lottoRank.hitCount(), lottoRank.reward(), rankCount); + } +} From 8da1b9db41548a9c516b694c219faeea26ba2e5f Mon Sep 17 00:00:00 2001 From: jjanggu Date: Sun, 19 May 2024 23:19:27 +0900 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20STEP=202=20View=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/lotto/InputView.java | 28 ++++++++++++++++++++++++ src/test/java/lotto/LottoController.java | 9 +++++--- src/test/java/lotto/LottoResult.java | 24 +++++++++++++++++--- src/test/java/lotto/LottoVendor.java | 10 ++++++++- src/test/java/lotto/Money.java | 7 ++++++ src/test/java/lotto/OutputView.java | 22 ++++++++++--------- 6 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/test/java/lotto/InputView.java b/src/test/java/lotto/InputView.java index 33f9991ed3..bd337db3f9 100644 --- a/src/test/java/lotto/InputView.java +++ b/src/test/java/lotto/InputView.java @@ -1,5 +1,6 @@ package lotto; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; @@ -18,6 +19,33 @@ public static int inputMoney() { } } + public static int inputManualCount() { + try { + System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); + return Integer.parseInt(SCANNER.nextLine()); + } catch (NumberFormatException e) { + throw new NumberFormatException("구매금액은 숫자로 입력해 주세요."); + } + } + + public static List inputManualLottoNumbers(final int counts) { + System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); + List manualLottos = new ArrayList<>(); + for (int i = 0; i < counts; i++) { + manualLottos.add(Lotto.from(inputLottoNumber())); + } + return manualLottos; + } + + private static List inputLottoNumber() { + String[] input = SCANNER.nextLine().split(","); + return Arrays.stream(input) + .map(String::trim) + .map(Integer::parseInt) + .map(LottoNumber::from) + .collect(Collectors.toList()); + } + public static List inputWinningLottoNumbers() { System.out.println("지난 주 당첨 번호를 입력해 주세요."); return Arrays.stream(SCANNER.nextLine().split(",")) diff --git a/src/test/java/lotto/LottoController.java b/src/test/java/lotto/LottoController.java index 147ad539b2..6ca858654a 100644 --- a/src/test/java/lotto/LottoController.java +++ b/src/test/java/lotto/LottoController.java @@ -6,14 +6,17 @@ public void run() { try { final Money money = Money.from(InputView.inputMoney()); final LottoVendor lottoVendor = LottoVendor.from(money); - final Lottos lottos = lottoVendor.purchaseAutoLottos(); - OutputView.printLottoPurchaseResult(lottos); + + final int manualCount = InputView.inputManualCount(); + final Lottos manualLottos = lottoVendor.purchaseManualLottos(InputView.inputManualLottoNumbers(manualCount)); + final Lottos autoLottos = lottoVendor.purchaseAutoLottos(); + OutputView.printLottoPurchaseResult(manualLottos, autoLottos); final Lotto lotto = Lotto.from(InputView.inputWinningLottoNumbers()); final LottoNumber bonusLottoNumber = LottoNumber.from(InputView.inputWinningBonus()); final WinningLotto winningLotto = WinningLotto.of(lotto, bonusLottoNumber); - final LottoResult lottoResult = LottoResult.of(lottos, winningLotto); + final LottoResult lottoResult = LottoResult.of(manualLottos, autoLottos, winningLotto); OutputView.printLottoResult(lottoResult); } catch (IllegalArgumentException e) { OutputView.printExceptionMessage(e); diff --git a/src/test/java/lotto/LottoResult.java b/src/test/java/lotto/LottoResult.java index 74a2aba283..6106fd876d 100644 --- a/src/test/java/lotto/LottoResult.java +++ b/src/test/java/lotto/LottoResult.java @@ -3,6 +3,7 @@ import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.summingInt; +import java.util.EnumMap; import java.util.Map; public class LottoResult { @@ -13,10 +14,27 @@ private LottoResult(final Map rankResults) { this.rankResults = rankResults; } - public static LottoResult of(final Lottos lottos, final WinningLotto winningLotto) { - final Map rankResults = lottos.lottos().stream() + public static LottoResult of(final Lottos manualLottos, final Lottos autoLottos, final WinningLotto winningLotto) { + final Map manualLottoResults = groupBy(manualLottos, winningLotto); + final Map autoLottoResults = groupBy(autoLottos, winningLotto); + final Map results = mergeResults(manualLottoResults, autoLottoResults); + + return new LottoResult(results); + } + + private static Map groupBy(final Lottos autoLottos, final WinningLotto winningLotto) { + return autoLottos.lottos().stream() .collect(groupingBy(winningLotto::calculateRank, summingInt(value -> 1))); - return new LottoResult(rankResults); + } + + private static Map mergeResults(Map manualResults, Map autoResults) { + Map combinedResults = new EnumMap<>(LottoRank.class); + + for (LottoRank rank : LottoRank.values()) { + combinedResults.put(rank, manualResults.getOrDefault(rank, 0) + autoResults.getOrDefault(rank, 0)); + } + + return combinedResults; } public int CountBy(final LottoRank lottoRank) { diff --git a/src/test/java/lotto/LottoVendor.java b/src/test/java/lotto/LottoVendor.java index 3a4d1e02d8..dd8be5ae3b 100644 --- a/src/test/java/lotto/LottoVendor.java +++ b/src/test/java/lotto/LottoVendor.java @@ -8,7 +8,7 @@ public class LottoVendor { public static final int LOTTO_PRICE = 1_000; - private final Money money; + private Money money; private LottoVendor(final Money money) { this.money = money; @@ -33,4 +33,12 @@ public Lottos purchaseAutoLottos() { return new Lottos(purchasedAutoLottos); } + + public Lottos purchaseManualLottos(final List lottos) { + final int priceOfLottos = lottos.size() * LOTTO_PRICE; + + this.money = money.minus(priceOfLottos); + + return new Lottos(lottos); + } } diff --git a/src/test/java/lotto/Money.java b/src/test/java/lotto/Money.java index e4ee16f0c5..0acd794db1 100644 --- a/src/test/java/lotto/Money.java +++ b/src/test/java/lotto/Money.java @@ -20,4 +20,11 @@ public boolean hasEnoughMoneyFor(final int price) { public int calculatePurchasableCount(final int price) { return this.money / price; } + + public Money minus(final int price) { + if (!hasEnoughMoneyFor(price)) { + throw new IllegalArgumentException("금액이 부족합니다."); + } + return Money.from(this.money - price); + } } diff --git a/src/test/java/lotto/OutputView.java b/src/test/java/lotto/OutputView.java index 82811d998e..599db62c53 100644 --- a/src/test/java/lotto/OutputView.java +++ b/src/test/java/lotto/OutputView.java @@ -11,16 +11,18 @@ public static void printExceptionMessage(final Exception e) { System.out.println(e.getMessage()); } - public static void printLottoPurchaseResult(final Lottos lottos) { - System.out.printf("%d개를 구매했습니다.\n", lottos.countPurchasedLottos()); - lottos.lottos() - .forEach(lotto -> { - final String lottoNumbers = lotto.lottoNumbers().stream() - .map(LottoNumber::value) - .map(String::valueOf) - .collect(Collectors.joining(", ")); - System.out.printf("[%s]\n", lottoNumbers); - }); + public static void printLottoPurchaseResult(final Lottos manualLottos, final Lottos autoLottos) { + System.out.printf("수동으로 %d장, 자동으로 %d개를 구매했습니다.\n", manualLottos.countPurchasedLottos(), autoLottos.countPurchasedLottos()); + manualLottos.lottos().forEach(OutputView::printLottos); + autoLottos.lottos().forEach(OutputView::printLottos); + } + + private static void printLottos(final Lotto lotto) { + final String lottoNumbers = lotto.lottoNumbers().stream() + .map(LottoNumber::value) + .map(String::valueOf) + .collect(Collectors.joining(", ")); + System.out.printf("[%s]\n", lottoNumbers); } public static void printLottoResult(final LottoResult lottoResult) {