Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
403b9eb
docs(README): 기능명세서, 예외사항 작성
BoeunHan Nov 5, 2023
c3c4e1f
docs: eslint, prettier 설정
BoeunHan Nov 5, 2023
8a5a670
feat: 컴퓨터 출력 메세지 상수화
BoeunHan Nov 5, 2023
551f2fc
feat: 에러 메세지 상수화
BoeunHan Nov 5, 2023
8b1b44d
style: MESSAGE 프로퍼티 순서 변경
BoeunHan Nov 5, 2023
e021ce4
refactor: MESSAGE 필드 메소드명 수정
BoeunHan Nov 5, 2023
f0fedad
feat: [ERROR] 접두사 붙여주는 메소드 추가
BoeunHan Nov 5, 2023
b9f34e7
fix(constants): 오타 수정
BoeunHan Nov 5, 2023
69dbd93
style(constants): 개행문자 추가
BoeunHan Nov 5, 2023
bbe6266
chore(constant): 에러 메세지 수정
BoeunHan Nov 5, 2023
3e40ae5
docs: eslint 설정파일 수정
BoeunHan Nov 5, 2023
88c95d2
feat(User): 로또 구입 금액 입력
BoeunHan Nov 5, 2023
8c63861
feat(error): InputError 생성
BoeunHan Nov 5, 2023
414558c
fix(UserInput): 에러 발생시키도록 수정
BoeunHan Nov 5, 2023
dfa82f6
feat(constants): 로또 관련 수치 상수화
BoeunHan Nov 5, 2023
17f96ac
docs(README): 예외사항 추가
BoeunHan Nov 5, 2023
c56c13f
feat(User): 당첨 번호 입력
BoeunHan Nov 5, 2023
e13db91
test(InputTest): 로또 구입 금액 테스트 추가
BoeunHan Nov 5, 2023
4d7d719
maintain(constants): 필요 없는 메소드 삭제
BoeunHan Nov 5, 2023
9d947e7
feat(UserInput): 보너스 번호 입력
BoeunHan Nov 6, 2023
1edcedf
refactor(UserInput): 무한루프를 재귀호출로 수정
BoeunHan Nov 6, 2023
89cbf64
refactor(constants): Object.freeze 위치 변경
BoeunHan Nov 6, 2023
1a13819
refactor(InputValidation): 유효성 검증 클래스 분리
BoeunHan Nov 6, 2023
4a7d4bc
refactor(Lotto): InputError로 수정, 상수 사용
BoeunHan Nov 6, 2023
e9ead03
fix(Lotto): validate 함수 에러 조건 수정
BoeunHan Nov 6, 2023
70a6403
fix(Lotto): import문 파일경로 수정
BoeunHan Nov 6, 2023
9a9da82
feat(Lotto): 로또 번호 오름차순 정렬
BoeunHan Nov 6, 2023
1ee8059
feat(Computer): 유저가 입력한 수만큼 로또 발행
BoeunHan Nov 6, 2023
effcec9
feat(Lotto): 당첨 번호와 해당 로또 번호의 일치하는 숫자 개수 계산
BoeunHan Nov 6, 2023
2f3411e
docs(README): 보너스 번호 유무 계산 기능 추가
BoeunHan Nov 6, 2023
e8cfd80
feat(Lotto): 로또 번호에 보너스 번호의 유무 계산
BoeunHan Nov 6, 2023
35d2ea8
refactor(constants): 변수명 수정
BoeunHan Nov 7, 2023
7f8b1ef
feat(constants): 로또 상금과 라벨을 반환하는 메소드 생성
BoeunHan Nov 7, 2023
9d348b9
refactor(constants): 상수 문자열 수정
BoeunHan Nov 7, 2023
2dd41d8
feat(Lotto): 숫자 일치 개수와 보너스 번호 유무를 넣으면 라벨과 상금을 반환
BoeunHan Nov 7, 2023
9e9b21b
feat(Computer): 발행한 로또 수량과 번호 출력
BoeunHan Nov 7, 2023
c297cb9
feat(Lotto): 등수 반환 함수 구현
BoeunHan Nov 7, 2023
07565e1
refactor(constants): winnings map 생성
BoeunHan Nov 7, 2023
1d3da69
refactor(Lotto): 등수에 해당하는 라벨과 상금 반환
BoeunHan Nov 7, 2023
29251ef
feat(Computer): 유저의 입력으로부터 당첨 번호, 보너스 번호 설정
BoeunHan Nov 7, 2023
6b5b98a
test(LottoTest): 로또 등수 반환 테스트 생성
BoeunHan Nov 7, 2023
c341027
fix(constants): 문법 오류 수정
BoeunHan Nov 7, 2023
f857044
refactor(Lotto): 불필요한 메소드 제거
BoeunHan Nov 7, 2023
e966302
feat(Computer): 로또 결과 가져오는 함수 구현
BoeunHan Nov 7, 2023
9092d9d
feat(NumberConverter): 숫자 3자리 단위로 콤마 찍어서 반환
BoeunHan Nov 8, 2023
85a4e84
feat(Computer): 로또 당첨 내역 통계 출력
BoeunHan Nov 8, 2023
2de15a9
feat(Computer): result를 클래스 필드로 변경
BoeunHan Nov 8, 2023
0e98395
feat(Computer): 총 상금 계산
BoeunHan Nov 8, 2023
1f8cb54
feat(NumberConverter): 소수점 포함해서 콤마 찍는 메소드 추가
BoeunHan Nov 8, 2023
186d718
test: NumberConverter 소수점 포함 콤마 출력 테스트
BoeunHan Nov 8, 2023
48695c7
feat(Computer): 수익률 출력
BoeunHan Nov 8, 2023
94c25bc
feat(Computer): 예외사항 발생 시 에러 메세지 출력
BoeunHan Nov 8, 2023
b7b2e64
feat(App): 앱 실행 로직 구현
BoeunHan Nov 8, 2023
9643f86
refactor(InputValidator): InputValidation 클래스 이름 수정
BoeunHan Nov 8, 2023
259d1e8
refactor(AlertError): InputError 클래스 이름 수정
BoeunHan Nov 8, 2023
a9b8f6c
feat(ArrayConverter): array를 string으로 변환하는 converter 생성
BoeunHan Nov 8, 2023
64d8008
test(ConverterTest): ArrayConverter 테스트 추가
BoeunHan Nov 8, 2023
2f6f383
refactor(InputManager): UserInput 클래스 이름 수정
BoeunHan Nov 8, 2023
c4048fd
refactor(Computer): 로또 발행 기능과 구입 금액 입력 기능 분리
BoeunHan Nov 8, 2023
c0e532d
refactor(LottoManager): 로또 발행 메소드 LottoManager로 이동
BoeunHan Nov 8, 2023
76f7f37
refactor(constants): LOTTERY_WINNINGS 배열로 수정
BoeunHan Nov 8, 2023
3f8bed5
fix(InputTest): InputValidator 클래스명 수정
BoeunHan Nov 8, 2023
5afd95e
style(App): 줄 간격 생성
BoeunHan Nov 8, 2023
02353d9
style: 사용하지 않는 import 제거
BoeunHan Nov 8, 2023
2e3085f
style(ApplicationTest): 큰따옴표 작은따옴표로 수정
BoeunHan Nov 8, 2023
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
28 changes: 28 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['airbnb-base', 'prettier', 'jest'],
overrides: [
{
env: {
node: true,
jest: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'max-depth': ['error', 2],
'max-params': ['error', 3],
'max-lines-per-function': ['error', { max: 15 }],
},
};
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "auto"
}
57 changes: 28 additions & 29 deletions __tests__/ApplicationTest.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import App from "../src/App.js";
import { MissionUtils } from "@woowacourse/mission-utils";
import App from '../src/App.js';
import { MissionUtils } from '@woowacourse/mission-utils';

const mockQuestions = (inputs) => {
MissionUtils.Console.readLineAsync = jest.fn();
Expand All @@ -19,7 +19,7 @@ const mockRandoms = (numbers) => {
};

const getLogSpy = () => {
const logSpy = jest.spyOn(MissionUtils.Console, "print");
const logSpy = jest.spyOn(MissionUtils.Console, 'print');
logSpy.mockClear();
return logSpy;
};
Expand All @@ -28,8 +28,8 @@ const runException = async (input) => {
// given
const logSpy = getLogSpy();

const RANDOM_NUMBERS_TO_END = [1,2,3,4,5,6];
const INPUT_NUMBERS_TO_END = ["1000", "1,2,3,4,5,6", "7"];
const RANDOM_NUMBERS_TO_END = [1, 2, 3, 4, 5, 6];
const INPUT_NUMBERS_TO_END = ['1000', '1,2,3,4,5,6', '7'];

mockRandoms([RANDOM_NUMBERS_TO_END]);
mockQuestions([input, ...INPUT_NUMBERS_TO_END]);
Expand All @@ -39,15 +39,15 @@ const runException = async (input) => {
await app.play();

// then
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("[ERROR]"));
}
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('[ERROR]'));
};

describe("로또 테스트", () => {
describe('로또 테스트', () => {
beforeEach(() => {
jest.restoreAllMocks();
})
});

test("기능 테스트", async () => {
test('기능 테스트', async () => {
// given
const logSpy = getLogSpy();

Expand All @@ -61,38 +61,37 @@ describe("로또 테스트", () => {
[2, 13, 22, 32, 38, 45],
[1, 3, 5, 14, 22, 45],
]);
mockQuestions(["8000", "1,2,3,4,5,6", "7"]);
mockQuestions(['8000', '1,2,3,4,5,6', '7']);

// when
const app = new App();
await app.play();

// then
const logs = [
"8개를 구매했습니다.",
"[8, 21, 23, 41, 42, 43]",
"[3, 5, 11, 16, 32, 38]",
"[7, 11, 16, 35, 36, 44]",
"[1, 8, 11, 31, 41, 42]",
"[13, 14, 16, 38, 42, 45]",
"[7, 11, 30, 40, 42, 43]",
"[2, 13, 22, 32, 38, 45]",
"[1, 3, 5, 14, 22, 45]",
"3개 일치 (5,000원) - 1개",
"4개 일치 (50,000원) - 0개",
"5개 일치 (1,500,000원) - 0개",
"5개 일치, 보너스 볼 일치 (30,000,000원) - 0개",
"6개 일치 (2,000,000,000원) - 0개",
"총 수익률은 62.5%입니다.",
'8개를 구매했습니다.',
'[8, 21, 23, 41, 42, 43]',
'[3, 5, 11, 16, 32, 38]',
'[7, 11, 16, 35, 36, 44]',
'[1, 8, 11, 31, 41, 42]',
'[13, 14, 16, 38, 42, 45]',
'[7, 11, 30, 40, 42, 43]',
'[2, 13, 22, 32, 38, 45]',
'[1, 3, 5, 14, 22, 45]',
'3개 일치 (5,000원) - 1개',
'4개 일치 (50,000원) - 0개',
'5개 일치 (1,500,000원) - 0개',
'5개 일치, 보너스 볼 일치 (30,000,000원) - 0개',
'6개 일치 (2,000,000,000원) - 0개',
'총 수익률은 62.5%입니다.',
];

logs.forEach((log) => {
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(log));
});
});

test("예외 테스트", async () => {
await runException("1000j");
test('예외 테스트', async () => {
await runException('1000j');
});
});

105 changes: 105 additions & 0 deletions __tests__/ComputerTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { MissionUtils } from '@woowacourse/mission-utils';
import Computer from '../src/Computer.js';
import Lotto from '../src/Lotto.js';

const getLogSpy = () => {
const logSpy = jest.spyOn(MissionUtils.Console, 'print');
logSpy.mockClear();
return logSpy;
};

describe('컴퓨터 기능 테스트', () => {
test.each([
{ input: 1000, count: 1 },
{ input: 10000, count: 10 },
])('로또 발행 장수 테스트', async ({ input, count }) => {
const computer = new Computer();
computer.purchaseAmount = input;
await computer.issueLottoForPurchaseAmount();

expect(computer.lottos.length).toBe(count);
});

test('로또 결과 테스트', () => {
const computer = new Computer();
computer.lottos = [
new Lotto([8, 21, 23, 41, 42, 43]),
new Lotto([3, 5, 11, 16, 32, 38]),
new Lotto([7, 11, 16, 35, 36, 44]),
new Lotto([1, 8, 11, 31, 41, 42]),
new Lotto([13, 14, 16, 38, 42, 45]),
new Lotto([7, 11, 30, 40, 42, 43]),
new Lotto([2, 13, 22, 32, 38, 45]),
new Lotto([1, 3, 5, 14, 22, 45]),
];
computer.winningNumbers = [1, 2, 3, 4, 5, 6];
computer.bonusNumber = 7;

expect(computer.getLottoResults()).toEqual([7, 0, 0, 0, 0, 1]);
});

test('로또 결과 출력 테스트', () => {
const computer = new Computer();

const mockGetLottoResults = (result) => {
computer.getLottoResults = jest.fn();
computer.getLottoResults.mockReturnValueOnce(result);
};
mockGetLottoResults([0, 1, 1, 0, 0, 3]);
const logSpy = getLogSpy();

computer.printLottoWinningStatistics();

const logs = [
'당첨 통계',
'---',
'3개 일치 (5,000원) - 3개',
'4개 일치 (50,000원) - 0개',
'5개 일치 (1,500,000원) - 0개',
'5개 일치, 보너스 볼 일치 (30,000,000원) - 1개',
'6개 일치 (2,000,000,000원) - 1개',
];

logs.forEach((log) => {
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(log));
});
});

test.each([
{ input: [0, 0, 0, 0, 0, 1], expected: 5000 },
{ input: [0, 0, 0, 1, 1, 0], expected: 1550000 },
{ input: [0, 1, 0, 0, 1, 0], expected: 2000050000 },
{ input: [0, 0, 0, 0, 0, 2], expected: 10000 },
{ input: [0, 0, 1, 2, 1, 0], expected: 33050000 },
{ input: [0, 1, 1, 1, 1, 1], expected: 2031555000 },
])('총 상금 계산 테스트', ({ input, expected }) => {
const computer = new Computer();
computer.result = input;

expect(computer.getTotalWinnings()).toEqual(expected);
});

test.each([
{ input: 5000, expected: '총 수익률은 6.3%입니다.' },
{ input: 10000, expected: '총 수익률은 12.5%입니다.' },
{ input: 15000, expected: '총 수익률은 18.8%입니다.' },
{ input: 1500000, expected: '총 수익률은 1,875.0%입니다.' },
{ input: 30000000, expected: '총 수익률은 37,500.0%입니다.' },
{ input: 20000000000, expected: '총 수익률은 25,000,000.0%입니다.' },
])('총 수익률 출력 테스트', ({ input, expected }) => {
const computer = new Computer();

const mockGetTotalWinnings = (result) => {
computer.getTotalWinnings = jest.fn();
computer.getTotalWinnings.mockReturnValueOnce(result);
};

mockGetTotalWinnings(input);
const logSpy = getLogSpy();

computer.purchaseAmount = 80000;
computer.printTotalRateOfReturn();

expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(expected));
});
});
31 changes: 31 additions & 0 deletions __tests__/ConverterTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NumberConverter, ArrayConverter } from '../src/utils/Converter.js';
describe('숫자 변환 테스트', () => {
test.each([
{ input: 1000, expected: '1,000' },
{ input: 10000, expected: '10,000' },
{ input: 1000000, expected: '1,000,000' },
])('$input에 1000단위로 콤마를 찍으면, $expected가 반환된다.', ({ input, expected }) => {
expect(NumberConverter.splitIntoThreeDigitWithComma(input)).toBe(expected);
});

test.each([
{ input: 1000.0, expected: '1,000.0' },
{ input: 1000.12, expected: '1,000.1' },
{ input: 1000.16, expected: '1,000.2' },
{ input: 37500.0, expected: '37,500.0' },
{ input: 25000000.0, expected: '25,000,000.0' },
])('$input에 1000단위로 콤마를 찍으면, $expected가 반환된다.', ({ input, expected }) => {
expect(NumberConverter.splitIntoThreeDigitWithCommaContainingDecimalPoint(input, 1)).toBe(
expected,
);
});
});

describe('배열 문자열 변환 테스트', () => {
test.each([{ input: [1, 2, 3, 4, 5], expected: '[1, 2, 3, 4, 5]' }])(
'$input을 문자열로 변환하면, $expected가 반환된다.',
({ input, expected }) => {
expect(ArrayConverter.convertArrayToString(input)).toBe(expected);
},
);
});
83 changes: 83 additions & 0 deletions __tests__/InputTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import InputValidator from '../src/InputValidator.js';

describe('입력 유효성 검증 테스트', () => {
describe('로또 구입 금액 유효성 테스트', () => {
test('빈 값일 경우 예외를 발생시킨다.', () => {
expect(() => InputValidator.checkPurchaseAmount('')).toThrow('[ERROR]');
});

test.each(['abc', 'ㄱㄴㄷ'])('숫자가 아닐 경우 예외를 발생시킨다.', (input) => {
expect(() => InputValidator.checkPurchaseAmount(input)).toThrow('[ERROR]');
});

test.each(['-1000', '0'])('0 이하의 숫자일 경우 예외를 발생시킨다.', (input) => {
expect(() => InputValidator.checkPurchaseAmount(input)).toThrow('[ERROR]');
});

test.each(['1', '100', '1234'])(
'1000으로 나누어떨어지지 않는 숫자일 경우 예외를 발생시킨다.',
(input) => {
expect(() => InputValidator.checkPurchaseAmount(input)).toThrow('[ERROR]');
},
);

test.each(['1000', '10000'])('값이 올바를 경우 예외를 발생시키지 않는다.', (input) => {
expect(() => InputValidator.checkPurchaseAmount(input)).not.toThrow('[ERROR]');
});
});

describe('당첨 번호 유효성 테스트', () => {
test('빈 값일 경우 예외를 발생시킨다.', () => {
expect(() => InputValidator.checkWinningNumbers('')).toThrow('[ERROR]');
});

test.each(['abc,1,2,3,4,5', '1,2,3,4,5,ㄱㄴㄷ'])(
'숫자가 아닐 경우 예외를 발생시킨다.',
(input) => {
expect(() => InputValidator.checkWinningNumbers(input)).toThrow('[ERROR]');
},
);

test.each(['-1000,1,2,3,4,5', '1,2,3,4,5,0'])(
'0 이하의 숫자일 경우 예외를 발생시킨다.',
(input) => {
expect(() => InputValidator.checkWinningNumbers(input)).toThrow('[ERROR]');
},
);

test.each(['1,2,3,4', '1,2,3,4,5,6,7'])(
'숫자가 6개가 아닐 경우 예외를 발생시킨다.',
(input) => {
expect(() => InputValidator.checkWinningNumbers(input)).toThrow('[ERROR]');
},
);

test.each(['1,2,3,4,4,4', '1,1,1,1,1,1'])('숫자가 중복될 경우 예외를 발생시킨다.', (input) => {
expect(() => InputValidator.checkWinningNumbers(input)).toThrow('[ERROR]');
});

test('값이 올바를 경우 예외를 발생시키지 않는다.', () => {
expect(() => InputValidator.checkWinningNumbers('1,2,3,4,5,6')).not.toThrow('[ERROR]');
});
});

describe('보너스 번호 유효성 테스트', () => {
const winningNumbers = [1, 2, 3, 4, 5, 6];

test('빈 값일 경우 예외를 발생시킨다.', () => {
expect(() => InputValidator.checkBonusNumber(winningNumbers, '')).toThrow('[ERROR]');
});

test.each(['abc', 'ㄱㄴㄷ'])('숫자가 아닐 경우 예외를 발생시킨다.', (input) => {
expect(() => InputValidator.checkBonusNumber(winningNumbers, input)).toThrow('[ERROR]');
});

test('당첨 번호에 존재하는 번호일 경우 예외를 발생시킨다.', () => {
expect(() => InputValidator.checkBonusNumber(winningNumbers, '6')).toThrow('[ERROR]');
});

test('값이 올바를 경우 예외를 발생시키지 않는다.', () => {
expect(() => InputValidator.checkBonusNumber(winningNumbers, '7')).not.toThrow('[ERROR]');
});
});
});
Loading