diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index b4d5da5..4f47327 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,26 +1,62 @@ package controller; -import model.*; +import model.Height; +import model.Players; +import model.PointGenerator; +import model.Prizes; +import model.Ladder; +import model.LadderResult; +import model.RandomValueGenerator; +import model.Point; +import view.InputView; import view.ResultView; - import java.util.ArrayList; import java.util.List; -import java.util.Random; import static model.Point.HAS_POINT; public class LadderController { - private static final int LADDER_SIZE = 4; - private static final int CHUNK_SIZE = 3; + private static final String ALL_PLAYERS = "all"; private final ResultView resultView = new ResultView(); + private final InputView inputView = new InputView(); public void startLadder() { - PointGenerator pointGenerator = new PointGenerator(new Random()); - LadderGame ladderGame = new LadderGame(new Size(LADDER_SIZE), new Size(LADDER_SIZE), pointGenerator); - List ladderPoints = ladderGame.getLadderPoints(); - List points = formatLadderPoints(ladderPoints); - List> ladderLines = processLadderLines(points); - resultView.printLadder(ladderLines); + Players players = new Players(inputView.inputNames()); + Prizes prizes = Prizes.createPrizes(inputView.inputResult(), players); + Height height = new Height(inputView.getMaxLadderHeight()); + PointGenerator pointGenerator = new PointGenerator(new RandomValueGenerator()); + + Ladder ladder = Ladder.createLadder(players.size(), height.getValue(), pointGenerator); + LadderResult ladderResult = calculateLadderResult(ladder, players.getPlayers(), prizes); + + printLadder(ladder, players, prizes); + printResult(ladderResult); + } + + private LadderResult calculateLadderResult(Ladder ladder, List players, Prizes prizes) { + LadderResult ladderResult = new LadderResult(ladder); + ladderResult.calculateResults(players, prizes); + return ladderResult; + } + + private void printLadder(Ladder ladder, Players players, Prizes prizes) { + List points = formatLadderPoints(ladder.getPointsFromLines()); + List> ladderLines = processLadderLines(points, players.size()); + resultView.printLadder(ladderLines, players.getPlayers(), prizes.getPrize()); + } + + private void printResult(LadderResult ladderResult) { + while (true) { + String targetPlayerName = inputView.getTargetPlayerName(); + + if (targetPlayerName.equals(ALL_PLAYERS)) { + resultView.printAllResults(ladderResult.getValue()); + break; + } + if (ladderResult.getValue().containsKey(targetPlayerName)) { + resultView.printSingleResult(ladderResult.getResultForPlayer(targetPlayerName)); + } + } } private List formatLadderPoints(List ladderPoints) { @@ -31,15 +67,16 @@ private List formatLadderPoints(List ladderPoints) { return formattedLadder; } - private List> processLadderLines(List ladderPoints) { + private List> processLadderLines(List ladderPoints, int numPlayers) { + int lineCount = numPlayers - 1; List> chunks = new ArrayList<>(); - for (int i = 0; i < ladderPoints.size(); i += CHUNK_SIZE) { - chunks.add(getLadderSegment(ladderPoints, i)); + for (int i = 0; i < ladderPoints.size(); i += lineCount) { + chunks.add(getLadderSegment(ladderPoints, i, lineCount)); } return chunks; } - private List getLadderSegment(List ladderPoints, int startIndex) { - return ladderPoints.subList(startIndex, Math.min(startIndex + CHUNK_SIZE, ladderPoints.size())); + private List getLadderSegment(List ladderPoints, int startIndex, int lineCount) { + return ladderPoints.subList(startIndex, Math.min(startIndex + lineCount, ladderPoints.size())); } } diff --git a/src/main/java/exception/ExceptionMessage.java b/src/main/java/exception/ExceptionMessage.java new file mode 100644 index 0000000..c9d5569 --- /dev/null +++ b/src/main/java/exception/ExceptionMessage.java @@ -0,0 +1,24 @@ +package exception; + +public enum ExceptionMessage { + LADDER_HEIGHT_MIN_VALUE("사다리 높이는 최소 2 이상이어야 합니다."), + LADDER_SIZE_NEGATIVE("사다리 사이즈가 0보다 작을 수는 없습니다."), + LADDER_HEIGHT_NOT_NUMBER("사다리 높이는 숫자여야 합니다."), + + PLAYER_NAME_MAX_LENGTH_EXCEEDED("참가자 이름은 최대 5글자를 초과할 수 없습니다."), + MIN_PLAYERS_REQUIRED("참가자는 최소 2명 이상이여야 합니다."), + + RESULT_COUNT_MISMATCH("실행결과 개수와 참가자의 수는 동일해야 합니다."), + RESULT_NOT_NULL_OR_EMPTY("실행결과는 null이거나 공백일 수는 없습니다."), + NULL_OR_EMPTY_INPUT("입력값이 null이거나 비어있을 순 없습니다."); + + private final String message; + + ExceptionMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/model/Height.java b/src/main/java/model/Height.java new file mode 100644 index 0000000..7eb720f --- /dev/null +++ b/src/main/java/model/Height.java @@ -0,0 +1,24 @@ +package model; + +import exception.ExceptionMessage; + +public class Height { + private static final int MIN_HEIGHT = 2; + + private final int value; + + public Height(int value) { + validateValue(value); + this.value = value; + } + + private void validateValue(int value) { + if (value < MIN_HEIGHT) { + throw new IllegalArgumentException(ExceptionMessage.LADDER_HEIGHT_MIN_VALUE.getMessage()); + } + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/model/Ladder.java b/src/main/java/model/Ladder.java index 76d767c..116f546 100644 --- a/src/main/java/model/Ladder.java +++ b/src/main/java/model/Ladder.java @@ -10,6 +10,18 @@ public Ladder(List lines) { this.lines = List.copyOf(lines); } + public static Ladder createLadder(int playerCount, int maxHeight, PointGenerator pointGenerator) { + List lines = Line.createLines(playerCount, maxHeight, pointGenerator); + return new Ladder(lines); + } + + public int move(int position) { + for (Line line : lines) { + position = line.move(position); + } + return position; + } + public List getPointsFromLines() { List result = new ArrayList<>(); for (Line line : lines) { @@ -17,4 +29,8 @@ public List getPointsFromLines() { } return List.copyOf(result); } + + public List getLines() { + return List.copyOf(lines); + } } diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java deleted file mode 100644 index a90daf6..0000000 --- a/src/main/java/model/LadderGame.java +++ /dev/null @@ -1,27 +0,0 @@ -package model; - -import java.util.ArrayList; -import java.util.List; - -public class LadderGame { - private final Ladder ladder; - private final PointGenerator generator; - - public LadderGame(Size width, Size height, PointGenerator generator) { - this.generator = generator; - this.ladder = new Ladder(generateLines(width, height)); - } - - private List generateLines(Size width, Size height) { - List lines = new ArrayList<>(); - for (int i = 0; i < height.getSize(); i++) { - List points = generator.createLinePoints(width); - lines.add(new Line(points)); - } - return List.copyOf(lines); - } - - public List getLadderPoints() { - return ladder.getPointsFromLines(); - } -} diff --git a/src/main/java/model/LadderResult.java b/src/main/java/model/LadderResult.java new file mode 100644 index 0000000..851f024 --- /dev/null +++ b/src/main/java/model/LadderResult.java @@ -0,0 +1,35 @@ +package model; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LadderResult { + private static final String NO_RESULT = "결과 없음"; + private final Map results; + private final Ladder ladder; + + public LadderResult(Ladder ladder) { + this.ladder = ladder; + this.results = new HashMap<>(); + } + + public void calculateResults(List playerNames, Prizes prizes) { + List prizeValues = prizes.getPrize(); + + for (String playerName : playerNames) { + int playerIndex = playerNames.indexOf(playerName); + playerIndex = ladder.move(playerIndex); + results.put(playerName, prizeValues.get(playerIndex)); + } + } + + public String getResultForPlayer(String name) { + return results.getOrDefault(name, NO_RESULT); + } + + public Map getValue() { + return Collections.unmodifiableMap(results); + } +} diff --git a/src/main/java/model/Line.java b/src/main/java/model/Line.java index 8606ca3..84179cd 100644 --- a/src/main/java/model/Line.java +++ b/src/main/java/model/Line.java @@ -1,6 +1,7 @@ package model; import java.util.List; +import java.util.stream.IntStream; public class Line { private final List points; @@ -9,6 +10,32 @@ public Line(List points) { this.points = List.copyOf(points); } + public static List createLines(int playerCount, int maxHeight, PointGenerator pointGenerator) { + return IntStream.range(0, maxHeight) + .mapToObj(i -> new Line(pointGenerator.createLinePoints(new Size(playerCount)))) + .toList(); + } + + public int move(int position) { + if(canMoveLeft(position)) { + return position -1; + } + + if(canMoveRight(position)) { + return position + 1; + } + return position; + } + + private boolean canMoveLeft(int position) { + return position > 0 && points.get(position - 1) == Point.HAS_POINT; + } + + private boolean canMoveRight(int position) { + return position < points.size() && points.get(position) == Point.HAS_POINT; + + } + public List getPointGroups() { return List.copyOf(points); } diff --git a/src/main/java/model/Player.java b/src/main/java/model/Player.java new file mode 100644 index 0000000..933515c --- /dev/null +++ b/src/main/java/model/Player.java @@ -0,0 +1,28 @@ +package model; + +import exception.ExceptionMessage; + +public class Player { + + private static final int MAX_NAME_LENGTH = 5; + private final String value; + + public Player(String value) { + validateValues(value); + this.value = value; + } + + public String getValue() { + return value; + } + + private void validateValues(String value) { + if (value == null || value.trim().isEmpty()) { + throw new IllegalArgumentException(ExceptionMessage.NULL_OR_EMPTY_INPUT.getMessage()); + } + + if (value.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException(ExceptionMessage.PLAYER_NAME_MAX_LENGTH_EXCEEDED.getMessage()); + } + } +} diff --git a/src/main/java/model/Players.java b/src/main/java/model/Players.java new file mode 100644 index 0000000..952dc12 --- /dev/null +++ b/src/main/java/model/Players.java @@ -0,0 +1,38 @@ +package model; + +import exception.ExceptionMessage; + +import java.util.List; + +public class Players { + + private static final int MIN_PLAYER_LENGTH = 2; + private final List players; + + public Players(List players) { + validatePlayers(players); + this.players = generatePlayers(players); + } + + public int size() { + return players.size(); + } + + public List getPlayers() { + return players.stream() + .map(Player::getValue) + .toList(); + } + + private List generatePlayers(List players) { + return players.stream() + .map(Player::new) + .toList(); + } + + private void validatePlayers(List players) { + if (players.size() < MIN_PLAYER_LENGTH) { + throw new IllegalArgumentException(ExceptionMessage.MIN_PLAYERS_REQUIRED.getMessage()); + } + } +} diff --git a/src/main/java/model/PointGenerator.java b/src/main/java/model/PointGenerator.java index 25f752e..09ba0a2 100644 --- a/src/main/java/model/PointGenerator.java +++ b/src/main/java/model/PointGenerator.java @@ -2,13 +2,12 @@ import java.util.ArrayList; import java.util.List; -import java.util.Random; public class PointGenerator { - private final Random random; + private final RandomUtil randomUtil; - public PointGenerator(Random random) { - this.random = random; + public PointGenerator(RandomUtil randomUtil) { + this.randomUtil = randomUtil; } public List createLinePoints(Size width) { @@ -28,7 +27,7 @@ private Point createPoint(boolean isPreviousLine) { if (isPreviousLine) { return Point.NO_POINT; } - int randomIndex = random.nextInt(points.size()); + int randomIndex = randomUtil.generateRandomNumber(); return points.get(randomIndex); } } diff --git a/src/main/java/model/Prize.java b/src/main/java/model/Prize.java new file mode 100644 index 0000000..1df2b14 --- /dev/null +++ b/src/main/java/model/Prize.java @@ -0,0 +1,23 @@ +package model; + +import exception.ExceptionMessage; + +public class Prize { + + private final String value; + + public Prize(String value) { + validateValue(value); + this.value = value; + } + + public String getValue() { + return value; + } + + private void validateValue(String value) { + if (value == null || value.trim().isEmpty()) { + throw new IllegalArgumentException(ExceptionMessage.RESULT_NOT_NULL_OR_EMPTY.getMessage()); + } + } +} diff --git a/src/main/java/model/Prizes.java b/src/main/java/model/Prizes.java new file mode 100644 index 0000000..7ae41cf --- /dev/null +++ b/src/main/java/model/Prizes.java @@ -0,0 +1,36 @@ +package model; + +import exception.ExceptionMessage; +import java.util.List; + +public class Prizes { + + private final List prize; + + public Prizes(List prize) { + this.prize = prize; + } + + public static Prizes createPrizes(List result, Players players) { + validatePrize(result, players); + return new Prizes(generatePrize(result)); + } + + public List getPrize() { + return prize.stream() + .map(Prize::getValue) + .toList(); + } + + private static List generatePrize(List result) { + return result.stream() + .map(Prize::new) + .toList(); + } + + private static void validatePrize(List prizes, Players players) { + if (prizes.size() != players.size()) { + throw new IllegalArgumentException(ExceptionMessage.RESULT_COUNT_MISMATCH.getMessage()); + } + } +} diff --git a/src/main/java/model/RandomUtil.java b/src/main/java/model/RandomUtil.java new file mode 100644 index 0000000..05e9f7a --- /dev/null +++ b/src/main/java/model/RandomUtil.java @@ -0,0 +1,5 @@ +package model; + +public interface RandomUtil { + int generateRandomNumber(); +} diff --git a/src/main/java/model/RandomValueGenerator.java b/src/main/java/model/RandomValueGenerator.java new file mode 100644 index 0000000..44f0139 --- /dev/null +++ b/src/main/java/model/RandomValueGenerator.java @@ -0,0 +1,13 @@ +package model; + +import java.util.Random; + +public class RandomValueGenerator implements RandomUtil { + private static final int RANDOM_BOUND = 2; + private static final Random random = new Random(); + + @Override + public int generateRandomNumber() { + return random.nextInt(RANDOM_BOUND); + } +} diff --git a/src/main/java/model/Size.java b/src/main/java/model/Size.java index 3ce0571..e2ae76d 100644 --- a/src/main/java/model/Size.java +++ b/src/main/java/model/Size.java @@ -1,5 +1,7 @@ package model; +import exception.ExceptionMessage; + public class Size { private final int size; @@ -14,7 +16,7 @@ public int getSize() { private void validateSize(int size) { if (size < 0) { - throw new IllegalArgumentException("사다리 사이즈가 0보다 작을 수는 없습니다."); + throw new IllegalArgumentException(ExceptionMessage.LADDER_SIZE_NEGATIVE.getMessage()); } } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000..f9a3fd7 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,56 @@ +package view; + +import exception.ExceptionMessage; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public List inputNames() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + String players = scanner.nextLine(); + return parseResults(players); + } + + public List inputResult() { + System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + String input = scanner.nextLine(); + return parseResults(input); + } + + public int getMaxLadderHeight() { + System.out.println("최대 사다리 높이는 몇 개인가요?"); + String input = scanner.nextLine(); + return parseLadderHeight(input); + } + + public String getTargetPlayerName() { + System.out.println("결과를 보고 싶은 사람은?"); + return scanner.nextLine(); + } + + private List parseResults(String input) { + throwIfNamesIsNullOrEmpty(input); + + return Arrays.stream(input.trim().split(",")) + .map(String::trim) + .toList(); + } + + private int parseLadderHeight(String input) { + try { + return Integer.parseInt(String.valueOf(input)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(ExceptionMessage.LADDER_HEIGHT_NOT_NUMBER.getMessage()); + } + } + + private void throwIfNamesIsNullOrEmpty(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException(ExceptionMessage.NULL_OR_EMPTY_INPUT.getMessage()); + } + } +} diff --git a/src/main/java/view/ResultView.java b/src/main/java/view/ResultView.java index d1d899a..87998f9 100644 --- a/src/main/java/view/ResultView.java +++ b/src/main/java/view/ResultView.java @@ -1,14 +1,17 @@ package view; import java.util.List; +import java.util.Map; public class ResultView { - public void printLadder(List> ladderRows) { + public void printLadder(List> ladderRows, List playerNames, List prize) { StringBuilder resultBuilder = new StringBuilder(); printResultHeader(); + System.out.println(String.join(" ", playerNames)); appendLadderRows(ladderRows, resultBuilder); System.out.println(resultBuilder); + System.out.println(String.join(" ", prize)); } private void appendLadderRows(List> ladderRows, StringBuilder resultBuilder) { @@ -18,7 +21,7 @@ private void appendLadderRows(List> ladderRows, StringBuilder resu } private void printResultHeader() { - System.out.println("실행결과"); + System.out.println("사다리결과"); System.out.println(); } @@ -28,6 +31,18 @@ private void appendRowToResult(StringBuilder resultBuilder, List ladder resultBuilder.append("\n"); } + public void printSingleResult(String prizes) { + System.out.println("실행결과"); + System.out.println(prizes); + } + + public void printAllResults(Map results) { + System.out.println("실행결과"); + results.forEach((player, result) -> + System.out.println(player + ":" + result) + ); + } + private void appendSymbolsForPoints(List ladderPoints, StringBuilder resultBuilder) { for (Boolean isExistPoint : ladderPoints) { if (isExistPoint) { diff --git a/src/test/java/model/HeightTest.java b/src/test/java/model/HeightTest.java new file mode 100644 index 0000000..5bd492f --- /dev/null +++ b/src/test/java/model/HeightTest.java @@ -0,0 +1,30 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +class HeightTest { + + @Test + @DisplayName("높이가 유효한 값일 때 정상적으로 생성된다.") + void shouldCreateHeightWithValidValue() { + Height height = new Height(5); + assertThat(height.getValue()).isEqualTo(5); + } + + @Test + @DisplayName("최소값일 때 높이가 정상적으로 생성된다") + void shouldCreateHeightWithMinimumValue() { + Height height = new Height(2); + assertThat(height.getValue()).isEqualTo(2); + } + + @Test + @DisplayName("높이가 2 미만일 때 예외가 발생한다.") + void shouldThrowExceptionForHeightBelowMin() { + assertThatThrownBy(() -> new Height(1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("사다리 높이는 최소 2 이상이어야 합니다."); + } +} diff --git a/src/test/java/model/LadderResultTest.java b/src/test/java/model/LadderResultTest.java new file mode 100644 index 0000000..54a2716 --- /dev/null +++ b/src/test/java/model/LadderResultTest.java @@ -0,0 +1,49 @@ +package model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; +import java.util.List; + +class LadderResultTest { + + private List player; + private List prize; + + @BeforeEach + void setUp() { + player = List.of("Gold", "nana", "Broze"); + prize = List.of("꽝", "3000", "5000"); + } + + private LadderResult createLadderResult(List player, List prize) { + Players players = new Players(player); + Prizes prizes = Prizes.createPrizes(prize, players); + + List lines = List.of( + new Line(List.of(Point.HAS_POINT, Point.NO_POINT)), + new Line(List.of(Point.NO_POINT, Point.HAS_POINT)) + ); + Ladder ladder = new Ladder(lines); + LadderResult ladderResult = new LadderResult(ladder); + ladderResult.calculateResults(player, prizes); + return ladderResult; + } + + @Test + @DisplayName("플레이어 이름에 대한 결과를 올바르게 계산한다.") + void shouldCalculateResultsCorrectly() { + LadderResult ladderResult = createLadderResult(player, prize); + + assertThat(ladderResult.getValue().values()).containsExactly("5000", "꽝", "3000"); + } + + @Test + @DisplayName("결과가 없는 플레이어에 대해 '결과 없음'을 반환한다.") + void shouldReturnNoResultWhenPlayerNotFound() { + LadderResult ladderResult = createLadderResult(player, prize); + + assertThat(ladderResult.getResultForPlayer("NonExistPlayer")).isEqualTo("결과 없음"); + } +} diff --git a/src/test/java/model/LadderTest.java b/src/test/java/model/LadderTest.java new file mode 100644 index 0000000..53e2396 --- /dev/null +++ b/src/test/java/model/LadderTest.java @@ -0,0 +1,43 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.*; + +class LadderTest { + + @Test + @DisplayName("레더의 라인이 정상적으로 반환된다.") + void shouldReturnLinesCorrectly() { + + List lines = Arrays.asList(new Line(Arrays.asList(Point.HAS_POINT, Point.NO_POINT)), + new Line(Arrays.asList(Point.NO_POINT, Point.HAS_POINT))); + + Ladder ladder = new Ladder(lines); + + List result = ladder.getLines(); + + assertThat(result).hasSize(2); + assertThat(result).isEqualTo(lines); + } + + @Test + @DisplayName("라인의 포인트 목록이 정상적으로 반환된다.") + void shouldReturnPointsFromLinesCorrectly() { + + Line line1 = new Line(Arrays.asList(Point.HAS_POINT, Point.NO_POINT)); + Line line2 = new Line(Arrays.asList(Point.NO_POINT, Point.HAS_POINT)); + List lines = Arrays.asList(line1, line2); + Ladder ladder = new Ladder(lines); + + List result = ladder.getPointsFromLines(); + + assertThat(result).hasSize(4); + assertThat(result.get(0)).isEqualTo(Point.HAS_POINT); + assertThat(result.get(1)).isEqualTo(Point.NO_POINT); + assertThat(result.get(2)).isEqualTo(Point.NO_POINT); + assertThat(result.get(3)).isEqualTo(Point.HAS_POINT); + } +} diff --git a/src/test/java/model/LineTest.java b/src/test/java/model/LineTest.java new file mode 100644 index 0000000..cfea1a2 --- /dev/null +++ b/src/test/java/model/LineTest.java @@ -0,0 +1,54 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; +import java.util.List; + +class LineTest { + + @Test + @DisplayName("라인이 유효한 포인트를 포함한다.") + void shouldContainPointsWhenValidProvided() { + List points = List.of(Point.HAS_POINT, Point.NO_POINT); + + Line line = new Line(points); + + assertThat(line.getPointGroups()).containsExactly(Point.HAS_POINT, Point.NO_POINT); + } + + @Test + @DisplayName("포인트들이 변경 불가능한 리스트로 반환한다.") + void shouldReturnUnmodifiableList() { + List points = List.of(Point.HAS_POINT, Point.NO_POINT); + + Line line = new Line(points); + + assertThatThrownBy(() -> line.getPointGroups().clear()) + .isInstanceOf(UnsupportedOperationException.class); + } + + @Test + @DisplayName("포인트들이 주어졌을 때 순서를 유지한다.") + void shouldContainPointsInOrder() { + List points = List.of(Point.HAS_POINT, Point.NO_POINT); + + Line line = new Line(points); + + assertThat(line.getPointGroups()) + .element(0).isEqualTo(Point.HAS_POINT); + + assertThat(line.getPointGroups()) + .element(1).isEqualTo(Point.NO_POINT); + } + + @Test + @DisplayName("하나의 포인트가 주어졌을 때 라인이 올바르게 처리한다.") + void shouldHandleSinglePoint() { + List points = List.of(Point.HAS_POINT); + + Line line = new Line(points); + + assertThat(line.getPointGroups()).containsExactly(Point.HAS_POINT); + } +} diff --git a/src/test/java/model/PlayerTest.java b/src/test/java/model/PlayerTest.java new file mode 100644 index 0000000..f4f01da --- /dev/null +++ b/src/test/java/model/PlayerTest.java @@ -0,0 +1,50 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import static org.assertj.core.api.Assertions.*; + +class PlayerTest { + + @Test + @DisplayName("유효한 이름으로 플레이어가 정상적으로 생성된다.") + void shouldCreatePlayerCorrectlyWhenNameIsValid() { + String validName = "Alice"; + + Player player = new Player(validName); + + assertThat(player.getValue()).isEqualTo(validName); + } + + @Test + @DisplayName("플레이어 이름이 최대 길이를 초과하면 예외가 발생한다.") + void shouldThrowExceptionWhenNameMaxLength() { + String invalidName = "LongName"; + + assertThatThrownBy(() -> new Player(invalidName)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("참가자 이름은 최대 5글자를 초과할 수 없습니다."); + } + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("플레이어 이름이 null이면 예외가 발생한다.") + void shouldThrowExceptionWhenNameIsNullOrEmpty(String invalidName) { + assertThatThrownBy(() -> new Player(invalidName)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("입력값이 null이거나 비어있을 순 없습니다."); + } + + + @ParameterizedTest + @ValueSource(strings = {" ", " "}) + @DisplayName("플레이어 이름이 공백 문자일 경우 예외가 발생한다.") + void shouldThrowExceptionWhenNameIsBlank(String invalidName) { + assertThatThrownBy(() -> new Player(invalidName)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("입력값이 null이거나 비어있을 순 없습니다."); + } +} diff --git a/src/test/java/model/PlayersTest.java b/src/test/java/model/PlayersTest.java new file mode 100644 index 0000000..f582a8a --- /dev/null +++ b/src/test/java/model/PlayersTest.java @@ -0,0 +1,39 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.*; + +class PlayersTest { + + @Test + @DisplayName("유효한 플레이어 리스트로 객체가 정상적으로 생성된다.") + void shouldNotThrowExceptionWhenValidPlayers() { + List validPlayerNames = List.of("Alice", "Bob"); + + Players players = new Players(validPlayerNames); + + assertThat(players.size()).isEqualTo(2); + } + + @Test + @DisplayName("플레이어 수가 부족하면 예외가 발생한다.") + void shouldThrowExceptionWhenNotEnoughPlayers() { + List invalidPlayerNames = List.of("Alice"); + + assertThatThrownBy(() -> new Players(invalidPlayerNames)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("참가자는 최소 2명 이상이여야 합니다."); + } + + @Test + @DisplayName("플레이어 수가 충분하면 객체가 정상적으로 생성된다.") + void shouldContainValidPlayersWhenGenerated() { + List validPlayerNames = List.of("Alice", "Bob"); + + Players players = new Players(validPlayerNames); + + assertThat(players.getPlayers()).containsExactly("Alice", "Bob"); + } +} diff --git a/src/test/java/model/PointGeneratorTest.java b/src/test/java/model/PointGeneratorTest.java new file mode 100644 index 0000000..efed8a5 --- /dev/null +++ b/src/test/java/model/PointGeneratorTest.java @@ -0,0 +1,57 @@ +package model; + +import model.util.FixedNumberGenerator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + +class PointGeneratorTest { + + private PointGenerator pointGenerator; + private Players players; + + @BeforeEach + void setUp() { + players = new Players(Arrays.asList("neo", "brown", "brie", "tommy")); + } + + private void createPointGeneratorWithFixedNumber(int number) { + pointGenerator = new PointGenerator(new FixedNumberGenerator(number)); + } + + @Test + @DisplayName("포인트 리스트 크기가 3으로 생성된다.") + void shouldHaveSizeThree() { + createPointGeneratorWithFixedNumber(0); + Size size = new Size(players.size()); + + List points = pointGenerator.createLinePoints(size); + + assertThat(points).hasSize(3); + } + + @Test + @DisplayName("고정된 숫자 생성기 값이 0일 때, 모든 포인트가 NO_POINT로 생성된다.") + void shouldCreateLinePointsAllNoPoint() { + createPointGeneratorWithFixedNumber(0); + Size size = new Size(players.size()); + + List points = pointGenerator.createLinePoints(size); + + assertThat(points).allMatch(point -> point == Point.NO_POINT); + } + + @Test + @DisplayName("고정된 숫자 생성기 값이 1일 때, HAS_POINT가 포함된 포인트가 생성된다.") + void shouldCreateLinePointsWithHasPoint() { + createPointGeneratorWithFixedNumber(1); + Size size = new Size(players.size()); + + List linePoints = pointGenerator.createLinePoints(size); + + assertThat(linePoints).contains(Point.HAS_POINT); + } +} diff --git a/src/test/java/model/PrizeTest.java b/src/test/java/model/PrizeTest.java new file mode 100644 index 0000000..1e3f94e --- /dev/null +++ b/src/test/java/model/PrizeTest.java @@ -0,0 +1,40 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import static org.assertj.core.api.Assertions.*; + +public class PrizeTest { + + @Test + @DisplayName("유효한 값이면 Prize 객체가 생성된다.") + public void shouldCreatePrizeWithValidValue() { + String validValue = "Gold"; + + Prize prize = new Prize(validValue); + + assertThat(prize.getValue()).isEqualTo(validValue); + } + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("값이 null이면 예외가 발생한다.") + public void shouldThrowExceptionWhenValueIsNull(String invalidValue) { + + assertThatThrownBy(() -> new Prize(invalidValue)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행결과는 null이거나 공백일 수는 없습니다."); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " "}) + @DisplayName("값이 빈 문자열, 공백일 경우 예외가 발생한다.") + public void shouldThrowExceptionWhenValueIsEmpty(String invalidValue) { + assertThatThrownBy(() -> new Prize(invalidValue)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행결과는 null이거나 공백일 수는 없습니다."); + } +} diff --git a/src/test/java/model/PrizesTest.java b/src/test/java/model/PrizesTest.java new file mode 100644 index 0000000..0c4d3c2 --- /dev/null +++ b/src/test/java/model/PrizesTest.java @@ -0,0 +1,45 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; +import java.util.List; + +public class PrizesTest { + + @Test + @DisplayName("유효한 값이면 사다라의 실행결과 객체가 생성된다.") + public void shouldCreatePrizesWithValidValues() { + List player = List.of("Gold", "nana", "Broze"); + List prize = List.of("꽝", "3000", "5000"); + Players players = new Players(player); + + Prizes prizes = Prizes.createPrizes(prize, players); + + assertThat(prizes.getPrize()).containsExactly("꽝", "3000", "5000"); + } + + @Test + @DisplayName("실행결과 개수와 참가자의 수가 다르면 예외를 발생한다.") + public void shouldThrowExceptionWhenPrizeSizeDoesNotMatchPlayersSize() { + List player = List.of("Gold", "nana"); + List prize = List.of("꽝", "3000", "5000"); + Players players = new Players(player); + + assertThatThrownBy(() -> Prizes.createPrizes(prize, players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행결과 개수와 참가자의 수는 동일해야 합니다."); + } + + @Test + @DisplayName("결과가 비어있으면 예외를 발생한다.") + public void shouldCreateEmptyPrizesWhenEmptyResults() { + List player = List.of("Gold", "nana"); + List prize = List.of(); + Players players = new Players(player); + + assertThatThrownBy(() -> Prizes.createPrizes(prize, players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행결과 개수와 참가자의 수는 동일해야 합니다."); + } +} diff --git a/src/test/java/model/RandomValueGeneratorTest.java b/src/test/java/model/RandomValueGeneratorTest.java new file mode 100644 index 0000000..7aafc65 --- /dev/null +++ b/src/test/java/model/RandomValueGeneratorTest.java @@ -0,0 +1,19 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +class RandomValueGeneratorTest { + private static final int MIN_RANDOM_VALUE = 0; + private static final int MAX_RANDOM_VALUE = 2; + private final RandomValueGenerator generator = new RandomValueGenerator(); + + @Test + @DisplayName("랜덤값이 지정된 범위 안에 생성된다.") + void testRandomValueGenerator() { + int randomNumber = generator.generateRandomNumber(); + + assertThat(randomNumber).isBetween(MIN_RANDOM_VALUE, MAX_RANDOM_VALUE); + } +} diff --git a/src/test/java/model/SizeTest.java b/src/test/java/model/SizeTest.java new file mode 100644 index 0000000..33a0765 --- /dev/null +++ b/src/test/java/model/SizeTest.java @@ -0,0 +1,26 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +public class SizeTest { + + @Test + @DisplayName("사다리 크기가 유효한 값이면 정상적으로 객체를 생성한다.") + public void shouldCreateSizeWithValidValue() { + int validSize = 5; + Size size = new Size(validSize); + assertThat(size.getSize()).isEqualTo(validSize); + } + + @Test + @DisplayName("사다리 크기가 유효하지 않는 값이면 예외가 발생한다.") + public void shouldThrowExceptionWhenSizeIsNegative() { + int invalidSize = -1; + + assertThatThrownBy(() -> new Size(invalidSize)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("사다리 사이즈가 0보다 작을 수는 없습니다."); + } +} diff --git a/src/test/java/model/util/FixedNumberGenerator.java b/src/test/java/model/util/FixedNumberGenerator.java new file mode 100644 index 0000000..b46a636 --- /dev/null +++ b/src/test/java/model/util/FixedNumberGenerator.java @@ -0,0 +1,16 @@ +package model.util; + +import model.RandomUtil; + +public class FixedNumberGenerator implements RandomUtil { + private final int fixedNumber; + + public FixedNumberGenerator(int fixedNumber) { + this.fixedNumber = fixedNumber; + } + + @Override + public int generateRandomNumber() { + return fixedNumber; + } +}