From 5354a73e8ad0a2d0e26740c2a7fd9c694a48b9e2 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 19:24:31 +0900 Subject: [PATCH 01/12] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..46a309bdb --- /dev/null +++ b/docs/README.md @@ -0,0 +1,15 @@ +## 구현할 기능 목록 + +- [ ] 경주할 자동차 이름을 입력받는다. +- [ ] 시도할 횟수를 입력받는다. +- [ ] 경주할 자동차에 대해 각각 0~9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. +- [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임을 완료한 후 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. +- [ ] 사용자 입력을 검증한다. + - [ ] 경주할 자동차 이름에 대한 검증 + - [ ] 시도할 횟수에 대한 검증 + - [ ] 검증 완료 후 에러 발생 시 `[ERROR]` 로 시작하는 에러 문구와 함께 예외를 throw하고 애플리케이션을 종료한다. + +## 테스트 코드 목록 + +- [ ] 사용자 입력 검증 기능 테스트 코드 +- [ ] end-to-end 테스크 코드 작성 From e2b99474f88a4acc178e29c3bdfa63f027c06619 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 19:58:23 +0900 Subject: [PATCH 02/12] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index 46a309bdb..52414aed3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,10 @@ ## 구현할 기능 목록 -- [ ] 경주할 자동차 이름을 입력받는다. -- [ ] 시도할 횟수를 입력받는다. -- [ ] 경주할 자동차에 대해 각각 0~9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. -- [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임을 완료한 후 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. +- [ ] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. +- [ ] 시도할 게임 횟수를 입력받는다. +- [ ] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. +- [ ] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. +- [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. - [ ] 사용자 입력을 검증한다. - [ ] 경주할 자동차 이름에 대한 검증 - [ ] 시도할 횟수에 대한 검증 From 1f9205b835044e9595c471877d85d31b6d7f6d58 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 20:27:24 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EA=B2=BD=EC=A3=BC=ED=95=A0=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=EC=B0=A8=20=EC=9E=85=EB=A0=A5=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20Car=20=EC=9D=B8=EC=8A=A4=ED=84=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 7 ++++++- src/Car.js | 12 ++++++++++++ src/Game.js | 22 ++++++++++++++++++++++ src/Input.js | 21 +++++++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/Car.js create mode 100644 src/Game.js create mode 100644 src/Input.js diff --git a/docs/README.md b/docs/README.md index 52414aed3..50bef3fc1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ ## 구현할 기능 목록 -- [ ] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. +- [x] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. - [ ] 시도할 게임 횟수를 입력받는다. - [ ] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. - [ ] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. diff --git a/src/App.js b/src/App.js index c38b30d5b..27a3aeb3a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,10 @@ +import Game from './Game.js'; + class App { - async play() {} + async play() { + const game = new Game(); + await game.play(); + } } export default App; diff --git a/src/Car.js b/src/Car.js new file mode 100644 index 000000000..822b117c6 --- /dev/null +++ b/src/Car.js @@ -0,0 +1,12 @@ +class Car { + #name = ''; + + constructor(name) { + this.#name = name; + } + /** + * TODO: 경주 자동차 이동 메서드 작성 + */ +} + +export default Car; diff --git a/src/Game.js b/src/Game.js new file mode 100644 index 000000000..15409b85c --- /dev/null +++ b/src/Game.js @@ -0,0 +1,22 @@ +import Car from './Car.js'; +import Input from './Input.js'; + +class Game { + #cars = []; + + async play() { + await this.setCars(); + } + + async setCars() { + const input = new Input(); + // TODO: 사용자 입력 검증 로직 주입해주기 + const value = await input.readLine( + '경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)\n' + ); + // TODO: 쉼표로 구분된 자동자 이름를 배열로 변환해주는 유틸함수 작성 + this.#cars = value.split(',').map((name) => new Car(name)); + } +} + +export default Game; diff --git a/src/Input.js b/src/Input.js new file mode 100644 index 000000000..51ebdd77e --- /dev/null +++ b/src/Input.js @@ -0,0 +1,21 @@ +import { Console } from '@woowacourse/mission-utils'; + +class Input { + async readLine(query) { + try { + const input = await Console.readLineAsync(query); + + /** + * TODO + * - 사용자 검증 로직 작성 + * - readLine 외부에서 검증 로직 주입 + */ + + return input; + } catch (error) { + throw error; + } + } +} + +export default Input; From 6b0c35641835b4a3b470d21a50cd0c06d165d5d8 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 20:34:16 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat(Game):=20=EC=8B=9C=EB=8F=84=ED=95=A0?= =?UTF-8?q?=20=EA=B2=8C=EC=9E=84=20=ED=9A=9F=EC=88=98=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=20=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/Game.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 50bef3fc1..5db7a0a2b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ ## 구현할 기능 목록 - [x] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. -- [ ] 시도할 게임 횟수를 입력받는다. +- [x] 시도할 게임 횟수를 입력받는다. - [ ] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. - [ ] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. - [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. diff --git a/src/Game.js b/src/Game.js index 15409b85c..e6d791767 100644 --- a/src/Game.js +++ b/src/Game.js @@ -3,9 +3,11 @@ import Input from './Input.js'; class Game { #cars = []; + #count = 0; async play() { await this.setCars(); + await this.setCount(); } async setCars() { @@ -17,6 +19,14 @@ class Game { // TODO: 쉼표로 구분된 자동자 이름를 배열로 변환해주는 유틸함수 작성 this.#cars = value.split(',').map((name) => new Car(name)); } + + async setCount() { + const input = new Input(); + // TODO: 사용자 입력 검증 로직 주입해주기 + const value = await input.readLine('시도할 횟수는 몇 회인가요?\n'); + + this.#count = Number(value); + } } export default Game; From 14a88f9dec5583c78b00574f80f52b0a1b72a9d8 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 20:58:29 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat(Game):=20=EB=82=A8=EC=9D=80=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=ED=9A=9F=EC=88=98=20=EA=B0=90=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Game 객체의 #count 변수 감소 - #count가 0이 되면 게임 종료 --- docs/README.md | 2 +- src/Game.js | 8 ++++++++ src/utils/index.js | 0 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/utils/index.js diff --git a/docs/README.md b/docs/README.md index 5db7a0a2b..c4651f4d1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ - [x] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. - [x] 시도할 게임 횟수를 입력받는다. - [ ] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. -- [ ] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. +- [x] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. - [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. - [ ] 사용자 입력을 검증한다. - [ ] 경주할 자동차 이름에 대한 검증 diff --git a/src/Game.js b/src/Game.js index e6d791767..65a14fde7 100644 --- a/src/Game.js +++ b/src/Game.js @@ -8,6 +8,10 @@ class Game { async play() { await this.setCars(); await this.setCount(); + while (this.isFinished()) { + // TODO: 자동차 이동 로직 추가 + this.#count -= 1; + } } async setCars() { @@ -27,6 +31,10 @@ class Game { this.#count = Number(value); } + + isFinished() { + return this.#count !== 0; + } } export default Game; diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 000000000..e69de29bb From fa7572e92a4f7216b02d2c21644e10fb4708cd0c Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 21:15:07 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EA=B2=BD=EC=A3=BC=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Car 클래스에 3개의 메서드 추가 - move(): 0 ~ 9사이의 정수 중 무작위 값을 골라 4 이상이면 #path에 '-' 문자 추가 - getName(): 자동차 이름 반환 - getPath(): 자동자가 이동한 path 반환 --- docs/README.md | 2 +- src/Car.js | 23 ++++++++++++++++++++--- src/Game.js | 12 +++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index c4651f4d1..2d166c276 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ - [x] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. - [x] 시도할 게임 횟수를 입력받는다. -- [ ] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. +- [x] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. - [x] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. - [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. - [ ] 사용자 입력을 검증한다. diff --git a/src/Car.js b/src/Car.js index 822b117c6..9a115e170 100644 --- a/src/Car.js +++ b/src/Car.js @@ -1,12 +1,29 @@ +import { Random } from '@woowacourse/mission-utils'; + class Car { #name = ''; + #path = ''; constructor(name) { this.#name = name; } - /** - * TODO: 경주 자동차 이동 메서드 작성 - */ + + move() { + const value = Random.pickNumberInRange(0, 9); + if (Number(value) < 4) { + return; + } + + this.#path += '-'; + } + + getName() { + return this.#name; + } + + getPath() { + return this.#path; + } } export default Car; diff --git a/src/Game.js b/src/Game.js index 65a14fde7..525fdf315 100644 --- a/src/Game.js +++ b/src/Game.js @@ -1,3 +1,5 @@ +import { Console } from '@woowacourse/mission-utils'; + import Car from './Car.js'; import Input from './Input.js'; @@ -8,8 +10,16 @@ class Game { async play() { await this.setCars(); await this.setCount(); + + Console.print('실행결과'); + while (this.isFinished()) { - // TODO: 자동차 이동 로직 추가 + this.#cars.forEach((car) => { + car.move(); + Console.print(`${car.getName()} : ${car.getPath()}`); + }); + Console.print(''); + this.#count -= 1; } } From f53a616a5f98cdb7b2e8008b2ff4a46fcec31c10 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 22:21:34 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat(Game):=20=EA=B2=BD=EC=A3=BC=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EC=9A=B0=EC=8A=B9=EC=9E=90=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/Game.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 2d166c276..c6a4d6358 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ - [x] 시도할 게임 횟수를 입력받는다. - [x] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. - [x] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. -- [ ] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. +- [x] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. - [ ] 사용자 입력을 검증한다. - [ ] 경주할 자동차 이름에 대한 검증 - [ ] 시도할 횟수에 대한 검증 diff --git a/src/Game.js b/src/Game.js index 525fdf315..67810e732 100644 --- a/src/Game.js +++ b/src/Game.js @@ -22,6 +22,8 @@ class Game { this.#count -= 1; } + + this.showWinner(); } async setCars() { @@ -45,6 +47,23 @@ class Game { isFinished() { return this.#count !== 0; } + + showWinner() { + let maximumPathLength = 0; + this.#cars.forEach((car) => { + const path = car.getPath(); + maximumPathLength = Math.max(maximumPathLength, path.length); + }); + + const winners = this.#cars + .filter((car) => { + const path = car.getPath(); + return maximumPathLength === path.length; + }) + .map((car) => car.getName()); + + Console.print(`최종 우승자 : ${winners.join(', ')}`); + } } export default Game; From 34c3604151dade3965ef5561f06ac6bd9b490c85 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 22:29:05 +0900 Subject: [PATCH 08/12] =?UTF-8?q?chore(Game):=20while=EB=AC=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20for=EB=AC=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for문으로 변경한 이유 - 게임 횟수 값 그대로 유지(#count) - jest에서 while 문 사용시 memory leak 발생 --- src/Game.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Game.js b/src/Game.js index 67810e732..14b1a398f 100644 --- a/src/Game.js +++ b/src/Game.js @@ -13,14 +13,12 @@ class Game { Console.print('실행결과'); - while (this.isFinished()) { + for (let i = 0; i < this.#count; i++) { this.#cars.forEach((car) => { car.move(); Console.print(`${car.getName()} : ${car.getPath()}`); }); Console.print(''); - - this.#count -= 1; } this.showWinner(); @@ -44,10 +42,6 @@ class Game { this.#count = Number(value); } - isFinished() { - return this.#count !== 0; - } - showWinner() { let maximumPathLength = 0; this.#cars.forEach((car) => { From d8ceb395b731d86e7bb4635184d21241f19faa63 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 22:29:52 +0900 Subject: [PATCH 09/12] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - '모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다' 기능 제거 --- docs/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index c6a4d6358..1c8b1d9cc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,6 @@ - [x] 경주할 자동차 이름을 입력받는다. 입력받은 자동차 이름 각각에 대해 `Car` 인스턴스를 생성한다. - [x] 시도할 게임 횟수를 입력받는다. - [x] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. -- [x] 모든 자동차가 이동한 후 게임 횟수를 1 감소시킨다. - [x] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. - [ ] 사용자 입력을 검증한다. - [ ] 경주할 자동차 이름에 대한 검증 From ab517aae96d1d6f6c801155db6ec89a752b17bf1 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 23:23:16 +0900 Subject: [PATCH 10/12] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EA=B2=80=EC=A6=9D=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용자 입력 검증 함수 - 자동차 이름 입력 검증(쉼표 구분, 자동차 이름 5글자 이상) - 유효한 게임 횟수 입력 검증(0 이상의 값) --- docs/README.md | 8 ++++---- src/Game.js | 14 ++++++++++---- src/Input.js | 10 ++++------ src/utils/Validator.js | 28 ++++++++++++++++++++++++++++ src/utils/index.js | 1 + 5 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/utils/Validator.js diff --git a/docs/README.md b/docs/README.md index 1c8b1d9cc..d618d456d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,10 +4,10 @@ - [x] 시도할 게임 횟수를 입력받는다. - [x] 경주할 자동차에 대해 각각 0 ~ 9사이의 정수 중 무작위 값을 구한 후 4이상인 경우 이동한다. - [x] 경주 게임 우승자는 이동 경로가 가장 긴 자동차이다. 게임 횟수가 0이 됐을 때(게임 완료) 우승한 자동차 이름을 쉼표(,)로 구분해 출력한다. -- [ ] 사용자 입력을 검증한다. - - [ ] 경주할 자동차 이름에 대한 검증 - - [ ] 시도할 횟수에 대한 검증 - - [ ] 검증 완료 후 에러 발생 시 `[ERROR]` 로 시작하는 에러 문구와 함께 예외를 throw하고 애플리케이션을 종료한다. +- [x] 사용자 입력을 검증한다. + - [x] 경주할 자동차 이름에 대한 검증 + - [x] 시도할 횟수에 대한 검증 + - [x] 검증 완료 후 에러 발생 시 `[ERROR]` 로 시작하는 에러 문구와 함께 예외를 throw하고 애플리케이션을 종료한다. ## 테스트 코드 목록 diff --git a/src/Game.js b/src/Game.js index 14b1a398f..f15bb5aff 100644 --- a/src/Game.js +++ b/src/Game.js @@ -2,6 +2,7 @@ import { Console } from '@woowacourse/mission-utils'; import Car from './Car.js'; import Input from './Input.js'; +import Validator from './utils/Validator.js'; class Game { #cars = []; @@ -26,9 +27,12 @@ class Game { async setCars() { const input = new Input(); - // TODO: 사용자 입력 검증 로직 주입해주기 + const value = await input.readLine( - '경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)\n' + '경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)\n', + { + validator: Validator.validCarList, + } ); // TODO: 쉼표로 구분된 자동자 이름를 배열로 변환해주는 유틸함수 작성 this.#cars = value.split(',').map((name) => new Car(name)); @@ -36,8 +40,10 @@ class Game { async setCount() { const input = new Input(); - // TODO: 사용자 입력 검증 로직 주입해주기 - const value = await input.readLine('시도할 횟수는 몇 회인가요?\n'); + + const value = await input.readLine('시도할 횟수는 몇 회인가요?\n', { + validator: Validator.rangeOverZero, + }); this.#count = Number(value); } diff --git a/src/Input.js b/src/Input.js index 51ebdd77e..92c3bd2f1 100644 --- a/src/Input.js +++ b/src/Input.js @@ -1,15 +1,13 @@ import { Console } from '@woowacourse/mission-utils'; class Input { - async readLine(query) { + async readLine(query, { validator }) { try { const input = await Console.readLineAsync(query); - /** - * TODO - * - 사용자 검증 로직 작성 - * - readLine 외부에서 검증 로직 주입 - */ + if (typeof validator === 'function') { + validator(input); + } return input; } catch (error) { diff --git a/src/utils/Validator.js b/src/utils/Validator.js new file mode 100644 index 000000000..fec57b8e3 --- /dev/null +++ b/src/utils/Validator.js @@ -0,0 +1,28 @@ +function rangeOverZero(input) { + if (!Number.isSafeInteger(Number(input))) { + throw new Error('[ERROR] 올바른 정수를 입력해주세요'); + } + if (Number(input) < 0) { + throw new Error('[ERROR] 음이 아닌 정수를 입력해주세요'); + } +} + +function validLength(input, { minLength = 1, maxLength }) { + return minLength <= input.length && input.length <= maxLength; +} + +function validCarList(input) { + const list = input.split(','); + if (list.every((item) => validLength(item, { maxLength: 5 }))) { + return; + } + throw new Error('[ERROR] 자동차 이름을 1글자 이상 5글자 이하로 작성해주세요'); +} + +const Validator = { + rangeOverZero, + validLength, + validCarList, +}; + +export default Validator; diff --git a/src/utils/index.js b/src/utils/index.js index e69de29bb..031e0cf2c 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -0,0 +1 @@ +export * from './Validator.js'; From 8d81cd18b4c1869246ae0710d445073c42dc5636 Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 23:46:55 +0900 Subject: [PATCH 11/12] =?UTF-8?q?test(Validator):=20Validator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/ValidatorTest.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 __tests__/ValidatorTest.js diff --git a/__tests__/ValidatorTest.js b/__tests__/ValidatorTest.js new file mode 100644 index 000000000..1c32826fe --- /dev/null +++ b/__tests__/ValidatorTest.js @@ -0,0 +1,27 @@ +import Validator from '../src/utils/Validator'; + +describe('Validator 함수 테스트', () => { + test('5글자 초과 시 예외 처리', () => { + const input = 'abcdefghi,abc'; + + expect(() => Validator.validCarList(input)).toThrow('[ERROR]'); + }); + + test('음의 정수 입력 시 예외 처리', () => { + const input = '-1'; + + expect(() => Validator.rangeOverZero(input)).toThrow('[ERROR]'); + }); + + test('정수 이외의 입력값에 대한 예외 처리', () => { + const input = 'abcd'; + + expect(() => Validator.rangeOverZero(input)).toThrow('[ERROR]'); + }); + + test('5글자 초과 시 false 반환', () => { + const input = 'abcdef'; + + expect(Validator.validLength(input, { maxLength: 5 })).toBe(false); + }); +}); From ee1dd396c33a933f7bef15c4fbb64728c701122f Mon Sep 17 00:00:00 2001 From: Jeongjin Date: Wed, 1 Nov 2023 23:47:08 +0900 Subject: [PATCH 12/12] =?UTF-8?q?docs:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index d618d456d..393271602 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,5 +11,4 @@ ## 테스트 코드 목록 -- [ ] 사용자 입력 검증 기능 테스트 코드 -- [ ] end-to-end 테스크 코드 작성 +- [x] 사용자 입력 검증 기능 테스트 코드