From 902d49ef6c8059d9d43eb77a5e93a841b2468507 Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 22:52:58 +0900 Subject: [PATCH 1/7] =?UTF-8?q?docs(README.md):=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EB=B6=84=EC=84=9D=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 --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index e078fd41f..34e21868c 100644 --- a/README.md +++ b/README.md @@ -1 +1,34 @@ # javascript-racingcar-precourse + +자동차 경주 게임 구현 + +## 기능 목록 + +### 유저 입력 처리 + +- [ ] 사용자는 경주할 자동차에 각각 이름(name)을 부여할 수 있다. +- [ ] 자동차 이름 입력시 n대의 자동차 이름을 입력하며, 이를 통해 경주에 참여하는 자동차 수를 정한다. +- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [ ] 사용자에게 몇 번의 이동을 할 것인지 라운드 횟수(total round)를 입력할 수 있다. + +### 자동차 경주 실행 및 실행 결과 출력 + +- [ ] 사용자가 입력한 이동 횟수(total round) 만큼 자동차 경주 함수를 실행한다. +- [ ] 각 차수(round)마다 n대의 자동차는 각각 전진 또는 정지(전진하지 않음) 할 수 있다. +- [ ] 자동차는 매번 0에서 9 사이의 무작위 값을 구한 후, 무작위 값이 4 이상일 경우 전진하고 4 미만일 경우 정지한다. +- [ ] 실행 결과를 출력한다. (자동차마다의 출력 문구: `${자동차 이름(name)} : ${자동차 위치(position)}`) +- [ ] 자동차의 위치(position)는 '-'로 표시한다. ('-'는 1회 전진, '--'는 2회 전진) + +### 우승자 계산 및 출력 + +- [ ] 주어진 횟수 동안 가장 많이 전진한 자동차를 우승자(winner)로 출력한다. (출력 문구: `최종 우승자 : ${우승자(winner)}`) +- [ ] 우승자는 한 명 이상일 수 있다. +- [ ] 우승자가 여러 명일 경우 쉼표를 이용하여 구분한다. + +### 에러 처리 + +- [ ] 사용자가 잘못된 값을 입력한 경우 "[ERROR]"로 시작하는 메시지와 함께 `Error`를 발생시킨 후 애플리케이션이 종료된다. +- [ ] 자동차 이름이 5자를 초과할 경우 +- [ ] 경주할 자동차 이름을 1개 이하로 지정한 경우 +- [ ] 시도할 횟수에 양의 정수 값이 아닌 값을 입력한 경우 +- [ ] 값을 입력하지 않은 경우 From c8a682264128ad160344bb19c6b1ddb009473faf Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 22:57:29 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat(input,=20inputValidator):=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=9E=85=EB=A0=A5=20=EC=B2=98=EB=A6=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 ++++++++-------- src/App.js | 11 +++++++++- src/constants/errorMessage.js | 9 ++++++++ src/utils/input.js | 22 +++++++++++++++++++ src/utils/inputValidator.js | 40 +++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 src/constants/errorMessage.js create mode 100644 src/utils/input.js create mode 100644 src/utils/inputValidator.js diff --git a/README.md b/README.md index 34e21868c..2c3b592ee 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ ### 유저 입력 처리 -- [ ] 사용자는 경주할 자동차에 각각 이름(name)을 부여할 수 있다. -- [ ] 자동차 이름 입력시 n대의 자동차 이름을 입력하며, 이를 통해 경주에 참여하는 자동차 수를 정한다. -- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. -- [ ] 사용자에게 몇 번의 이동을 할 것인지 라운드 횟수(total round)를 입력할 수 있다. +- [x] 사용자는 경주할 자동차에 각각 이름(name)을 부여할 수 있다. +- [x] 자동차 이름 입력시 n대의 자동차 이름을 입력하며, 이를 통해 경주에 참여하는 자동차 수를 정한다. +- [x] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [x] 사용자에게 몇 번의 이동을 할 것인지 라운드 횟수(total round)를 입력할 수 있다. ### 자동차 경주 실행 및 실행 결과 출력 @@ -27,8 +27,8 @@ ### 에러 처리 -- [ ] 사용자가 잘못된 값을 입력한 경우 "[ERROR]"로 시작하는 메시지와 함께 `Error`를 발생시킨 후 애플리케이션이 종료된다. -- [ ] 자동차 이름이 5자를 초과할 경우 -- [ ] 경주할 자동차 이름을 1개 이하로 지정한 경우 -- [ ] 시도할 횟수에 양의 정수 값이 아닌 값을 입력한 경우 -- [ ] 값을 입력하지 않은 경우 +- [x] 사용자가 잘못된 값을 입력한 경우 "[ERROR]"로 시작하는 메시지와 함께 `Error`를 발생시킨 후 애플리케이션이 종료된다. +- [x] 자동차 이름이 5자를 초과할 경우 +- [x] 경주할 자동차 이름을 1개 이하로 지정한 경우 +- [x] 시도할 횟수에 양의 정수 값이 아닌 값을 입력한 경우 +- [x] 값을 입력하지 않은 경우 diff --git a/src/App.js b/src/App.js index 091aa0a5d..71e8d18ca 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,14 @@ +import { getCarNames, getTotalRound } from "./utils/input.js"; + class App { - async run() {} + async run() { + try { + const carNameList = await getCarNames(); + const totalRound = await getTotalRound(); + } catch (error) { + throw new Error(`[ERROR]: ${error.message}`); + } + } } export default App; diff --git a/src/constants/errorMessage.js b/src/constants/errorMessage.js new file mode 100644 index 000000000..b10e129f7 --- /dev/null +++ b/src/constants/errorMessage.js @@ -0,0 +1,9 @@ +export const CAR_NAME_MAX_LENGTH = 5; + +export const ERROR_MESSAGE = { + EMPTY_INPUT: "필수 입력 값입니다.\n항목을 입력해 주세요.\n", + SINGLE_CAR_NAME: + "자동차 경주에는 두 개 이상의 자동차 이름이 필요합니다.\n쉼표(,)를 기준으로 두 개 이상의 이름을 입력해주세요.\n", + MAX_LENGTH_EXCEEDED: `각각의 자동차 이름은 ${CAR_NAME_MAX_LENGTH}글자 이하로 이루어져야 합니다.\n`, + INVALID_NUMBER: "시도할 횟수는 1 이상의 숫자여야 합니다.\n", +}; diff --git a/src/utils/input.js b/src/utils/input.js new file mode 100644 index 000000000..267a48eb1 --- /dev/null +++ b/src/utils/input.js @@ -0,0 +1,22 @@ +import { Console } from "@woowacourse/mission-utils"; +import { validateCarNames, validateRoundNumber } from "./inputValidator.js"; + +export const getCarNames = async () => { + const carNamesInput = await Console.readLineAsync( + "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)\n" + ); + + const carNameList = validateCarNames(carNamesInput); + + return carNameList; +}; + +export const getTotalRound = async () => { + const totalRoundInput = await Console.readLineAsync( + "시도할 횟수는 몇 회인가요?\n" + ); + + const totalRound = validateRoundNumber(totalRoundInput); + + return totalRound; +}; diff --git a/src/utils/inputValidator.js b/src/utils/inputValidator.js new file mode 100644 index 000000000..04c767ab0 --- /dev/null +++ b/src/utils/inputValidator.js @@ -0,0 +1,40 @@ +import { + CAR_NAME_MAX_LENGTH, + ERROR_MESSAGE, +} from "../constants/errorMessage.js"; + +export const validateCarNames = (carNames) => { + if (!carNames || carNames.trim() === "") { + throw new Error(ERROR_MESSAGE.EMPTY_INPUT); + } + + const carNameList = carNames.split(",").map((name) => name.trim()); + if (carNameList.length < 2) { + throw new Error(ERROR_MESSAGE.SINGLE_CAR_NAME); + } + + carNameList.forEach((name) => { + if (name.length > CAR_NAME_MAX_LENGTH) { + throw new Error(ERROR_MESSAGE.MAX_LENGTH_EXCEEDED); + } + }); + + return carNameList; +}; + +export const validateRoundNumber = (totalRound) => { + if (!totalRound) { + throw new Error(ERROR_MESSAGE.EMPTY_INPUT); + } + + const totalRoundNumber = Number(totalRound); + if ( + isNaN(totalRound) || + totalRound <= 0 || + !Number.isInteger(totalRoundNumber) + ) { + throw new Error(ERROR_MESSAGE.INVALID_NUMBER); + } + + return totalRoundNumber; +}; From dccaf5aa14bc72528353ee8900e35c89c506127b Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 23:01:49 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat(Car,=20Race):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EA=B2=BD=EC=A3=BC=20=EC=8B=A4=ED=96=89=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- src/models/Car.js | 30 ++++++++++++++++++++++++++++++ src/models/Race.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/models/Car.js create mode 100644 src/models/Race.js diff --git a/README.md b/README.md index 2c3b592ee..850cc30e1 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ ### 자동차 경주 실행 및 실행 결과 출력 -- [ ] 사용자가 입력한 이동 횟수(total round) 만큼 자동차 경주 함수를 실행한다. -- [ ] 각 차수(round)마다 n대의 자동차는 각각 전진 또는 정지(전진하지 않음) 할 수 있다. -- [ ] 자동차는 매번 0에서 9 사이의 무작위 값을 구한 후, 무작위 값이 4 이상일 경우 전진하고 4 미만일 경우 정지한다. -- [ ] 실행 결과를 출력한다. (자동차마다의 출력 문구: `${자동차 이름(name)} : ${자동차 위치(position)}`) -- [ ] 자동차의 위치(position)는 '-'로 표시한다. ('-'는 1회 전진, '--'는 2회 전진) +- [x] 사용자가 입력한 이동 횟수(total round) 만큼 자동차 경주 함수를 실행한다. +- [x] 각 차수(round)마다 n대의 자동차는 각각 전진 또는 정지(전진하지 않음) 할 수 있다. +- [x] 자동차는 매번 0에서 9 사이의 무작위 값을 구한 후, 무작위 값이 4 이상일 경우 전진하고 4 미만일 경우 정지한다. +- [x] 실행 결과를 출력한다. (자동차마다의 출력 문구: `${자동차 이름(name)} : ${자동차 위치(position)}`) +- [x] 자동차의 위치(position)는 '-'로 표시한다. ('-'는 1회 전진, '--'는 2회 전진) ### 우승자 계산 및 출력 diff --git a/src/models/Car.js b/src/models/Car.js new file mode 100644 index 000000000..1f9eebce0 --- /dev/null +++ b/src/models/Car.js @@ -0,0 +1,30 @@ +import { Random } from "@woowacourse/mission-utils"; + +class Car { + constructor(name) { + this.name = name; + this.position = 0; + } + + move() { + const value = Random.pickNumberInRange(0, 9); + + if (value >= 4) { + this.position++; + } + } + + getName() { + return this.name; + } + + getPosition() { + return this.position; + } + + getState() { + return `${this.name} : ${"-".repeat(this.position)}`; + } +} + +export default Car; diff --git a/src/models/Race.js b/src/models/Race.js new file mode 100644 index 000000000..73a02ff57 --- /dev/null +++ b/src/models/Race.js @@ -0,0 +1,28 @@ +import { Console } from "@woowacourse/mission-utils"; +import Car from "./Car.js"; + +class Race { + constructor(carNames, totalRound) { + this.cars = carNames.map((name) => new Car(name)); + this.totalRound = totalRound; + } + + runARound() { + this.cars.forEach((car) => { + car.move(); + Console.print(car.getState()); + }); + + Console.print(""); + } + + start() { + Console.print("\n실행 결과"); + + for (let i = 0; i < this.totalRound; i++) { + this.runARound(); + } + } +} + +export default Race; From 643835e48a102b4cbdf90c219096c777c8f861d1 Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 23:03:12 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat(Race):=20=EC=9A=B0=EC=8A=B9=EC=9E=90?= =?UTF-8?q?=20=EA=B3=84=EC=82=B0=20=EB=B0=8F=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- src/App.js | 6 +++++- src/models/Race.js | 11 +++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 850cc30e1..a2ec0f7d1 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ ### 우승자 계산 및 출력 -- [ ] 주어진 횟수 동안 가장 많이 전진한 자동차를 우승자(winner)로 출력한다. (출력 문구: `최종 우승자 : ${우승자(winner)}`) -- [ ] 우승자는 한 명 이상일 수 있다. -- [ ] 우승자가 여러 명일 경우 쉼표를 이용하여 구분한다. +- [x] 주어진 횟수 동안 가장 많이 전진한 자동차를 우승자(winner)로 출력한다. (출력 문구: `최종 우승자 : ${우승자(winner)}`) +- [x] 우승자는 한 명 이상일 수 있다. +- [x] 우승자가 여러 명일 경우 쉼표를 이용하여 구분한다. ### 에러 처리 diff --git a/src/App.js b/src/App.js index 71e8d18ca..d3f955235 100644 --- a/src/App.js +++ b/src/App.js @@ -1,3 +1,4 @@ +import Race from "./models/Race.js"; import { getCarNames, getTotalRound } from "./utils/input.js"; class App { @@ -5,8 +6,11 @@ class App { try { const carNameList = await getCarNames(); const totalRound = await getTotalRound(); + + const race = new Race(carNameList, totalRound); + race.start(); } catch (error) { - throw new Error(`[ERROR]: ${error.message}`); + throw new Error(`[ERROR] ${error.message}`); } } } diff --git a/src/models/Race.js b/src/models/Race.js index 73a02ff57..2fff9e2ac 100644 --- a/src/models/Race.js +++ b/src/models/Race.js @@ -16,12 +16,23 @@ class Race { Console.print(""); } + getWinner() { + const maxDistance = Math.max(...this.cars.map((car) => car.getPosition())); + const winner = this.cars + .filter((car) => car.getPosition() === maxDistance) + .map((car) => car.getName()); + + return winner; + } + start() { Console.print("\n실행 결과"); for (let i = 0; i < this.totalRound; i++) { this.runARound(); } + + Console.print(`최종 우승자 : ${this.getWinner().join(", ")}`); } } From e8564069d96ad15668a58a427c0b9a93a72af0fe Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 23:11:26 +0900 Subject: [PATCH 5/7] =?UTF-8?q?fix(inputValidator):=20=EC=9D=B8=ED=92=8B?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80(=EC=9E=90=EB=8F=99=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EB=B0=A9=EC=A7=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/constants/errorMessage.js | 1 + src/utils/inputValidator.js | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/README.md b/README.md index a2ec0f7d1..48057b1d9 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,4 @@ - [x] 경주할 자동차 이름을 1개 이하로 지정한 경우 - [x] 시도할 횟수에 양의 정수 값이 아닌 값을 입력한 경우 - [x] 값을 입력하지 않은 경우 +- [ ] 중복된 자동차 이름 값을 가질 경우 diff --git a/src/constants/errorMessage.js b/src/constants/errorMessage.js index b10e129f7..a1c2bf845 100644 --- a/src/constants/errorMessage.js +++ b/src/constants/errorMessage.js @@ -6,4 +6,5 @@ export const ERROR_MESSAGE = { "자동차 경주에는 두 개 이상의 자동차 이름이 필요합니다.\n쉼표(,)를 기준으로 두 개 이상의 이름을 입력해주세요.\n", MAX_LENGTH_EXCEEDED: `각각의 자동차 이름은 ${CAR_NAME_MAX_LENGTH}글자 이하로 이루어져야 합니다.\n`, INVALID_NUMBER: "시도할 횟수는 1 이상의 숫자여야 합니다.\n", + DUPLICATE_NAME: "자동차 이름이 중복되지 않게 입력해 주세요.\n", }; diff --git a/src/utils/inputValidator.js b/src/utils/inputValidator.js index 04c767ab0..3e2137eb4 100644 --- a/src/utils/inputValidator.js +++ b/src/utils/inputValidator.js @@ -19,6 +19,11 @@ export const validateCarNames = (carNames) => { } }); + const uniqueNames = new Set(carNameList); + if (uniqueNames.size !== carNameList.length) { + throw new Error(ERROR_MESSAGE.DUPLICATE_NAME); + } + return carNameList; }; From 03604827373518658b01a0cf2cb2de5b06c872da Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 23:28:53 +0900 Subject: [PATCH 6/7] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Car.test.js | 48 +++++++++++++++++++++++++++ __tests__/Race.test.js | 72 +++++++++++++++++++++++++++++++++++++++++ __tests__/input.test.js | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 __tests__/Car.test.js create mode 100644 __tests__/Race.test.js create mode 100644 __tests__/input.test.js diff --git a/__tests__/Car.test.js b/__tests__/Car.test.js new file mode 100644 index 000000000..fed06262e --- /dev/null +++ b/__tests__/Car.test.js @@ -0,0 +1,48 @@ +import Car from "../src/models/Car"; +import { Random } from "@woowacourse/mission-utils"; + +describe("Car 클래스 테스트", () => { + test("move: Random 값이 4 이상일 때만 position이 증가한다.", () => { + const car = new Car("testCar"); + + jest.spyOn(Random, "pickNumberInRange").mockReturnValue(4); + car.move(); + expect(car.getPosition()).toBe(1); + + jest.spyOn(Random, "pickNumberInRange").mockReturnValue(3); + car.move(); + expect(car.getPosition()).toBe(1); + + jest.spyOn(Random, "pickNumberInRange").mockRestore(); + }); + + test("getName: 인스턴스의 이름을 반환한다.", () => { + const car = new Car("myCar"); + expect(car.getName()).toBe("myCar"); + }); + + test("getPosition: 인스턴스의 현재 위치를 반환한다.", () => { + const car = new Car("testCar"); + + expect(car.getPosition()).toBe(0); + + jest.spyOn(Random, "pickNumberInRange").mockReturnValue(5); + car.move(); + expect(car.getPosition()).toBe(1); + + jest.spyOn(Random, "pickNumberInRange").mockRestore(); + }); + + test("getState: 인스턴스의 이름과 위치 상태('-'로 표시)를 반환한다.", () => { + const car = new Car("myCar"); + + expect(car.getState()).toBe("myCar : "); + + jest.spyOn(Random, "pickNumberInRange").mockReturnValue(4); + car.move(); + car.move(); + expect(car.getState()).toBe("myCar : --"); + + jest.spyOn(Random, "pickNumberInRange").mockRestore(); + }); +}); diff --git a/__tests__/Race.test.js b/__tests__/Race.test.js new file mode 100644 index 000000000..1750a2ce0 --- /dev/null +++ b/__tests__/Race.test.js @@ -0,0 +1,72 @@ +import Race from "../src/models/Race"; +import { Console } from "@woowacourse/mission-utils"; + +describe("Race 클래스 테스트", () => { + let race; + + beforeEach(() => { + const carNames = ["car1", "car2", "car3"]; + const totalRound = 3; + race = new Race(carNames, totalRound); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("getWinner: 가장 멀리 이동한 자동차를 우승자로 반환한다.", () => { + race.cars[0].position = 2; + race.cars[1].position = 3; + race.cars[2].position = 1; + + expect(race.getWinner()).toEqual(["car2"]); + }); + + test("getWinner: 두 명 이상의 우승자가 발생할 경우 쉼표(,)로 구분하여 반환한다.", () => { + race.cars[0].position = 2; + race.cars[1].position = 3; + race.cars[2].position = 3; + + expect(race.getWinner()).toEqual(["car2", "car3"]); + }); + + test("start: 전체 레이스 결과 및 최종 우승자를 출력한다.", () => { + const printSpy = jest.spyOn(Console, "print"); + + jest + .spyOn(race.cars[0], "move") + .mockImplementation(() => (race.cars[0].position += 2)); + jest + .spyOn(race.cars[1], "move") + .mockImplementation(() => (race.cars[1].position += 3)); + jest + .spyOn(race.cars[2], "move") + .mockImplementation(() => (race.cars[2].position += 1)); + + race.start(); + + expect(printSpy).toHaveBeenCalledWith("\n실행 결과"); + expect(printSpy).toHaveBeenCalledWith("최종 우승자 : car2"); + }); + + test("runARound: 각 자동차의 이름과 이동 상태가 출력된다.", () => { + const printSpy = jest.spyOn(Console, "print"); + + jest + .spyOn(race.cars[0], "move") + .mockImplementation(() => (race.cars[0].position += 1)); + jest + .spyOn(race.cars[1], "move") + .mockImplementation(() => (race.cars[1].position += 2)); + jest + .spyOn(race.cars[2], "move") + .mockImplementation(() => (race.cars[2].position += 3)); + + race.runARound(); + + expect(printSpy).toHaveBeenCalledWith("car1 : -"); + expect(printSpy).toHaveBeenCalledWith("car2 : --"); + expect(printSpy).toHaveBeenCalledWith("car3 : ---"); + expect(printSpy).toHaveBeenCalledWith(""); + }); +}); diff --git a/__tests__/input.test.js b/__tests__/input.test.js new file mode 100644 index 000000000..aba5ab508 --- /dev/null +++ b/__tests__/input.test.js @@ -0,0 +1,64 @@ +import { validateCarNames, validateRoundNumber } from "./inputValidator"; +import { ERROR_MESSAGE } from "../constants/errorMessage"; + +describe("validateCarNames 테스트", () => { + test("유효한 자동차 이름 목록 입력시 이름 목록을 배열로 반환한다.", () => { + const carNames = "car1, car2, car3"; + expect(validateCarNames(carNames)).toEqual(["car1", "car2", "car3"]); + }); + + test("빈 입력 시 오류를 발생시킨다.", () => { + expect(() => validateCarNames("")).toThrow(ERROR_MESSAGE.EMPTY_INPUT); + }); + + test("항목이 하나뿐인 경우 오류를 발생시킨다.", () => { + expect(() => validateCarNames("car1")).toThrow( + ERROR_MESSAGE.SINGLE_CAR_NAME + ); + }); + + test("자동차 이름이 지정된 최대 길이를 초과할 때 오류를 발생시킨다.", () => { + const invalidCarNames = "car123456, car2"; + expect(() => validateCarNames(invalidCarNames)).toThrow( + ERROR_MESSAGE.MAX_LENGTH_EXCEEDED + ); + }); + + test("중복된 이름이 있을 때 오류 발생시킨다.", () => { + const duplicateNames = "car1, car2, car1"; + expect(() => validateCarNames(duplicateNames)).toThrow( + ERROR_MESSAGE.DUPLICATE_NAME + ); + }); +}); + +describe("validateRoundNumber 테스트", () => { + test("유효한 totalRound 입력 시 입력한 값을 정수로 변환하여 반환한다.", () => { + expect(validateRoundNumber("5")).toBe(5); + }); + + test("빈 입력 시 오류를 발생시킨다.", () => { + expect(() => validateRoundNumber("")).toThrow(ERROR_MESSAGE.EMPTY_INPUT); + }); + + test("0 이하의 숫자를 입력할 경우 오류를 발생시킨다.", () => { + expect(() => validateRoundNumber("0")).toThrow( + ERROR_MESSAGE.INVALID_NUMBER + ); + expect(() => validateRoundNumber("-3")).toThrow( + ERROR_MESSAGE.INVALID_NUMBER + ); + }); + + test("소수 입력 시 오류를 발생시킨다.", () => { + expect(() => validateRoundNumber("3.5")).toThrow( + ERROR_MESSAGE.INVALID_NUMBER + ); + }); + + test("숫자가 아닌 문자열 입력 시 오류를 발생시킨다.", () => { + expect(() => validateRoundNumber("abc")).toThrow( + ERROR_MESSAGE.INVALID_NUMBER + ); + }); +}); From 95390225e50cdb82e55f01c00082d511f12824e1 Mon Sep 17 00:00:00 2001 From: aoooec Date: Mon, 28 Oct 2024 23:32:01 +0900 Subject: [PATCH 7/7] =?UTF-8?q?docs(README.md):=20=EB=A6=AC=EB=93=9C?= =?UTF-8?q?=EB=AF=B8=20=EA=B5=AC=ED=98=84=EC=82=AC=ED=95=AD=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48057b1d9..00ac2494a 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,4 @@ - [x] 경주할 자동차 이름을 1개 이하로 지정한 경우 - [x] 시도할 횟수에 양의 정수 값이 아닌 값을 입력한 경우 - [x] 값을 입력하지 않은 경우 -- [ ] 중복된 자동차 이름 값을 가질 경우 +- [x] 중복된 자동차 이름 값을 가질 경우