diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..1afd7749b3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,77 @@ +## 기능 목록 +- [x] 자동차 이름 요청 메시지 출력 +- [x] 자동차 이름 입력 받기 + - [x] 쉼표로 구분 됐는지 입력값 검증 + - [x] 잘못된 입력의 경우 에러 문구 출력 및 재시도 + - [x] 이름의 길이가 5자 이하인지 검증 + - [x] 5자 초과의 경우 에러 문구 출력 및 재시도 + - [x] 중복되는 이름이 있는지 검증 + - [x] 중복시 에러 문구 출력 및 재시도 +- [x] 시도 회수 요청 메시지 출력 +- [x] 시도 회수 입력 받기 + - [x] 입력값 숫자인지 검증 +- [x] 자동차 이동 + - [x] 차수별 이동 + - [x] 차수별 현황 출력 +- [x] 최종 우승자 선정 + - [x] 최종 우승자 안내 문구 출력 + - [x] 공동 우승자의 경우 ", " 로 구분하여 출력 + +## 구현 클래스 목록 +- CarController + - play() + +- InputView + - readCars() + - readTryCount() + +- InputManager + - readCars() + - readTryCount() + +- InputValidator + - validateCars() + - validateTryCount() + +- Car + - move() + - getPosition() + - getName() + - hasMaxPosition() + - getCurrentStatus() + +- Cars + - getNumberOfCars() + - moveAll() + - findWinners() + - getCurrentDirection() + +- OutputView + - printCarRequest() + - printTryCountRequest() + - printCurrentDirection() + - printWinnerCars() + +- CarService + - saveCars() + - saveTryCount() + - findTryCount() + - move() + - findWinnerCars() + +- CarRepository + - saveCars() + - saveTryCount() + - findCars() + - findTryCount() + +- TryCount + - hasNext() + +- RandomMoveGenerator + - generate + +## 열거형 목록 +- ErrorMessage +- GameMessage +- MoveStatus diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index b9ed0456a3..e65cdf9d99 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,9 @@ package racingcar; +import racingcar.controller.CarController; + public class Application { public static void main(String[] args) { - // TODO 구현 진행 + new CarController().play(); } } diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java deleted file mode 100644 index ab3df94921..0000000000 --- a/src/main/java/racingcar/Car.java +++ /dev/null @@ -1,12 +0,0 @@ -package racingcar; - -public class Car { - private final String name; - private int position = 0; - - public Car(String name) { - this.name = name; - } - - // 추가 기능 구현 -} diff --git a/src/main/java/racingcar/constant/ErrorMessage.java b/src/main/java/racingcar/constant/ErrorMessage.java new file mode 100644 index 0000000000..da32e69bc3 --- /dev/null +++ b/src/main/java/racingcar/constant/ErrorMessage.java @@ -0,0 +1,21 @@ +package racingcar.constant; + +public enum ErrorMessage { + INVALID_CAR_INPUT("자동차 이름을 입력할 시 쉼표로 구분해야 합니다."), + INVALID_CARS_NUM("자동차 이름에 중복이 있습니다."), + INVALID_CAR_NAME_LENGTH("자동차 이름의 길이가 잘못됐습니다."), + INVALID_TRY_COUNT_INPUT("시도 회수의 입력값은 숫자만 가능합니다."), + HAS_NO_MOVE_STATUS("다음 MoveStatus가 존재하지 않습니다."), + INVALID_MOVE_STATUS_SIZE("MoveStatus의 개수가 잘못되었습니다."); + + private static final String ERROR_PREFIX = "[ERROR] "; + private final String message; + + ErrorMessage(final String message) { + this.message = message; + } + + public String getMessage() { + return ERROR_PREFIX + this.message; + } +} diff --git a/src/main/java/racingcar/constant/GameMessage.java b/src/main/java/racingcar/constant/GameMessage.java new file mode 100644 index 0000000000..bb827c92aa --- /dev/null +++ b/src/main/java/racingcar/constant/GameMessage.java @@ -0,0 +1,17 @@ +package racingcar.constant; + +public enum GameMessage { + CAR_INPUT_REQUEST("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"), + TRY_COUNT_REQUEST("시도할 회수는 몇회인가요?"), + WINNER_CARS("최종 우승자 : %s"); + + private final String message; + + GameMessage(final String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } +} diff --git a/src/main/java/racingcar/constant/MoveStatus.java b/src/main/java/racingcar/constant/MoveStatus.java new file mode 100644 index 0000000000..add5db0df6 --- /dev/null +++ b/src/main/java/racingcar/constant/MoveStatus.java @@ -0,0 +1,18 @@ +package racingcar.constant; + +public enum MoveStatus { + MOVE, STOP; + + private static final Integer moveDivider = 4; + + public static MoveStatus getMoveStatus(final int randomNumber) { + if (moveDivider <= randomNumber) { + return MOVE; + } + return STOP; + } + + public boolean isMove() { + return this == MOVE; + } +} diff --git a/src/main/java/racingcar/controller/CarController.java b/src/main/java/racingcar/controller/CarController.java new file mode 100644 index 0000000000..fdf7e5d494 --- /dev/null +++ b/src/main/java/racingcar/controller/CarController.java @@ -0,0 +1,47 @@ +package racingcar.controller; + +import racingcar.domain.Cars; +import racingcar.domain.TryCount; +import racingcar.io.InputManager; +import racingcar.io.OutputView; +import racingcar.service.CarService; + +public class CarController { + + private final InputManager inputManager = new InputManager(); + private final OutputView outputView = new OutputView(); + private final CarService carService = new CarService(); + + public void play() { + createCars(); + createTryCount(); + moveCars(); + findWinnerCars(); + } + + private void moveCars() { + final TryCount tryCount = carService.findTryCount(); + + while(tryCount.hasNext()) { + final String currentDirection = carService.move(); + outputView.printCurrentDirection(currentDirection); + } + } + + private void findWinnerCars() { + final String winnerCars = carService.findWinnerCars(); + outputView.printWinnerCars(winnerCars); + } + + private void createTryCount() { + outputView.printTryCountRequest(); + final TryCount tryCount = inputManager.readTryCount(); + carService.saveTryCount(tryCount); + } + + private void createCars() { + outputView.printCarRequest(); + final Cars cars = inputManager.readCars(); + carService.saveCars(cars); + } +} diff --git a/src/main/java/racingcar/domain/Car.java b/src/main/java/racingcar/domain/Car.java new file mode 100644 index 0000000000..8cd17d0422 --- /dev/null +++ b/src/main/java/racingcar/domain/Car.java @@ -0,0 +1,66 @@ +package racingcar.domain; + +import racingcar.constant.ErrorMessage; +import racingcar.constant.MoveStatus; + +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class Car { + + private static final Integer MAX_SIZE = 5; + private static final Integer START_INDEX = 0; + private static final String DIRECTION_TAG = "-"; + private static final String NAME_DELIMITER = " : "; + private final String name; + private int position = 0; + + public Car(final String name) { + validateName(name); + this.name = name; + } + + private void validateName(final String name) { + if (name.length() > MAX_SIZE) { + throw new IllegalArgumentException(ErrorMessage.INVALID_CAR_NAME_LENGTH.getMessage()); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Car car = (Car) o; + return position == car.position && Objects.equals(name, car.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, position); + } + + public void move(final MoveStatus moveStatus) { + if (moveStatus.isMove()) { + this.position++; + } + } + + public Integer getPosition() { + return this.position; + } + + public String getName() { + return this.name; + } + + public boolean hasMaxPosition(final int maxPosition) { + return this.position == maxPosition; + } + + public String getCurrentStatus() { + return this.name + NAME_DELIMITER + IntStream.range(START_INDEX, position) + .mapToObj(i -> DIRECTION_TAG) + .collect(Collectors.joining()); + } +} diff --git a/src/main/java/racingcar/domain/Cars.java b/src/main/java/racingcar/domain/Cars.java new file mode 100644 index 0000000000..836b4403ca --- /dev/null +++ b/src/main/java/racingcar/domain/Cars.java @@ -0,0 +1,68 @@ +package racingcar.domain; + +import racingcar.constant.ErrorMessage; +import racingcar.constant.MoveStatus; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +public class Cars { + + private static final Integer MIN_POSITION = 0; + private static final String WINNER_DELIMITER = ", "; + private static final String NEW_LINE_DELIMITER = "\n"; + private final List cars; + + public Cars(final List cars) { + validateUnique(cars); + this.cars = Collections.unmodifiableList(cars); + } + + private void validateUnique(final List cars) { + if (new HashSet<>(cars).size() != cars.size()) { + throw new IllegalArgumentException(ErrorMessage.INVALID_CARS_NUM.getMessage()); + } + } + + public Integer getNumberOfCars() { + return cars.size(); + } + + public void moveAll(final MoveStatuses moveStatuses) { + validateMoveStatusSize(moveStatuses); + cars.forEach(car -> move(car, moveStatuses.getNext())); + } + + private void validateMoveStatusSize(final MoveStatuses moveStatuses) { + if (cars.size() != moveStatuses.getSize()) { + throw new IllegalArgumentException(ErrorMessage.INVALID_MOVE_STATUS_SIZE.getMessage()); + } + } + + private void move(final Car car, final MoveStatus moveStatus) { + car.move(moveStatus); + } + + public String findWinners() { + final int maxPosition = getMaxPosition(); + return cars.stream() + .filter(car -> car.hasMaxPosition(maxPosition)) + .map(Car::getName) + .collect(Collectors.joining(WINNER_DELIMITER)); + } + + private int getMaxPosition() { + return cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(MIN_POSITION); + } + + public String getCurrentDirection() { + return cars.stream() + .map(Car::getCurrentStatus) + .collect(Collectors.joining(NEW_LINE_DELIMITER)) + NEW_LINE_DELIMITER; + } +} diff --git a/src/main/java/racingcar/domain/MoveStatuses.java b/src/main/java/racingcar/domain/MoveStatuses.java new file mode 100644 index 0000000000..f5f513fd91 --- /dev/null +++ b/src/main/java/racingcar/domain/MoveStatuses.java @@ -0,0 +1,31 @@ +package racingcar.domain; + +import racingcar.constant.ErrorMessage; +import racingcar.constant.MoveStatus; + +import java.util.ArrayList; +import java.util.List; + +public class MoveStatuses { + private static final int REMOVE_INDEX = 0; + private final List moveStatuses; + + public MoveStatuses(final List moveStatuses) { + this.moveStatuses = new ArrayList<>(moveStatuses); + } + + public MoveStatus getNext() { + validateHasNext(); + return moveStatuses.remove(REMOVE_INDEX); + } + + public int getSize() { + return this.moveStatuses.size(); + } + + private void validateHasNext() { + if (moveStatuses.isEmpty()) { + throw new IllegalStateException(ErrorMessage.HAS_NO_MOVE_STATUS.getMessage()); + } + } +} diff --git a/src/main/java/racingcar/domain/TryCount.java b/src/main/java/racingcar/domain/TryCount.java new file mode 100644 index 0000000000..a64fdf0fb1 --- /dev/null +++ b/src/main/java/racingcar/domain/TryCount.java @@ -0,0 +1,14 @@ +package racingcar.domain; + +public class TryCount { + + private Integer tryCount; + + public TryCount(final Integer tryCount) { + this.tryCount = tryCount; + } + + public boolean hasNext() { + return this.tryCount-- > 0; + } +} diff --git a/src/main/java/racingcar/io/InputManager.java b/src/main/java/racingcar/io/InputManager.java new file mode 100644 index 0000000000..a5e90edac5 --- /dev/null +++ b/src/main/java/racingcar/io/InputManager.java @@ -0,0 +1,37 @@ +package racingcar.io; + +import racingcar.domain.Car; +import racingcar.domain.Cars; +import racingcar.domain.TryCount; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class InputManager { + + private static final String CAR_DELIMITER = ","; + private final InputView inputView = new InputView(); + + public Cars readCars() { + return read(() -> { + final List cars = Arrays.stream(inputView.readCars().split(CAR_DELIMITER)).map(Car::new).collect(Collectors.toList()); + return new Cars(cars); + }); + } + + public TryCount readTryCount() { + return read(() -> new TryCount(Integer.parseInt(inputView.readTryCount()))); + } + + private T read(final Supplier supplier) { + while (true) { + try { + return supplier.get(); + } catch (final IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } +} diff --git a/src/main/java/racingcar/io/InputValidator.java b/src/main/java/racingcar/io/InputValidator.java new file mode 100644 index 0000000000..f7067c2f7b --- /dev/null +++ b/src/main/java/racingcar/io/InputValidator.java @@ -0,0 +1,22 @@ +package racingcar.io; + +import racingcar.constant.ErrorMessage; + +public class InputValidator { + + private static final String CAR_DELIMITER = ","; + private static final Character MIN_NUMBER = '0'; + private static final Character MAX_NUMBER = '9'; + + public void validateCars(final String input) { + if (input.startsWith(CAR_DELIMITER) || input.endsWith(CAR_DELIMITER)) { + throw new IllegalArgumentException(ErrorMessage.INVALID_CAR_INPUT.getMessage()); + } + } + + public void validateTryCount(final String input) { + if (input.chars().anyMatch(c -> MIN_NUMBER > c || c > MAX_NUMBER)) { + throw new IllegalArgumentException(ErrorMessage.INVALID_TRY_COUNT_INPUT.getMessage()); + } + } +} diff --git a/src/main/java/racingcar/io/InputView.java b/src/main/java/racingcar/io/InputView.java new file mode 100644 index 0000000000..2cd99e6b05 --- /dev/null +++ b/src/main/java/racingcar/io/InputView.java @@ -0,0 +1,23 @@ +package racingcar.io; + +import camp.nextstep.edu.missionutils.Console; + +import java.util.List; + +public class InputView { + + private final InputValidator inputValidator = new InputValidator(); + + + public String readCars() { + final String input = Console.readLine(); + inputValidator.validateCars(input); + return input; + } + + public String readTryCount() { + final String input = Console.readLine(); + inputValidator.validateTryCount(input); + return input; + } +} diff --git a/src/main/java/racingcar/io/OutputView.java b/src/main/java/racingcar/io/OutputView.java new file mode 100644 index 0000000000..6c5b1240e9 --- /dev/null +++ b/src/main/java/racingcar/io/OutputView.java @@ -0,0 +1,22 @@ +package racingcar.io; + +import racingcar.constant.GameMessage; +import racingcar.domain.Cars; + +public class OutputView { + public void printCarRequest() { + System.out.println(GameMessage.CAR_INPUT_REQUEST.getMessage()); + } + + public void printTryCountRequest() { + System.out.println(GameMessage.TRY_COUNT_REQUEST.getMessage()); + } + + public void printCurrentDirection(final String currentDirection) { + System.out.println(currentDirection); + } + + public void printWinnerCars(final String winnerCars) { + System.out.println(String.format(GameMessage.WINNER_CARS.getMessage(), winnerCars)); + } +} diff --git a/src/main/java/racingcar/repository/CarRepository.java b/src/main/java/racingcar/repository/CarRepository.java new file mode 100644 index 0000000000..6497a37d5d --- /dev/null +++ b/src/main/java/racingcar/repository/CarRepository.java @@ -0,0 +1,26 @@ +package racingcar.repository; + +import racingcar.domain.Cars; +import racingcar.domain.TryCount; + +public class CarRepository { + + private Cars cars; + private TryCount tryCount; + + public void saveCars(final Cars cars) { + this.cars = cars; + } + + public void saveTryCount(final TryCount tryCount) { + this.tryCount = tryCount; + } + + public TryCount findTryCount() { + return this.tryCount; + } + + public Cars findCars() { + return this.cars; + } +} diff --git a/src/main/java/racingcar/service/CarService.java b/src/main/java/racingcar/service/CarService.java new file mode 100644 index 0000000000..c803a08ae9 --- /dev/null +++ b/src/main/java/racingcar/service/CarService.java @@ -0,0 +1,40 @@ +package racingcar.service; + +import racingcar.domain.Cars; +import racingcar.domain.MoveStatuses; +import racingcar.domain.TryCount; +import racingcar.repository.CarRepository; +import racingcar.utils.RandomMoveGenerator; + +public class CarService { + + private final CarRepository carRepository = new CarRepository(); + private final RandomMoveGenerator randomMoveGenerator = new RandomMoveGenerator(); + + public void saveCars(final Cars cars) { + carRepository.saveCars(cars); + } + + public void saveTryCount(final TryCount tryCount) { + carRepository.saveTryCount(tryCount); + } + + public TryCount findTryCount() { + return carRepository.findTryCount(); + } + + public String move() { + final Cars cars = carRepository.findCars(); + final MoveStatuses moveStatuses = randomMoveCars(cars.getNumberOfCars()); + cars.moveAll(moveStatuses); + return cars.getCurrentDirection(); + } + + private MoveStatuses randomMoveCars(final Integer numberOfCars) { + return randomMoveGenerator.generate(numberOfCars); + } + + public String findWinnerCars() { + return carRepository.findCars().findWinners(); + } +} diff --git a/src/main/java/racingcar/utils/RandomMoveGenerator.java b/src/main/java/racingcar/utils/RandomMoveGenerator.java new file mode 100644 index 0000000000..eae5c026ac --- /dev/null +++ b/src/main/java/racingcar/utils/RandomMoveGenerator.java @@ -0,0 +1,26 @@ +package racingcar.utils; + +import camp.nextstep.edu.missionutils.Randoms; +import racingcar.constant.MoveStatus; +import racingcar.domain.MoveStatuses; + +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class RandomMoveGenerator { + + private static final int START_INDEX = 0; + private static final int MIN_RANGE = 0; + private static final int MAX_RANGE = 9; + + public MoveStatuses generate(final Integer numberOfCars) { + return new MoveStatuses(IntStream.range(START_INDEX, numberOfCars) + .mapToObj(i -> generate()) + .collect(Collectors.toList())); + } + + private MoveStatus generate() { + final int randomNumber = Randoms.pickNumberInRange(MIN_RANGE, MAX_RANGE); + return MoveStatus.getMoveStatus(randomNumber); + } +} diff --git a/src/test/java/racingcar/domain/CarTest.java b/src/test/java/racingcar/domain/CarTest.java new file mode 100644 index 0000000000..6bb8765e2d --- /dev/null +++ b/src/test/java/racingcar/domain/CarTest.java @@ -0,0 +1,34 @@ +package racingcar.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import racingcar.constant.MoveStatus; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Car 도메인에서") +class CarTest { + + @Test + @DisplayName("이름의 길이가 5를 초과하는 경우 예외를 던진다.") + void create() { + Assertions.assertThatThrownBy(() -> new Car("asdfasdf")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("MoveStatus의 상태에 따라 움직인다.") + void move() { + //given + final Car car = new Car("aaa"); + final Integer olderPosition = car.getPosition(); + + //when + car.move(MoveStatus.STOP); + car.move(MoveStatus.MOVE); + + //then + Assertions.assertThat(car.getPosition()).isNotEqualTo(olderPosition); + } +} diff --git a/src/test/java/racingcar/domain/CarsTest.java b/src/test/java/racingcar/domain/CarsTest.java new file mode 100644 index 0000000000..8458c6e399 --- /dev/null +++ b/src/test/java/racingcar/domain/CarsTest.java @@ -0,0 +1,44 @@ +package racingcar.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import racingcar.constant.MoveStatus; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Car를 가지는 일급 컬렉션에서") +class CarsTest { + + @Test + @DisplayName("생성시 같은 name의 car가 존재하면 예외를 던진다.") + void create() { + Assertions.assertThatThrownBy(() -> new Cars(Arrays.asList(new Car("a"), new Car("a")))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("Car와 MoveStatus의 개수가 상이할 시 예외를 던진다.") + void moveAll() { + final Cars cars = new Cars(Arrays.asList(new Car("a"), new Car("b"))); + Assertions.assertThatThrownBy(() -> cars.moveAll(new MoveStatuses(Arrays.asList(MoveStatus.MOVE, MoveStatus.STOP, MoveStatus.MOVE)))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("우승차 조회가 수행되는가") + void findWinners() { + //given + final String winner = "a"; + final Cars cars = new Cars(Arrays.asList(new Car(winner), new Car("b"))); + cars.moveAll(new MoveStatuses(Arrays.asList(MoveStatus.MOVE, MoveStatus.STOP))); + + //when + final String winnerString = cars.findWinners(); + + //then + Assertions.assertThat(winnerString).isEqualTo(winner); + } +} diff --git a/src/test/java/racingcar/domain/MoveStatusesTest.java b/src/test/java/racingcar/domain/MoveStatusesTest.java new file mode 100644 index 0000000000..a49ecf9ceb --- /dev/null +++ b/src/test/java/racingcar/domain/MoveStatusesTest.java @@ -0,0 +1,25 @@ +package racingcar.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import racingcar.constant.MoveStatus; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("MoveStatus 리스트 를 가지는 일급컬렉션에서") +class MoveStatusesTest { + + @Test + @DisplayName("남은 MoveStatus가 없을 때 예외를 던진다.") + void getNext() { + final MoveStatuses moveStatuses = new MoveStatuses(Arrays.asList()); + + Assertions.assertThatThrownBy(moveStatuses::getNext) + .isInstanceOf(IllegalStateException.class); + } +} diff --git a/src/test/java/racingcar/io/InputValidatorTest.java b/src/test/java/racingcar/io/InputValidatorTest.java new file mode 100644 index 0000000000..1be0fac96a --- /dev/null +++ b/src/test/java/racingcar/io/InputValidatorTest.java @@ -0,0 +1,34 @@ +package racingcar.io; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("입력값 검증에서") +class InputValidatorTest { + + private final InputValidator inputValidator = new InputValidator(); + + @Test + @DisplayName("쉼표로 시작하는 입력값에 대해 예외를 던진다.") + void validateCarsWithStartsWithComma() { + Assertions.assertThatThrownBy(() -> inputValidator.validateCars(",pobi")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("쉼표로 끝나는 입력값에 대해 예외를 던진다.") + void validateCarsWithEndsWithComma() { + Assertions.assertThatThrownBy(() -> inputValidator.validateCars("pobi,abc,")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("숫자가 아닌 값에 대해 예외를 던진다.") + void validateTryCount() { + Assertions.assertThatThrownBy(() -> inputValidator.validateTryCount("a")) + .isInstanceOf(IllegalArgumentException.class); + } +}