Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
.vscode
node_modules
dist
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
"version": "1.0.0",
"description": "로또 미션을 통해서 학습하는 클린코드",
"main": "./src/main.js",
"type": "module",
"type": "module",
"scripts": {
"start": "node src/main.js",
"start:watch": "node --watch src/main.js",
"start": "node dist/main.js",
"start:watch": "node --watch dist/main.js",
"build": "tsc",
"clean": "tsc --build --clean",
"test": "vitest"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^20.14.10",
"typescript": "^5.5.3",
"vitest": "^1.6.0"
}
}
47 changes: 47 additions & 0 deletions src/View/LottoView.ts

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 알고 있는 뷰는 데이터를 보여주는 역할을 하고 컨트롤러가 입력을 받아서 모델의 데이터를 조작하는 걸로 알고 있어요!
그래서 지금 뷰에 있는 기능들을 컨트롤러로 옮겨야 하지 않을까 생각이 듭니다!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다시 생각해보니 ask 메서드를 통해 나오는 query가 있어서 뷰에 포함시켜도 될 것 같네요.. 어렵군요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 많이 고민했던 부분인데 console로 입력받는 부분에 필요한 query문이 만약 웹 서비스 형식으로 구현되어있다면 query 출력은 view가 담당하는게 맞지 않을까 생각해서 view로 위치시켰습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import readline from 'readline';

export class LottoView {
public async getMoney(): Promise<number> {
const inputValue = await this.ask('구입 금액을 입력해 주세요. : ');

return Number(inputValue);
}

public async getWinningNumbers(): Promise<number[]> {
const inputValue = await this.ask('당첨 번호를 입력해 주세요. : ');

return inputValue.split(',').map((number) => Number(number));
}

public async getWinningBonusNumber(): Promise<number> {
const inputValue = await this.ask('보너스 번호를 입력해 주세요. : ');

return Number(inputValue);
}

public ask(query: string): Promise<string> {
return new Promise((resolve, reject) => {
if (arguments.length !== 1) {
reject(new Error('arguments must be 1'));
}

if (typeof query !== 'string') {
reject(new Error('query must be string'));
}

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

rl.question(query, (input) => {
rl.close();
resolve(input);
});
});
}

public printMessage(message: string) {
console.log(message);
}
}
32 changes: 32 additions & 0 deletions src/__tests__/Lotto.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Lotto } from '../model/Lotto.js';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확장자 js로 해도 잘 작동되나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문제없이 잘 작동하는데 문제가 될만한 부분이 있을까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 타입스크립트인데 js로 되어있어서 궁금해서 여쭤봤어요 ㅎㅎ


describe('Lotto 클래스', () => {
describe('matchNumbers 메서드', () => {
const lotto = new Lotto([1, 2, 3, 4, 5, 6]);
const winningNumbers = [2, 3, 4, 5, 6, 7];

it('맞춘 숫자 개수와 보너스 번호 포함 여부를 정확하게 반환해야 한다', () => {
const bonusNumber = 8;

const { matchedCount, includedBonusNumber } = lotto.matchNumbers(
winningNumbers,
bonusNumber
);

expect(matchedCount).toBe(5);
expect(includedBonusNumber).toBe(false);
});

it('보너스 번호가 포함된 경우 맞춘 숫자 개수와 보너스 번호 포함 여부를 정확하게 반환해야 한다', () => {
const bonusNumber = 6;

const { matchedCount, includedBonusNumber } = lotto.matchNumbers(
winningNumbers,
bonusNumber
);

expect(matchedCount).toBe(5);
expect(includedBonusNumber).toBe(true);
});
});
});
36 changes: 36 additions & 0 deletions src/__tests__/LottoGame.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { LottoGame } from '../model/LottoGame.js';
import { getRandomNumber } from '../util/getRandomNumber.js';

describe('LottoGame 클래스 테스트', () => {
const lottoGame = new LottoGame();

it('유효하지 않은 로또 규칙을 설정하면 오류를 반환한다.', () => {
expect(() => lottoGame.setLottoRule(1000, 'invalid')).toThrowError();
expect(() => lottoGame.setLottoRule(-1000, '1')).toThrowError();
});

it('유효하지 않은 사용자 금액을 입력하면 오류를 반환한다.', () => {
lottoGame.setLottoRule(1000, '1');

expect(() => lottoGame.setTickets(-1000)).toThrowError();
expect(() => lottoGame.setTickets(500)).toThrowError();
});

it('유효하지 않은 당첨 번호를 설정하면 오류를 반환한다.', () => {
lottoGame.setLottoRule(1000, '1');
lottoGame.setTickets(1000);

expect(() =>
lottoGame.setWinningLotto([1, 2, 3, 4, 5, 5], 6)
).toThrowError();
expect(() =>
lottoGame.setWinningLotto([1, 2, 3, 4, 5, 6], -10)
).toThrowError();
expect(() =>
lottoGame.setWinningLotto([1, 2, 3, 4, 5, 6, 7], 10)
).toThrowError();
expect(() =>
lottoGame.setWinningLotto([1, 2, 3, 4, 5, 6], 6)
).toThrowError();
});
});
11 changes: 11 additions & 0 deletions src/__tests__/LottoRule.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LottoRule } from '../model/LottoRule.js';

describe('LottoRule', () => {
it('가격이 0보다 작으면 에러가 발생한다.', () => {
expect(() => new LottoRule(-1000, '1')).toThrowError();
});

it('로또 타입이 올바르지 않으면 에러가 발생한다.', () => {
expect(() => new LottoRule(1000, 'INVALID_TYPE')).toThrowError();
});
});
29 changes: 29 additions & 0 deletions src/__tests__/getRandomNumber.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getRandomNumber } from '../util/getRandomNumber.js';

describe('getRandomNumber', () => {
it('지정된 최소값과 최대값 사이의 랜덤 숫자를 반환한다.', () => {
const min = 1;
const max = 10;
const randomNumber = getRandomNumber(min, max);

expect(randomNumber).toBeGreaterThanOrEqual(min);
expect(randomNumber).toBeLessThanOrEqual(max);
});

it('최소값과 최대값이 동일할 때 최소값을 반환한다.', () => {
const min = 5;
const max = 5;
const randomNumber = getRandomNumber(min, max);

expect(randomNumber).toBe(min);
});

it('최소값이 최대값보다 클 때 값을 교환하여 랜덤 값을 반환한다.', () => {
const min = 4;
const max = 1;
const randomNumber = getRandomNumber(min, max);

expect(randomNumber).toBeGreaterThanOrEqual(max);
expect(randomNumber).toBeLessThanOrEqual(min);
});
});
13 changes: 13 additions & 0 deletions src/__tests__/hasDuplicatesInArray.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { hasDuplicatesInArray } from '../util/hasDuplicatesInArray.js';

describe('hasDuplicatesInArray', () => {
it('중복된 값이 있는 경우 true를 반환한다.', () => {
const arrayWithDuplicates = [1, 2, 3, 4, 2];
expect(hasDuplicatesInArray(arrayWithDuplicates)).toBe(true);
});

it('중복된 값이 없을 경우 false를 반환한다.', () => {
const arrayWithNoDuplicates = [1, 2, 3, 4, 5];
expect(hasDuplicatesInArray(arrayWithNoDuplicates)).toBe(false);
});
});
15 changes: 15 additions & 0 deletions src/__tests__/isArrayLengthValid.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { isArrayLengthValid } from '../util/isArrayLengthValid.js';

describe('isArrayLengthValid', () => {
it('배열의 길이가 주어진 길이와 일치하면 true를 반환한다.', () => {
const array = [1, 2, 3];
const length = 3;
expect(isArrayLengthValid(array, length)).toBe(true);
});

it('배열의 길이가 주어진 길이와 일치하지 않으면 false를 반환한다.', () => {
const array = [1, 2, 3, 4];
const length = 3;
expect(isArrayLengthValid(array, length)).toBe(false);
});
});
25 changes: 25 additions & 0 deletions src/__tests__/isNumberInRange.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { isNumberInRange } from '../util/isNumberInRange.js';

describe('isNumberInRange', () => {
it('숫자가 최소 범위 미만인 경우 false를 반환한다.', () => {
expect(isNumberInRange({ number: 0, minRange: 1, maxRange: 10 })).toBe(
false
);
});

it('숫자가 최대 범위 초과인 경우 false를 반환한다.', () => {
expect(isNumberInRange({ number: 11, minRange: 1, maxRange: 10 })).toBe(
false
);
});

it('숫자가 유효한 범위 내에 있는 경우 true를 반환한다.', () => {
expect(isNumberInRange({ number: 5, minRange: 1, maxRange: 10 })).toBe(
true
);
});

it('최대 범위가 지정되지 않은 경우에도 유효한 범위 내에 있는 경우 true를 반환한다.', () => {
expect(isNumberInRange({ number: 5, minRange: 1 })).toBe(true);
});
});
15 changes: 15 additions & 0 deletions src/__tests__/isValidInteger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { isValidInteger } from '../util/isValidInteger.js';

describe('isValidInteger', () => {
it('정수인 경우 true 반환', () => {
expect(isValidInteger(42)).toBe(true);
expect(isValidInteger(0)).toBe(true);
expect(isValidInteger(-10)).toBe(true);
});

it('정수가 아닌 경우 false 반환', () => {
expect(isValidInteger(3.14)).toBe(false);
expect(isValidInteger(-4.5)).toBe(false);
expect(isValidInteger(NaN)).toBe(false);
});
});
11 changes: 0 additions & 11 deletions src/__tests__/sum.test.js

This file was deleted.

Loading