diff --git a/docs/README.md b/docs/README.md
index e69de29..336b510 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -0,0 +1,614 @@
+# ๐
ํฌ๋ฆฌ์ค๋ง์ค ํ๋ก๋ชจ์
+
+### [ ๋ชฉ์ฐจ ]
+
+#### 1. [ ๋น์ฆ๋์คํ ์ ๋ฌ์ฌํญ ](#๋น์ฆ๋์ค-ํ-์ ๋ฌ์ฌํญ)
+
+- [ํ๋ก๊ทธ๋จ ๊ธฐ๋ฅ ์ค๋ช
](#ํ๋ก๊ทธ๋จ-๊ธฐ๋ฅ-์ค๋ช
)
+ - [์์ฝ ๋ ์ง ์
๋ ฅ](#์์ฝ-๋ ์ง-์
๋ ฅ)
+ - [์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ](#์ฃผ๋ฌธ-๋ด์ญ-์
๋ ฅ)
+ - [์คํ ๊ฒฐ๊ณผ ์์](#์คํ-๊ฒฐ๊ณผ-์์)
+
+#### 2. [ ๊ฐ๋ฐํ ์ ๋ฌ์ฌํญ ](#๊ฐ๋ฐํ-์ ๋ฌ์ฌํญ)
+
+- [๊ธฐ๋ฅ ๋ชฉ๋ก](#๊ธฐ๋ฅ-๋ชฉ๋ก)
+- [ํ๋ก๊ทธ๋จ ํจํค์ง ๊ตฌ์กฐ](#ํจํค์ง-๊ตฌ์กฐ)
+- [ํ๋ก์ ํธ ์ํคํ
์ฒ](#ํ๋ก์ ํธ-์ํคํ
์ฒ)
+- [์ถํ ํ์ฅ ๋ฐ ์ฝ๋ ์ฌ์ฌ์ฉ ์ ์ฐธ๊ณ ์ฌํญ](#์ถํ-ํ์ฅ-๋ฐ-์ฝ๋-์ฌ์ฌ์ฉ-์-์ฐธ๊ณ ์ฌํญ)
+
+#### 3. [ ๊ณตํต ์ ๋ฌ ์ฌํญ ]
+
+- [1์ฃผ์ผ ๋ค ๊ฐ๋ฐ ํ์์์ ๋
ผ์ํ๋ฉด ์ข์ ์ฌํญ](#1์ฃผ์ผ-๋ค-๊ฐ๋ฐ-ํ์์์-๋
ผ์ํ๋ฉด-์ข์-์ฌํญ)
+
+---
+
+## ๋น์ฆ๋์ค ํ ์ ๋ฌ์ฌํญ
+
+> ### ํ๋ก๊ทธ๋จ ๊ธฐ๋ฅ ์ค๋ช
+
+#### ์์ฝ ๋ ์ง ์
๋ ฅ
+
+#### 1-1. ์์ฝ ๋ ์ง ์
๋ ฅ ( ์ ํจํ์ง ์์ ์
๋ ฅ๊ฐ )
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>
+[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>a
+[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>40
+[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>-5
+[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+```
+
+#### ์ ํจํ์ง ์์ ์์ฝ๋ ์ง ์
๋ ฅ ๊ธฐ์ค
+
+- ์์ฝ ๋ ์ง ์
๋ ฅ์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ ์
๋ ฅํ ์,
+
์๋ฌ๊ฐ ๋ฐ์ํ๊ณ ์์ฝ ๋ ์ง๋ฅผ ๋ค์ ์
๋ ฅ๋ฐ์ต๋๋ค.
+ - ๋น์ด์๋ ๊ฐ
+ - ์ซ์ ํ์์ด ์๋ ์
๋ ฅ ๊ฐ
+ - 1๋ถํฐ 31 ์ฌ์ด๊ฐ ์๋ ๊ฐ
+ - 0๋ณด๋ค ์์ ์ซ์ ๊ฐ
+ - ๊ณต๋ฐฑ ํฌํจ 2000๊ธ์ ์ด์์ธ ๊ฐ
+ - ๊ณต๋ฐฑ ์ ๊ฑฐ ํ 3๊ธ์ ์ด์์ธ ๊ฐ
+
+#### 1-2. ์์ฝ ๋ ์ง ์
๋ ฅ ( ์ฌ๋ฐ๋ฅธ ์
๋ ฅ ๊ฐ + ๊ณต๋ฐฑ์ ํฌํจํ ์
๋ ฅ ๊ฐ )
+
+```bash
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>24
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+```
+
+```bash
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>31
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+```
+
+```bash
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>2 1
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+```
+
+```bash
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+> 3 1
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+```
+
+- ์์ฝ ๋ ์ง ์
๋ ฅ์ด ๊ณต๋ฐฑ์ ํฌํจํ๋๋ผ๋
+ [์ ํจํ์ง ์์ ๊ฐ](#์ ํจํ์ง-์์-์์ฝ๋ ์ง-์
๋ ฅ-๊ธฐ์ค)์ด ์๋ ํ์์ ์
๋ ฅ์ด๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
+
+#### ์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ
+
+#### 2-1. ์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ ( ์ ํจํ์ง ์์ ์
๋ ฅ๊ฐ )
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>1
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>-3
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-a
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํ๋๊ฐ๋ฆญ์นํจ-1
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>์์ ์๋ฌ๋-2,ํํ์ค-3,ํฐ๋ณธ์คํ
์ดํฌ-5,์ ๋ก์ฝ๋ผ-10,ํด์ฐ๋ฌผํ์คํ-5
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>์ ๋ก์ฝ๋ผ-3,๋ ๋์์ธ-2,์ดํ์ธ-1
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+> ํํ์ค-1,์์ ์๋ฌ๋-,ํฐ๋ณธ์คํ
์ดํฌ-3
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+> ์์ด์คํฌ๋ฆผ-1,-3,์ด์ฝ์ผ์ดํฌ-1
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+> ์์ ์๋ฌ๋-1,์ด์ฝ์ผ์ดํฌ-1,์์ ์๋ฌ๋-1
+[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>
+```
+
+#### ์ ํจํ์ง ์์ ์ฃผ๋ฌธ๋ด์ญ ์
๋ ฅ ๊ธฐ์ค
+
+- ์ฃผ๋ฌธ ๋ด์ญ์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ ์
๋ ฅํ ์,
+
์๋ฌ๊ฐ ๋ฐ์ํ๊ณ ์ฃผ๋ฌธ ๋ด์ญ์ ๋ค์ ์
๋ ฅ๋ฐ์ต๋๋ค.
+ - ๋น์ด์๋ ๊ฐ
+ - ๋ฉ๋ด ์ด๋ฆ์ด ๋น์ด์๋ ๊ฐ
+ - ๋ฉ๋ด ๊ฐ์๊ฐ ๋น์ด์๋ ๊ฐ
+ - ๋ฉ๋ด ๊ฐ์๊ฐ ์ซ์ ํ์์ด ์๋ ๊ฐ
+ - ๋ฉ๋ด ์ด๋ฆ์ด 30๊ธ์ ์ด๊ณผ์ธ ๊ฐ
+ - ๋ฉ๋ด ๊ฐ์๊ฐ 3๊ธ์ ์ด๊ณผ์ธ ๊ฐ
+ - ํ๋งค์ค์ธ ๋ฉ๋ด๊ฐ ์๋ ๋ฉ๋ด ์ด๋ฆ์ ํฌํจํ ๊ฐ
+ - ๊ฐ ์ฃผ๋ฌธ์ ๋ฉ๋ด ๊ฐ์ ํฉ์ด 20๊ฐ๋ฅผ ์ด๊ณผํ๋ ๊ฐ
+ - ๋ฉ๋ด ์ด๋ฆ์ด ์๋ฃ๋ง์ผ๋ก ์ด๋ฃจ์ด์ง ๊ฐ
+ - ๋ฉ๋ด ์ด๋ฆ๊ณผ ๋ฉ๋ด ๊ฐ์๋ฅผ ๋๋๋ ๊ตฌ๋ถ์(-)๊ฐ ํฌํจ๋์ง ์๋ ๊ฐ
+ - ๊ตฌ๋ถ์(-)๋ก ๋๋๋ ๊ฐ
+ - ๊ณต๋ฐฑ ํฌํจ 2000๊ธ์ ์ด๊ณผ์ธ ๊ฐ
+ - ๊ณต๋ฐฑ ์ ๊ฑฐ ํ 1000๊ธ์ ์ด๊ณผ์ธ ๊ฐ
+
+#### 2-2. ์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ ( ์ฌ๋ฐ๋ฅธ ์
๋ ฅ๊ฐ + ๊ณต๋ฐฑ์ ํฌํจํ ์
๋ ฅ๊ฐ )
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>31
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-1,ํฐ๋ณธ์คํ
์ดํฌ-1,๋ฐ๋นํ๋ฆฝ-1,์์ด์คํฌ๋ฆผ-1,์ด์ฝ์ผ์ดํฌ-1,์ดํ์ธ-1,๋ ๋์์ธ-1
+12์ 31์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+...
+```
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>25
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>์ ์ก์ด ์ ํ - 1, ํฐ ๋ณธ์คํ
์ดํฌ-1,๋ฐ๋นํ ๋ฆฝ-1, ์ด์ฝ ์ผ์ดํฌ-1, ํฌ๋ฆฌ์ค๋ง์ค ํ์คํ -1, ๋ ๋ ์์ธ-1
+12์ 25์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+...
+```
+
+- ์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ์ด ๊ณต๋ฐฑ์ ํฌํจํ๋๋ผ๋
+ [์ ํจํ์ง ์์ ๊ฐ](#์ ํจํ์ง-์์-์ฃผ๋ฌธ๋ด์ญ-์
๋ ฅ-๊ธฐ์ค)์ด ์๋ ํ์์ ์
๋ ฅ์ด๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
+
+#### ์คํ ๊ฒฐ๊ณผ ์์
+
+- ๋ค์์ ์ดํด๋ฅผ ๋๊ธฐ ์ํ ๋ช๊ฐ์ง ์์ ํ๋ก๊ทธ๋จ ์คํ ๊ฒฐ๊ณผ์
๋๋ค.
+
+#### 3-1. ์ฃผ๋ฌธ ๊ธ์ก์ด 10000์ ๋ฏธ๋ง, ์ด๋ฒคํธ ์ ์ฉ ๋์์ด ์๋ ์ฃผ๋ฌธ
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>1
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-1,์ ๋ก์ฝ๋ผ-1
+12์ 1์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+
+<์ฃผ๋ฌธ ๋ฉ๋ด>
+์ ๋ก์ฝ๋ผ 1๊ฐ
+ํํ์ค 1๊ฐ
+
+<ํ ์ธ ์ ์ด์ฃผ๋ฌธ ๊ธ์ก>
+8,500์
+
+<์ฆ์ ๋ฉ๋ด>
+์์
+
+<ํํ ๋ด์ญ>
+์์
+
+<์ดํํ ๊ธ์ก>
+0์
+
+<ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก>
+8,500์
+
+<12์ ์ด๋ฒคํธ ๋ฐฐ์ง>
+์์
+```
+
+#### 3-2. ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ, ํ์ผ ํ ์ธ ์ ์ฉ ์ฃผ๋ฌธ ์์
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>13
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-1,์์ ์๋ฌ๋-1,ํฐ๋ณธ์คํ
์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1,์ ๋ก์ฝ๋ผ-1
+12์ 13์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+
+<์ฃผ๋ฌธ ๋ฉ๋ด>
+์ด์ฝ์ผ์ดํฌ 1๊ฐ
+์ ๋ก์ฝ๋ผ 1๊ฐ
+ํํ์ค 1๊ฐ
+ํฐ๋ณธ์คํ
์ดํฌ 1๊ฐ
+์์ ์๋ฌ๋ 1๊ฐ
+
+<ํ ์ธ ์ ์ด์ฃผ๋ฌธ ๊ธ์ก>
+86,500์
+
+<์ฆ์ ๋ฉ๋ด>
+์์
+
+<ํํ ๋ด์ญ>
+ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ: -2,200์
+ํ์ผ ํ ์ธ: -2,023์
+
+<์ดํํ ๊ธ์ก>
+-4,223์
+
+<ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก>
+82,277์
+
+<12์ ์ด๋ฒคํธ ๋ฐฐ์ง>
+์์
+```
+
+#### 3-3. ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ, ์ฃผ๋ง ํ ์ธ, ์ฆ์ ์ด๋ฒคํธ ์ ์ฉ ์ฃผ๋ฌธ ์์
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>23
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-2,ํฐ๋ณธ์คํ
์ดํฌ-1,ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1
+12์ 23์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+
+<์ฃผ๋ฌธ ๋ฉ๋ด>
+ํํ์ค 2๊ฐ
+ํฐ๋ณธ์คํ
์ดํฌ 1๊ฐ
+ํด์ฐ๋ฌผํ์คํ 2๊ฐ
+๋ ๋์์ธ 1๊ฐ
+
+<ํ ์ธ ์ ์ด์ฃผ๋ฌธ ๊ธ์ก>
+196,000์
+
+<์ฆ์ ๋ฉ๋ด>
+์ดํ์ธ 1๊ฐ
+
+<ํํ ๋ด์ญ>
+ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ: -3,200์
+์ฃผ๋ง ํ ์ธ: -6,069์
+์ฆ์ ์ด๋ฒคํธ: -25,000์
+
+<์ดํํ ๊ธ์ก>
+-34,269์
+
+<ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก>
+186,731์
+
+<12์ ์ด๋ฒคํธ ๋ฐฐ์ง>
+์ฐํ
+```
+
+#### 3-4. ํ์ผ ํ ์ธ๋ง ์ ์ฉ๋ ์ฃผ๋ฌธ ์์
+
+```bash
+์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น 12์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค.
+12์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)
+>28
+์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)
+>ํํ์ค-1,์์ด์คํฌ๋ฆผ-3,์ ๋ก์ฝ๋ผ-1
+12์ 28์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!
+
+<์ฃผ๋ฌธ ๋ฉ๋ด>
+์ ๋ก์ฝ๋ผ 1๊ฐ
+ํํ์ค 1๊ฐ
+์์ด์คํฌ๋ฆผ 3๊ฐ
+
+<ํ ์ธ ์ ์ด์ฃผ๋ฌธ ๊ธ์ก>
+23,500์
+
+<์ฆ์ ๋ฉ๋ด>
+์์
+
+<ํํ ๋ด์ญ>
+ํ์ผ ํ ์ธ: -6,069์
+
+<์ดํํ ๊ธ์ก>
+-6,069์
+
+<ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก>
+17,431์
+
+<12์ ์ด๋ฒคํธ ๋ฐฐ์ง>
+๋ณ
+```
+
+---
+
+## ๊ฐ๋ฐํ ์ ๋ฌ์ฌํญ
+
+## ๐จโ๐ป๊ธฐ๋ฅ ๋ชฉ๋ก
+
+## ๐ป [ ์
๋ ฅ ๋ฐ ์
๋ ฅ๊ฐ ๊ฒ์ฆ ๊ธฐ๋ฅ ]
+
+> ### ๐ฏ ๋ชจ๋ ์ข
๋ฅ ์
๋ ฅ๊ฐ์ ๋ํ ๊ฒ์ฆ
+
+- [x] ๋ชจ๋ ์ฌ์ฉ์ ์
๋ ฅ๊ฐ์ ๊ณต๋ฐฑ ํฌํจ ๊ธธ์ด 2000๊ธ์ ์ดํ๋ก ํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `BasicInputException`์ ๋ฐ์์ํค๊ณ ,
+ ์
๋ ฅ ์ข
๋ฅ์ ๋ฐ๋ผ "[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์." ๋๋
"[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์
+ ํด๋น ์
๋ ฅ
+ ์ข
๋ฅ(๋ ์ง ํน์ ์ฃผ๋ฌธ)์ ๋ฐ๋๋ค.
+
+> ### ๐ ์์ฝ ๋ ์ง ์
๋ ฅ ๋ฐ ์
๋ ฅ๊ฐ ๊ฒ์ฆ
+
+- [x] `์์ฝ ๋ ์ง` ์
๋ ฅ ์์ฒญ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] ์ฌ์ฉ์์๊ฒ `์์ฝ ๋ ์ง`๋ฅผ ์
๋ ฅ๋ฐ๋๋ค.
+ - [x] ๋ ์ง๊ฐ ๋น์ด์๋ ๊ฐ์ด ์๋์ ํ์ธํ๋ค.
+ - [x] ๋ ์ง์ ๊ณต๋ฐฑ์ด ํฌํจ๋์ด ์๋์ง ํ์ธํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ์ ๋ค์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ๊ธ์ ์ค๊ฐ์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํด ๊ณต๋ฐฑ ์ฌ์ด๋ฅผ ์ด์ด์ค๋ค.
+ - [x] ๊ณต๋ฐฑ ์ ๊ฑฐ ํ ๊ธ์ ๊ธธ์ด๊ฐ 2 ์ดํ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์์ฝ ๋ ์ง๊ฐ ์ซ์ ํ์์ธ์ง ํ์ธํ๋ค.
+ - [x] ์์ฝ ๋ ์ง๊ฐ ์์์ธ์ง ํ์ธํ๋ค.
+- [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ `DayInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์์ฝ ๋ ์ง` ์
๋ ฅ์ ๋ฐ๋๋ค.
+
+> ### ๐ ์ฃผ๋ฌธ ๋ด์ญ ์
๋ ฅ ๋ฐ ์
๋ ฅ๊ฐ ๊ฒ์ฆ
+
+- [x] `์ฃผ๋ฌธ ๋ด์ญ` ์
๋ ฅ ์์ฒญ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] ์ฌ์ฉ์์๊ฒ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ๋ฐ๋๋ค.
+ - [x] `์ฃผ๋ฌธ ๋ด์ญ`์ด ๋น์ด์์ง ์์์ง ํ์ธํ๋ค.
+ - [x] `์ฃผ๋ฌธ ๋ด์ญ`์ด 1000๊ธ์ ์ดํ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `BasicInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ๊ณต๋ฐฑ์ด ํฌํจ๋์ด ์๋์ง ํ์ธํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ์ ๋ค์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ๊ธ์ ์ค๊ฐ์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํด ๊ณต๋ฐฑ ์ฌ์ด๋ฅผ ์ด์ด์ค๋ค.
+ - [x] `์ฃผ๋ฌธ`์ `๋ฉ๋ด ์ด๋ฆ`๊ณผ `๋ฉ๋ด ๊ฐ์`๋ก ์ด๋ฃจ์ด์ง๋ค.
+ - [x] `์ฃผ๋ฌธ`์ ์ผํ(,)๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ตฌ๋ถํ๋ค.
+ - [x] `๋ฉ๋ด ์ด๋ฆ`์ `๋ฉ๋ด ๊ฐ์`๋ ๋์(-)๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ตฌ๋ถํ๋ค.
+
+> #### i) ๐`์ฃผ๋ฌธ`์ ๋ํ ์
๋ ฅ๊ฐ ๊ฒ์ฆ
+
+- [x] `์ฃผ๋ฌธ`์ด ๋น์ด์๋ ๊ฐ์ด ์๋์ ํ์ธํ๋ค.
+- [x] `์ฃผ๋ฌธ`์ด 50๊ธ์ ์ดํ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `BasicInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+- [x] `์ฃผ๋ฌธ`์ด ๋์(-)๋ฅผ ํฌํจํ๋์ง ํ์ธํ๋ค.
+- [x] `์ฃผ๋ฌธ` ์ ๋ค์ ๊ณต๋ฐฑ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ์๋ค์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๋ค.
+ - [x] ๊ณต๋ฐฑ์ด ๊ธ์ ์ค๊ฐ์ ํฌํจ๋์ด ์์ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํด ๊ณต๋ฐฑ ์ฌ์ด๋ฅผ ์ด์ด์ค๋ค.
+- [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `OrdersInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+
+> #### ii) โ๏ธ`๋ฉ๋ด ์ด๋ฆ`์ ๋ํ ์
๋ ฅ๊ฐ ๊ฒ์ฆ
+
+- [x] `๋ฉ๋ด ์ด๋ฆ`์ด ๋น์ด์๋ ๊ฐ์ด ์๋์ ํ์ธํ๋ค.
+- [x] `๋ฉ๋ด ์ด๋ฆ`์ด 30๊ธ์ ์ดํ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `BasicInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+- [x] `๋ฉ๋ด ์ด๋ฆ`์ด ๋ฉ๋ดํ์ ์๋ ๋ฉ๋ด์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `InvalidOrdersException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์." ๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+
+> #### iii) `๋ฉ๋ด ๊ฐ์`์ ๋ํ ์
๋ ฅ๊ฐ ๊ฒ์ฆ
+
+- [x] `๋ฉ๋ด ๊ฐ์`๊ฐ ๋น์ด์๋ ๊ฐ์ด ์๋์ ํ์ธํ๋ค.
+- [x] `๋ฉ๋ด ๊ฐ์`๊ฐ 2๊ธ์ ์ดํ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `BasicInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+- [x] `๋ฉ๋ด ๊ฐ์`๊ฐ ์ซ์ ํ์์ธ์ง ํ์ธํ๋ค.
+- [x] `๋ฉ๋ด ๊ฐ์`๊ฐ 1 ์ด์ ์ ์ ์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `OrdersInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+
+> #### ๐ iv) `์ฃผ๋ฌธ ๋ด์ญ` ์
๋ ฅ๊ฐ ์ฌ๊ฒ์ฆ
+
+- [x] `์ฃผ๋ฌธ ๋ด์ญ`์ ์ทจํฉํ์ ๋, ์ค๋ณต ๋ฉ๋ด๊ฐ ์กด์ฌํ๋์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `OrdersInputException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+
+## ๐งฉ [ ๋น์ฆ๋์ค ๋ก์ง ๊ด๋ จ ๊ธฐ๋ฅ ]
+
+> ### ๐ ๋ ์ง์ ๋ํ ์ ์ฉ ๊ฐ๋ฅํ ์ด๋ฒคํธ ํ๋จ ๋๋ฉ์ธ ๋ก์ง
+
+- ์ฌ์ฉ์์๊ฒ ์
๋ ฅ๋ฐ์ ๋ ์ง์ ๋ํด
+ - [x] ๋ ์ง๊ฐ 1 ์ด์ 31 ์ดํ์ ์ซ์์ธ์ง ํ์ธํ๋ค.
+ - [x] 1 ์ด์ 31 ์ดํ์ ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ, `InvalidDayException`์ ๋ฐ์์ํค๊ณ ,
"[ERROR] ์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ
+ ์ถ๋ ฅํ๋ค.
+ - [x] ํด๋น ๋ ์ง๊ฐ ํฌ๋ฆฌ์ค๋ง์ค D-Day ํ๋ก๋ชจ์
๋์ ๋ ์ง์ธ์ง ํ์ธํ๋ค.
+ - [x] ํ์ผ ํ ์ธ ๋์ ๋ ์ง์ธ์ง ํ์ธํ๋ค.
+ - [x] ์ฃผ๋ง ํ ์ธ ๋์ ๋ ์ง์ธ์ง ํ์ธํ๋ค.
+ - [x] ํน๋ณ ํ ์ธ ๋์ ๋ ์ง์ธ์ง ํ์ธํ๋ค.
+
+> ### ๐ ์ฃผ๋ฌธ ๋ด์ญ์ ๋ฐ๋ฅธ ์ด๋ฒคํธ ์ ์ฉ ์ฌ๋ถ ํ๋จ ๋๋ฉ์ธ ๋ก์ง
+
+- ์ฌ์ฉ์์๊ฒ ์
๋ ฅ๋ฐ์ ์ฃผ๋ฌธ ๋ด์ญ( ๋ฉ๋ด ์ด๋ฆ๊ณผ ์๋ )์ ๋ํด
+ - [x] `์ฃผ๋ฌธ ๋ด์ญ`์ ์ทจํฉํ์ ๋, `๋ฉ๋ด ๊ฐ์`๊ฐ `20๊ฐ`๊ฐ ๋์ด๊ฐ๋์ง ํ์ธํ๋ค.
+ - [x] `์ฃผ๋ฌธ ๋ด์ญ`์ ์ทจํฉํ์ ๋, `์ฃผ๋ฌธ ๋ด์ญ`์ ์๋ฃ์๋ง ์๋์ง ํ์ธํ๋ค.
+ - [x] ์ ๊ฒฝ์ฐ๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ ๊ฒฝ์ฐ `InvalidOrdersException`์ ๋ฐ์์ํค๊ณ ,
+ "[ERROR] ์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋ธ๋ค.
์ดํ ๋ค์ `์ฃผ๋ฌธ ๋ด์ญ`์ ์
๋ ฅ์ ๋ฐ๋๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด `10000์` ์ดํ์ด๋ฉด, ํ ์ธ ์ด๋ฒคํธ ์ ์ฉ ๋์์์ ์ ์ธ์ํจ๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด `12๋ง์ ์ด์`์ผ ์, `์ดํ์ธ 1๊ฐ` ๋ฅผ ์ฆ์ ํ๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ์ด์ฉํด์ `ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก`์ ๊ณ์ฐํ ์ ์๋ค.
+
+> ### ๐ ์ฃผ๋ฌธ ๋ด์ญ์ ๋ํ ์ด๋ฒคํธ ์ ์ฉ ๊ฒฐ๊ณผ ์ฐ์ถ ๋๋ฉ์ธ ๋ก์ง
+
+- [x] ์ฃผ๋ฌธ ๋ด์ญ๊ณผ ๋ ์ง๋ฅผ ๋น๊ตํด์, `ํํ ๋ด์ญ`์ ์์ฐํ๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ๋ ์ง์ ๋ฐ๋ฅธ ํ ์ธ ์ฌ๋ถ๋ฅผ ์ ์ฉํด์, `ํ ์ธ ๊ธ์ก`์ ๊ณ์ฐํ๋ค.
+ - [x] ํํ ๋ด์ญ์ ๊ธ์ก์ ํฉ์ณ์, `์ด ํํ ๊ธ์ก`์ ๊ณ์ฐํ๋ค.
+ - [x] ์ฃผ๋ฌธ ๋ด์ญ์ ์ฆ์ ์ด๋ฒคํธ๊ฐ ํฌํจ๋์ด ์์ ์, ์ฆ์ ํ์ ๊ฐ๊ฒฉ๊น์ง `์ด ํํ ๊ธ์ก`์ ํฌํจ์ํจ๋ค.
+ - [x] ์ด ํํ ๊ธ์ก์ ๊ธฐ๋ฐ์ผ๋ก 12์ ์ด๋ฒคํธ ๋ฐฐ์ง๋ฅผ ๋ฐ๊ธํ๋ค.
+ - [x] ํํ ๊ธ์ก์ด `5000์` ์ด์์ผ ์, `๋ณ`
+
ํํ ๊ธ์ก์ด `1๋ง์` ์ด์์ผ ์, `ํธ๋ฆฌ`
+
ํํ ๊ธ์ก์ด `2๋ง์` ์ด์์ผ ์, `์ฐํ`
+ - [x] `ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก` ์์ `ํ ์ธ ๊ธ์ก`์ ๋นผ์ `ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก`์ ๊ณ์ฐํ๋ค.
+
+## ๐จ [ ์ถ๋ ฅ ๊ธฐ๋ฅ ]
+
+> ### ๐๏ธ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ์๋ฆผ ์ถ๋ ฅ
+
+- [x] ์
๋ ฅ๋ฐ์ ๋ ์ง์ ํด๋นํ๋ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์๋ฆผ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+
+> ### ๐โโ๏ธ ์ฃผ๋ฌธ ๋ฉ๋ด ์ถ๋ ฅ
+
+- [x] ์ฃผ๋ฌธ ๋ฉ๋ด๋ฅผ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] ์ฃผ๋ฌธ ๋ฉ๋ด๋ `${๋ฉ๋ด์ด๋ฆ} ${๋ฉ๋ด๊ฐ์} ๊ฐ` ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+- [x] ์ฃผ๋ฌธํ ๋ฉ๋ด ์ ์ฒด๋ฅผ ์์ ๊ฐ์ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+- [x] ์ถ๋ ฅ ์์๋ ์์ ๋กญ๊ฒ ํ๋ค.
+
+> ### ๐ฐ ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก ์ถ๋ ฅ
+
+- [x] ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก์ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] `ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก`์ ๋ํ๋ธ๋ค.
+ - [x] ๊ธ์ก์ ์ธ์๋ฆฌ ์๋ง๋ค `,`์ ๋ถ์ด๋ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+
+> ### ๐ ์ฆ์ ๋ฉ๋ด ์ถ๋ ฅ
+
+- [x] ์ฆ์ ๋ฉ๋ด๋ฅผ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] ์ฆ์ ๋ฉ๋ด๊ฐ ์๋ ๊ฒฝ์ฐ `${์ฆ์ ๋ฉ๋ด ์ด๋ฆ} ${์ฆ์ ๋ฉ๋ด ๊ฐ์}๊ฐ` ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+- [x] ์ฆ์ ๋ฉ๋ด๊ฐ ์๋ ๊ฒฝ์ฐ `์์`์ผ๋ก ์ถ๋ ฅํ๋ค.
+
+> ### ๐ ํํ ๋ด์ญ ์ถ๋ ฅ
+
+- [x] ํํ ๋ด์ญ์ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] ์ ์ฉ๋๋ ํ ์ธ ์ด๋ฒคํธ๋ณ ์ด๋ฆ ๋ฐ ํํ ๊ธ์ก์ ์ ๋ฆฌํด์ ๋ํ๋ธ๋ค.
+ - [x] `${์ ์ฉ ํํ ์ด๋ฒคํธ ์ด๋ฆ}: -${ํํ ๊ธ์ก}์` ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+ - [x] `ํํ ๊ธ์ก`์ ์ธ์๋ฆฌ ์๋ง๋ค `,`์ ๋ถ์ด๋ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+ - [x] ์ ์ฉ๋ ํํ์ด ์์ผ๋ฉด `์์`์ผ๋ก ์ถ๋ ฅํ๋ค.
+- [x] ์ฌ๋ฌ ๊ฐ์ ์ด๋ฒคํธ๊ฐ ์ ์ฉ๋์์ผ๋ฉด, ์ถ๋ ฅ ์์๋ ์์ ๋กญ๊ฒ ํ๋ค.
+
+> ### ๐ ์ด ํํ ๊ธ์ก ์ถ๋ ฅ
+
+- [x] ์ด ํํ ๊ธ์ก์ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] `์ด ํํ ๊ธ์ก`์ `ํํ ๋ด์ญ`์ ์ ์ฉ๋ ํํ ๊ธ์ก์ ๋ชจ๋ ๋ํ ๊ฐ์ ์ถ๋ ฅํ๋ค.
+ - [x] `-${ํํ ๊ธ์ก}์` ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+ - [x] `ํํ ๊ธ์ก`์ ์ธ์๋ฆฌ ์๋ง๋ค `,`๋ฅผ ๋ถ์ด๋ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+- [x] `์ด ํํ ๊ธ์ก`์ด 0์์ด๋ฉด `0์`์ผ๋ก ์ถ๋ ฅํ๋ค.
+
+> ### ๐ต ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก ์ถ๋ ฅ
+
+- [x] ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก์ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] `ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก`์ `ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก`์์ `์ด ํํ ๊ธ์ก`์ ๋บ ๊ฐ์ ์ถ๋ ฅํ๋ค.
+ - [x] `${ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก}์` ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+ - [x] `ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก`์ ์ธ์๋ฆฌ ์๋ง๋ค `,`๋ฅผ ๋ถ์ด๋ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+
+> ### โญ๐๐
12์ ์ด๋ฒคํธ ๋ฐฐ์ง ์ถ๋ ฅ
+
+- [x] 12์ ์ด๋ฒคํธ ๋ฐฐ์ง๋ฅผ ๋ํ๋ด๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+- [x] `๋ฐฐ์ง ์ด๋ฆ` ์ ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
+ - [x] `12์ ์ด๋ฒคํธ ๋ฐฐ์ง`๋ `์ด ํํ ๊ธ์ก`์ ๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ๊ฐ์ ๋ค๋ฅด๊ฒ ์ถ๋ ฅํ๋ค.
+ - [x] 5000์ ์ด์์ `๋ณ`, 10000์ ์ด์์ `ํธ๋ฆฌ`, 20000์ ์ด์์ `์ฐํ`๋ก ์ถ๋ ฅํ๋ค.
+- [x] ์ด๋ฒคํธ ๋ฐฐ์ง๊ฐ ๋ถ์ฌ๋์ง ์์ผ๋ฉด `์์`์ ์ถ๋ ฅํ๋ค.
+
+---
+
+## ๐ํจํค์ง ๊ตฌ์กฐ
+
+```bash
+christmas
+ โโโ Application.java
+ โโโ EventPlanner.java
+ โโโ controller
+ โย ย โโโ OrdersController.java
+ โย ย โโโ ReservationDayController.java
+ โโโ domain
+ โย ย โโโ DayPerMonth.java
+ โย ย โโโ EventManager.java
+ โย ย โโโ Order.java
+ โย ย โโโ Orders.java
+ โย ย โโโ ReservationDay.java
+ โย ย โโโ constant
+ โย ย โย ย โโโ event
+ โย ย โย ย โย ย โโโ ChristmasPromotion.java
+ โย ย โย ย โย ย โโโ EventBadge.java
+ โย ย โย ย โย ย โโโ EventNumberConstant.java
+ โย ย โย ย โย ย โโโ EventSymbolConstant.java
+ โย ย โย ย โย ย โโโ Promotion.java
+ โย ย โย ย โโโ orders
+ โย ย โย ย โย ย โโโ FoodType.java
+ โย ย โย ย โย ย โโโ Menu.java
+ โย ย โย ย โย ย โโโ OrdersConstant.java
+ โย ย โย ย โโโ reservationday
+ โย ย โย ย โโโ ReservationDayConstant.java
+ โย ย โโโ exception
+ โย ย โโโ InvalidOrdersException.java
+ โย ย โโโ InvalidReservationDayException.java
+ โย ย โโโ message
+ โย ย โโโ InvalidOrdersExceptionMessage.java
+ โย ย โโโ InvalidReservationDayExceptionMessage.java
+ โโโ dto
+ โย ย โโโ BenefitsDetailsDto.java
+ โย ย โโโ EstimatedAmountWithDiscountDto.java
+ โย ย โโโ EventBadgeDto.java
+ โย ย โโโ EventBenefitsPreviewDto.java
+ โย ย โโโ GiftDto.java
+ โย ย โโโ OrderedMenusDto.java
+ โย ย โโโ TotalAmountWithNoDiscountDto.java
+ โย ย โโโ TotalBenefitedAmountDto.java
+ โโโ global
+ โย ย โโโ ApplicationConstant.java
+ โโโ service
+ โย ย โโโ EventManagerService.java
+ โย ย โโโ OrdersService.java
+ โย ย โโโ ReservationDayService.java
+ โโโ view
+ โโโ input
+ โย ย โโโ InputView.java
+ โย ย โโโ constant
+ โย ย โย ย โโโ InputNumberConstant.java
+ โย ย โย ย โโโ InputSymbolConstant.java
+ โย ย โโโ exception
+ โย ย โย ย โโโ BasicInputException.java
+ โย ย โย ย โโโ DayInputException.java
+ โย ย โย ย โโโ OrdersInputException.java
+ โย ย โย ย โโโ message
+ โย ย โย ย โโโ BasicInputExceptionMessageFormat.java
+ โย ย โย ย โโโ DayInputExceptionMessage.java
+ โย ย โย ย โโโ OrdersInputExceptionMessage.java
+ โย ย โโโ parser
+ โย ย โย ย โโโ InputParser.java
+ โย ย โโโ validator
+ โย ย โโโ BasicValidator.java
+ โย ย โโโ DayInputValidator.java
+ โย ย โโโ MenuCountInputValidator.java
+ โย ย โโโ MenuNameInputValidator.java
+ โย ย โโโ OrderInputValidator.java
+ โย ย โโโ OrdersInputValidator.java
+ โย ย โโโ PositiveIntegerCheckable.java
+ โโโ output
+ โโโ OutputView.java
+ โโโ constant
+ โโโ OutputFormatConstant.java
+ โโโ OutputMessageConstant.java
+ โโโ OutputSymbolConstant.java
+```
+
+## ํ๋ก์ ํธ ์ํคํ
์ฒ
+
+
+
+## ์ถํ ํ์ฅ ๋ฐ ์ฝ๋ ์ฌ์ฌ์ฉ ์ ์ฐธ๊ณ ์ฌํญ
+
+- `global/ApplicationConstant` ํด๋์ค์
+ `CURRENT_PROMOTION_MONTH`๋ ์ด๋ฒคํธ๊ฐ ์ํ๋๋ ์(month)์ ์๋ฏธํฉ๋๋ค.
+
+- `ReservationDay` ํด๋์ค๋ 12์์ ๋ ์ง ๊ฐ๊ณผ 12์ ์ด๋ฒคํธ ๋๋ฉ์ธ ๋ก์ง์ ์ฒ๋ฆฌํ๋ ํด๋์ค์
๋๋ค.
+ ํด๋น ํด๋์ค๋ `DayPerMonth`๋ผ๋ ์ถ์ ํด๋์ค๋ฅผ ์์๋ฐ์ผ๋ฉฐ, ์ด ํด๋์ค๋ ์ ํจ ๋ ์ง ๊ฒ์ฆ ๋ก์ง์ ๊ฐ์ง๋๋ค.
+ ์๋ฅผ ๋ค์ด, ๋ค์ ๋ฌ 1์ ์ด๋ฒคํธ๋ฅผ ์ํด ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉ ํ์ ๋ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ ์์๋ก ์งํํ์๋ฉด ๋ฉ๋๋ค.
+ 1. `domain.constant.reservationday.ReservationDayConstant` ํด๋์ค์์,
+ `JANUARY_FIRST_DAY`, `JANUARY_LAST_DAY` ๊ฐ์ ์ถ๊ฐํฉ๋๋ค.
+ 2. `ReservationDay` ํด๋์ค์ `isInAppropriateRange`๋ฉ์๋์ DECEMBER ๊ด๋ จ ์์ ๊ฐ์ 1์์ ์์ฑํ ์์ ๊ฐ์ผ๋ก ๋์ฒดํด์ค๋๋ค.
+ 3. `ReservationDay` ํด๋์ค์ 12์ ๊ด๋ จ ๋๋ฉ์ธ ๋ก์ง์ ์ ๊ฑฐํ๊ณ ,
1์ ์ด๋ฒคํธ์ ๋ง๋ ๋๋ฉ์ธ ๋ก์ง์ผ๋ก ํด๋์ค๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
+ 4. `EventManager` ํด๋์ค๋ ์ด๋ฒคํธ ๊ด๋ จ ๋๋ฉ์ธ ๋ก์ง์
์์ฝ ๋ ์ง์ ์ฃผ๋ฌธ ๋ด์ญ์ ํตํด ํด๊ฒฐํ๋ ํด๋์ค์
๋๋ค.
+ 5. `ReservationDay`ํด๋์ค์ ๋๋ฉ์ธ ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ `EventManager`๋๋ฉ์ธ ๋ก์ง์ ์์ ํด์ฃผ์๋ฉด ๋ฉ๋๋ค.์ด ๋, `christmas.domain.constant.event` ํด๋์
+ ์ด๋ฒคํธ ๋ณ์ ๊ฐ์ ๋ณ๊ฒฝ ๋๋ ํ์ฉํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
+
+---
+
+### 1์ฃผ์ผ ๋ค ๊ฐ๋ฐ ํ์์์ ๋
ผ์ํ๋ฉด ์ข์ ์ฌํญ
+
+- ํ์ผ ํ ์ธ ๋ ์ ์์ด์คํฌ๋ฆผ๋ง ๋ง์ด ์์ผ๋จน๋ ์๋์ด ์ค๋ฉด ๋งค์ถ์ ๋ถ๋ฆฌํ ๊ฒ ๊ฐ์ต๋๋ค.
+ ์ด์ ๋ํ ๋์์ฑ
์ด ํ์ํ์ง ์์๊น์?
+- 30์ผ๊ณผ 31์ผ์ ์ฐ๋ง์ด๋ผ ์๋์ด ๋ง์ด ๋ชฐ๋ฆด ์๊ธฐ์ธ๋ฐ, ์ด๋ฅผ ์ ์ธํ ๋งํ ์ด๋ฒคํธ๊ฐ ๋ค์ ๋ถ์กฑํ ๊ฒ ๊ฐ์ต๋๋ค.
+ ์ฐ๋ง ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ์์ ์ด๋จ๊น์?
+- ์ฆ์ ์ด๋ฒคํธ๊ฐ ์ดํ์ธ๋ง ์ ๊ณตํด์ฃผ๋ ๊ฒ ๊ฐ์, ์์ด๋ค๊ณผ ํจ๊ป ์ค๋ ๋ถ๋ชจ๋๋ค์๊ฒ๋ ๊ทธ๋ค์ง ์ ์ธ์ฑ
์ด ๋์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค.
+
๊ณ ๊ฐ์ ์ ์ธํ๊ธฐ ์ํด ์ดํ์ธ์ ์ ๊ณตํ๋ ๊ฒ์ธ๋ฐ, ์คํ๋ ค ์์ด๋ค ์์์ ์์ฃผ ์ฅ๋ ค(?)๋ฅผ ํ๋ ๊ฒ ๊ฐ์ ์ ํฌ ์๋น์ ์ด์ฉํ์ง ์์ ์๋ ์์ ๊ฑฐ ๊ฐ์ต๋๋ค.์ฆ์ ํ์ ๋ค์ํํ๋ ๊ฒ์ ์ด๋ป๊ฒ ์๊ฐํ์๋์?
\ No newline at end of file
diff --git a/src/main/java/christmas/Application.java b/src/main/java/christmas/Application.java
index b9ba6a2..579e42e 100644
--- a/src/main/java/christmas/Application.java
+++ b/src/main/java/christmas/Application.java
@@ -1,7 +1,11 @@
package christmas;
+import christmas.view.input.InputView;
+import christmas.view.output.OutputView;
+
public class Application {
public static void main(String[] args) {
- // TODO: ํ๋ก๊ทธ๋จ ๊ตฌํ
+ EventPlanner eventPlanner = new EventPlanner(new InputView(), new OutputView());
+ eventPlanner.execute();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/EventPlanner.java b/src/main/java/christmas/EventPlanner.java
new file mode 100644
index 0000000..d5b1d48
--- /dev/null
+++ b/src/main/java/christmas/EventPlanner.java
@@ -0,0 +1,82 @@
+package christmas;
+
+import camp.nextstep.edu.missionutils.Console;
+import christmas.controller.OrdersController;
+import christmas.controller.ReservationDayController;
+import christmas.domain.EventManager;
+import christmas.domain.Orders;
+import christmas.domain.ReservationDay;
+import christmas.service.EventManagerService;
+import christmas.view.input.InputView;
+import christmas.view.output.OutputView;
+
+public class EventPlanner {
+ private final OutputView outputView;
+ private final ReservationDayController reservationDayController;
+ private final OrdersController ordersController;
+ private final EventManagerService eventManagerService;
+
+ public EventPlanner(InputView inputView, OutputView outputView) {
+ this.outputView = outputView;
+ reservationDayController = new ReservationDayController(inputView, outputView);
+ ordersController = new OrdersController(inputView, outputView);
+ eventManagerService = new EventManagerService();
+ outputView.printGreetingMessage();
+ }
+
+ public void execute() {
+ ReservationDay reservationDay = reservationDayController.insertReservationDay();
+ Orders orders = ordersController.insertOrders();
+ EventManager eventManager = EventManager.of(reservationDay, orders);
+ printResult(reservationDay, orders, eventManager);
+ terminatePlanner();
+ }
+
+ private void printResult(ReservationDay reservationDay, Orders orders, EventManager eventManager) {
+ printIntroMessage(reservationDay);
+ printOrderedMenus(orders);
+ printTotalAmountWithNoDiscount(orders);
+ printGiftMenu(orders);
+ printBenefitsDetails(eventManager);
+ printTotalBenefitedAmount(eventManager);
+ printEstimatedAmountWithDiscount(eventManager);
+ printEventBadge(eventManager);
+ }
+
+ private void printIntroMessage(ReservationDay reservationDay) {
+ outputView.printIntroMessage(reservationDayController.createEventBenefitsPreviousDto(reservationDay));
+ }
+
+ private void printOrderedMenus(Orders orders) {
+ outputView.printOrderedMenus(ordersController.createOrderedMenusDto(orders));
+ }
+
+ private void printTotalAmountWithNoDiscount(Orders orders) {
+ outputView.printTotalAmountWithNoDiscount(ordersController.createTotalAmountWithNoDiscountDto(orders));
+ }
+
+ private void printGiftMenu(Orders orders) {
+ outputView.printGiftMenu(eventManagerService.createGiftDto(orders));
+ }
+
+ private void printBenefitsDetails(EventManager eventManager) {
+ outputView.printBenefitsDetails(eventManagerService.createBenefitsDetailsDto(eventManager));
+ }
+
+ private void printTotalBenefitedAmount(EventManager eventManager) {
+ outputView.printTotalBenefitedAmount(eventManagerService.createTotalBenefitedAmountDto(eventManager));
+ }
+
+ private void printEstimatedAmountWithDiscount(EventManager eventManager) {
+ outputView.printEstimatedAmountWithDiscount(
+ eventManagerService.createEstimatedAmountWithDiscountDto(eventManager));
+ }
+
+ private void printEventBadge(EventManager eventManager) {
+ outputView.printEventBadge(eventManagerService.createEventBadgeDto(eventManager));
+ }
+
+ private void terminatePlanner() {
+ Console.close();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/controller/OrdersController.java b/src/main/java/christmas/controller/OrdersController.java
new file mode 100644
index 0000000..fa8a313
--- /dev/null
+++ b/src/main/java/christmas/controller/OrdersController.java
@@ -0,0 +1,47 @@
+package christmas.controller;
+
+import christmas.domain.Orders;
+import christmas.domain.exception.InvalidOrdersException;
+import christmas.dto.OrderedMenusDto;
+import christmas.dto.TotalAmountWithNoDiscountDto;
+import christmas.service.OrdersService;
+import christmas.view.input.InputView;
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.output.OutputView;
+import java.util.Map;
+
+public class OrdersController {
+ private final InputView inputView;
+ private final OutputView outputView;
+ private final OrdersService ordersService;
+
+ public OrdersController(InputView inputView, OutputView outputView) {
+ this.inputView = inputView;
+ this.outputView = outputView;
+ ordersService = new OrdersService();
+ }
+
+ public Orders insertOrders() {
+ try {
+ Map orders = askToInsertOrders();
+ return ordersService.createOrders(orders);
+ } catch (BasicInputException | OrdersInputException | InvalidOrdersException e) {
+ outputView.printErrorMessage(e.getMessage());
+ return insertOrders();
+ }
+ }
+
+ private Map askToInsertOrders() throws BasicInputException, OrdersInputException {
+ outputView.askToInsertOrders();
+ return inputView.getOrders();
+ }
+
+ public OrderedMenusDto createOrderedMenusDto(Orders orders) {
+ return ordersService.createOrdersHistoryDto(orders);
+ }
+
+ public TotalAmountWithNoDiscountDto createTotalAmountWithNoDiscountDto(Orders orders) {
+ return ordersService.createTotalAmountWithNoDiscountDto(orders);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/controller/ReservationDayController.java b/src/main/java/christmas/controller/ReservationDayController.java
new file mode 100644
index 0000000..f10378c
--- /dev/null
+++ b/src/main/java/christmas/controller/ReservationDayController.java
@@ -0,0 +1,41 @@
+package christmas.controller;
+
+import christmas.domain.ReservationDay;
+import christmas.domain.exception.InvalidReservationDayException;
+import christmas.dto.EventBenefitsPreviewDto;
+import christmas.service.ReservationDayService;
+import christmas.view.input.InputView;
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.DayInputException;
+import christmas.view.output.OutputView;
+
+public class ReservationDayController {
+ private final InputView inputView;
+ private final OutputView outputView;
+ private final ReservationDayService reservationDayService;
+
+ public ReservationDayController(InputView inputView, OutputView outputView) {
+ this.inputView = inputView;
+ this.outputView = outputView;
+ reservationDayService = new ReservationDayService();
+ }
+
+ public ReservationDay insertReservationDay() {
+ try {
+ int reservationDay = askToInsertReservationDay();
+ return reservationDayService.createReservationDay(reservationDay);
+ } catch (BasicInputException | DayInputException | InvalidReservationDayException e) {
+ outputView.printErrorMessage(e.getMessage());
+ return insertReservationDay();
+ }
+ }
+
+ private int askToInsertReservationDay() throws BasicInputException, DayInputException {
+ outputView.askToInsertReservationDay();
+ return inputView.getReservationDay();
+ }
+
+ public EventBenefitsPreviewDto createEventBenefitsPreviousDto(ReservationDay reservationDay) {
+ return reservationDayService.createEventBenefitsPreviewDto(reservationDay);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/DayPerMonth.java b/src/main/java/christmas/domain/DayPerMonth.java
new file mode 100644
index 0000000..28e4d7a
--- /dev/null
+++ b/src/main/java/christmas/domain/DayPerMonth.java
@@ -0,0 +1,22 @@
+package christmas.domain;
+
+import static christmas.domain.constant.reservationday.ReservationDayConstant.DECEMBER_LAST_DAY;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.DEFAULT_FIRST_DAY;
+import static christmas.domain.exception.message.InvalidReservationDayExceptionMessage.NOT_IN_APPROPRIATE_RANGE;
+
+import christmas.domain.exception.InvalidReservationDayException;
+
+public abstract class DayPerMonth {
+ public DayPerMonth() {
+ }
+
+ protected void validate(final int day) {
+ if (!isInAppropriateRange(day)) {
+ throw InvalidReservationDayException.of(NOT_IN_APPROPRIATE_RANGE.getMessage());
+ }
+ }
+
+ protected boolean isInAppropriateRange(final int day) {
+ return day >= DEFAULT_FIRST_DAY.getValue() && day <= DECEMBER_LAST_DAY.getValue();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/EventManager.java b/src/main/java/christmas/domain/EventManager.java
new file mode 100644
index 0000000..faccf98
--- /dev/null
+++ b/src/main/java/christmas/domain/EventManager.java
@@ -0,0 +1,138 @@
+package christmas.domain;
+
+import static christmas.domain.constant.event.ChristmasPromotion.CHRISTMAS_D_DAY_PROMOTION;
+import static christmas.domain.constant.event.EventNumberConstant.NONE_PROMOTION_APPLIED_AMOUNT;
+import static christmas.domain.constant.event.Promotion.GIFT_PROMOTION;
+import static christmas.domain.constant.event.Promotion.SPECIAL_PROMOTION;
+import static christmas.domain.constant.event.Promotion.WEEKDAY_PROMOTION;
+import static christmas.domain.constant.event.Promotion.WEEKEND_PROMOTION;
+
+import christmas.domain.constant.event.EventBadge;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class EventManager {
+ private final ReservationDay reservationDay;
+ private final Orders orders;
+
+ private EventManager(ReservationDay reservationDay, Orders orders) {
+ this.reservationDay = reservationDay;
+ this.orders = orders;
+ }
+
+ public static EventManager of(ReservationDay reservationDay, Orders orders) {
+ return new EventManager(reservationDay, orders);
+ }
+
+ public Map createBenefitsDetails() {
+ Map benefitsDetails = new LinkedHashMap<>();
+ if (orders.isEventApplicable()) {
+ return makeBenefitsDetails(benefitsDetails);
+ }
+ return Collections.unmodifiableMap(benefitsDetails);
+ }
+
+ private Map makeBenefitsDetails(Map benefitsDetails) {
+ addChristmasPromotionDetails(benefitsDetails);
+ addWeekdayPromotionDetails(benefitsDetails);
+ addWeekendPromotionDetails(benefitsDetails);
+ addSpecialPromotionDetails(benefitsDetails);
+ addGiftPromotionDetails(benefitsDetails);
+ return Collections.unmodifiableMap(benefitsDetails);
+ }
+
+ private void addChristmasPromotionDetails(Map benefitsDetails) {
+ if (reservationDay.isChristmasPromotionApplicable()) {
+ benefitsDetails.put(CHRISTMAS_D_DAY_PROMOTION.getName(),
+ calculateChristmasPromotionBenefitAmount());
+ }
+ }
+
+ private int calculateChristmasPromotionBenefitAmount() {
+ return CHRISTMAS_D_DAY_PROMOTION.getBenefitAmount(reservationDay.getDay());
+ }
+
+ private void addWeekdayPromotionDetails(Map benefitsDetails) {
+ if (canAddWeekdayPromotion()) {
+ benefitsDetails.put(WEEKDAY_PROMOTION.getName(),
+ calculateWeekdayPromotionBenefitAmount());
+ }
+ }
+
+ private boolean canAddWeekdayPromotion() {
+ return reservationDay.isWeekdayPromotionApplicable()
+ && calculateWeekdayPromotionBenefitAmount()
+ > NONE_PROMOTION_APPLIED_AMOUNT.getValue();
+ }
+
+ private int calculateWeekdayPromotionBenefitAmount() {
+ int count = orders.getOrders().stream()
+ .filter(Order::isWeekdayPromotionApplicable)
+ .mapToInt(Order::getMenuCount)
+ .sum();
+ return WEEKDAY_PROMOTION.getBenefitAmount() * count;
+ }
+
+ private void addWeekendPromotionDetails(Map benefitsDetails) {
+ if (canAddWeekendPromotion()) {
+ benefitsDetails.put(WEEKEND_PROMOTION.getName(),
+ calculateWeekendPromotionBenefitAmount());
+ }
+ }
+
+ private boolean canAddWeekendPromotion() {
+ return reservationDay.isWeekendPromotionApplicable()
+ && calculateWeekendPromotionBenefitAmount()
+ > NONE_PROMOTION_APPLIED_AMOUNT.getValue();
+ }
+
+ private int calculateWeekendPromotionBenefitAmount() {
+ int count = orders.getOrders().stream()
+ .filter(Order::isWeekendPromotionApplicable)
+ .mapToInt(Order::getMenuCount)
+ .sum();
+ return WEEKEND_PROMOTION.getBenefitAmount() * count;
+ }
+
+ private void addSpecialPromotionDetails(Map benefitsDetails) {
+ if (reservationDay.isSpecialPromotionApplicable()) {
+ benefitsDetails.put(SPECIAL_PROMOTION.getName(), calculateSpecialPromotionBenefitAmount());
+ }
+ }
+
+ private int calculateSpecialPromotionBenefitAmount() {
+ return SPECIAL_PROMOTION.getBenefitAmount();
+ }
+
+ private void addGiftPromotionDetails(Map benefitsDetails) {
+ if (orders.isGiftEventApplicable()) {
+ benefitsDetails.put(GIFT_PROMOTION.getName(), calculateGiftPromotionBenefitAmount());
+ }
+ }
+
+ private int calculateGiftPromotionBenefitAmount() {
+ return GIFT_PROMOTION.getBenefitAmount();
+ }
+
+ public int calculateTotalBenefitedAmount() {
+ return createBenefitsDetails().values().stream()
+ .mapToInt(Integer::intValue)
+ .sum();
+ }
+
+ public int calculateEstimatedOrdersAmountWithDiscount() {
+ return orders.calculateTotalAmountWithNoDiscount() - calculateTotalDiscountedAmount();
+ }
+
+ private int calculateTotalDiscountedAmount() {
+ if (orders.isGiftEventApplicable()) {
+ return calculateTotalBenefitedAmount() - calculateGiftPromotionBenefitAmount();
+ }
+ return calculateTotalBenefitedAmount();
+ }
+
+ public String issueEventBadge() {
+ return EventBadge.getBadgeNameByBenefitedPrice(calculateTotalBenefitedAmount());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/Order.java b/src/main/java/christmas/domain/Order.java
new file mode 100644
index 0000000..0d1b0b5
--- /dev/null
+++ b/src/main/java/christmas/domain/Order.java
@@ -0,0 +1,43 @@
+package christmas.domain;
+
+import christmas.domain.constant.orders.FoodType;
+import christmas.domain.constant.orders.Menu;
+import christmas.domain.exception.InvalidOrdersException;
+
+public class Order {
+ private final Menu menu;
+ private final int count;
+
+ private Order(Menu menu, final int count) {
+ this.menu = menu;
+ this.count = count;
+ }
+
+ public static Order of(final String menuName, final int count) throws InvalidOrdersException {
+ return new Order(Menu.searchByName(menuName), count);
+ }
+
+ public String getMenuName() {
+ return menu.getName();
+ }
+
+ public int getMenuCount() {
+ return count;
+ }
+
+ public FoodType getFoodType() {
+ return menu.getFoodType();
+ }
+
+ public boolean isWeekdayPromotionApplicable() {
+ return menu.isWeekDayPromotionApplicable();
+ }
+
+ public boolean isWeekendPromotionApplicable() {
+ return menu.isWeekendPromotionApplicable();
+ }
+
+ public int getTotalPrice() {
+ return menu.getPrice() * count;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/Orders.java b/src/main/java/christmas/domain/Orders.java
new file mode 100644
index 0000000..5aa333e
--- /dev/null
+++ b/src/main/java/christmas/domain/Orders.java
@@ -0,0 +1,71 @@
+package christmas.domain;
+
+import static christmas.domain.constant.event.EventNumberConstant.EVENT_APPLICABLE_AMOUNT;
+import static christmas.domain.constant.event.EventNumberConstant.GIFT_EVENT_APPLICABLE_AMOUNT;
+import static christmas.domain.constant.orders.OrdersConstant.MAX_MENU_COUNTS;
+import static christmas.domain.exception.message.InvalidOrdersExceptionMessage.EXCEED_MENU_COUNTS_UPPER_LIMIT;
+import static christmas.domain.exception.message.InvalidOrdersExceptionMessage.MENUS_ONLY_CONTAIN_BEVERAGE;
+
+import christmas.domain.constant.orders.FoodType;
+import christmas.domain.exception.InvalidOrdersException;
+import java.util.Collections;
+import java.util.List;
+
+public class Orders {
+ private final List orders;
+
+ private Orders(List orders) {
+ this.orders = orders;
+ }
+
+ public static Orders from(List orders) {
+ validate(orders);
+ return new Orders(orders);
+ }
+
+ private static void validate(List orders) {
+ validateSumOfMenuCountsNotExceedUpperLimit(orders);
+ validateOrderedMenusNotOnlyContainBeverage(orders);
+ }
+
+ private static void validateSumOfMenuCountsNotExceedUpperLimit(List orders) {
+ if (sumOfMenuCountsExceedUpperLimit(orders)) {
+ throw InvalidOrdersException.of(EXCEED_MENU_COUNTS_UPPER_LIMIT.getMessage());
+ }
+ }
+
+ private static boolean sumOfMenuCountsExceedUpperLimit(List orders) {
+ return orders.stream()
+ .mapToInt(Order::getMenuCount)
+ .sum() > MAX_MENU_COUNTS.getValue();
+ }
+
+ private static void validateOrderedMenusNotOnlyContainBeverage(List orders) {
+ if (orderedMenusOnlyContainBeverage(orders)) {
+ throw InvalidOrdersException.of(MENUS_ONLY_CONTAIN_BEVERAGE.getMessage());
+ }
+ }
+
+ private static boolean orderedMenusOnlyContainBeverage(List orders) {
+ return orders.stream()
+ .allMatch(order -> order.getFoodType() == FoodType.BEVERAGE);
+ }
+
+ public int calculateTotalAmountWithNoDiscount() {
+ return orders.stream()
+ .mapToInt(Order::getTotalPrice)
+ .sum();
+ }
+
+ public boolean isEventApplicable() {
+ return calculateTotalAmountWithNoDiscount() >= EVENT_APPLICABLE_AMOUNT.getValue();
+ }
+
+ public boolean isGiftEventApplicable() {
+ return calculateTotalAmountWithNoDiscount() >= GIFT_EVENT_APPLICABLE_AMOUNT.getValue();
+ }
+
+ public List getOrders() {
+ return Collections.unmodifiableList(orders);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/ReservationDay.java b/src/main/java/christmas/domain/ReservationDay.java
new file mode 100644
index 0000000..1888dc0
--- /dev/null
+++ b/src/main/java/christmas/domain/ReservationDay.java
@@ -0,0 +1,54 @@
+package christmas.domain;
+
+import static christmas.domain.constant.reservationday.ReservationDayConstant.DECEMBER_CHRISTMAS_DAY;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.DECEMBER_FIRST_DAY;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.DECEMBER_LAST_DAY;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.FRIDAY_VALUE;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.SATURDAY_VALUE;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.SUNDAY_VALUE;
+import static christmas.domain.constant.reservationday.ReservationDayConstant.WEEKDAY_LENGTH;
+
+import christmas.domain.exception.InvalidReservationDayException;
+
+public class ReservationDay extends DayPerMonth {
+ private final int day;
+
+ private ReservationDay(final int day) throws InvalidReservationDayException {
+ validate(day);
+ this.day = day;
+ }
+
+ public static ReservationDay from(final int day) throws InvalidReservationDayException {
+ return new ReservationDay(day);
+ }
+
+ public boolean isChristmasPromotionApplicable() {
+ return day >= DECEMBER_FIRST_DAY.getValue() && day <= DECEMBER_CHRISTMAS_DAY.getValue();
+ }
+
+ public boolean isWeekdayPromotionApplicable() {
+ return !isWeekend();
+ }
+
+ public boolean isWeekendPromotionApplicable() {
+ return isWeekend();
+ }
+
+ private boolean isWeekend() {
+ return day % WEEKDAY_LENGTH.getValue() == FRIDAY_VALUE.getValue()
+ || day % WEEKDAY_LENGTH.getValue() == SATURDAY_VALUE.getValue();
+ }
+
+ public boolean isSpecialPromotionApplicable() {
+ return day % WEEKDAY_LENGTH.getValue() == SUNDAY_VALUE.getValue() || day == DECEMBER_CHRISTMAS_DAY.getValue();
+ }
+
+ public int getDay() {
+ return day;
+ }
+
+ @Override
+ protected boolean isInAppropriateRange(final int day) {
+ return day >= DECEMBER_FIRST_DAY.getValue() && day <= DECEMBER_LAST_DAY.getValue();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/event/ChristmasPromotion.java b/src/main/java/christmas/domain/constant/event/ChristmasPromotion.java
new file mode 100644
index 0000000..3e50d44
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/event/ChristmasPromotion.java
@@ -0,0 +1,23 @@
+package christmas.domain.constant.event;
+
+import static christmas.domain.constant.event.EventNumberConstant.CHRISTMAS_PROMOTION_INCREASING_AMOUNT;
+
+public enum ChristmasPromotion {
+ CHRISTMAS_D_DAY_PROMOTION("ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ", 900);
+
+ private final String name;
+ private final int startBenefitAmount;
+
+ ChristmasPromotion(final String name, final int startBenefitAmount) {
+ this.name = name;
+ this.startBenefitAmount = startBenefitAmount;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getBenefitAmount(final int day) {
+ return startBenefitAmount + day * CHRISTMAS_PROMOTION_INCREASING_AMOUNT.getValue();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/event/EventBadge.java b/src/main/java/christmas/domain/constant/event/EventBadge.java
new file mode 100644
index 0000000..bac6c4c
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/event/EventBadge.java
@@ -0,0 +1,44 @@
+package christmas.domain.constant.event;
+
+import static christmas.domain.constant.event.EventSymbolConstant.NO_BADGE_SYMBOL;
+
+public enum EventBadge {
+ STAR("๋ณ", 5_000),
+ TREE("ํธ๋ฆฌ", 10_000),
+ SANTA("์ฐํ", 20_000);
+
+ private final String name;
+ private final int minimumTotalBenefitedPrice;
+
+ EventBadge(final String name, final int minimumTotalBenefitedPrice) {
+ this.name = name;
+ this.minimumTotalBenefitedPrice = minimumTotalBenefitedPrice;
+ }
+
+ public static String getBadgeNameByBenefitedPrice(final int totalBenefitedPrice) {
+ if (isStar(totalBenefitedPrice)) {
+ return STAR.name;
+ }
+ if (isTree(totalBenefitedPrice)) {
+ return TREE.name;
+ }
+ if (isSanta(totalBenefitedPrice)) {
+ return SANTA.name;
+ }
+ return NO_BADGE_SYMBOL.getSymbol();
+ }
+
+ private static boolean isStar(final int totalBenefitedPrice) {
+ return totalBenefitedPrice >= STAR.minimumTotalBenefitedPrice
+ && totalBenefitedPrice < TREE.minimumTotalBenefitedPrice;
+ }
+
+ private static boolean isTree(final int totalBenefitedPrice) {
+ return totalBenefitedPrice >= TREE.minimumTotalBenefitedPrice
+ && totalBenefitedPrice < SANTA.minimumTotalBenefitedPrice;
+ }
+
+ private static boolean isSanta(final int totalBenefitedPrice) {
+ return totalBenefitedPrice >= SANTA.minimumTotalBenefitedPrice;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/event/EventNumberConstant.java b/src/main/java/christmas/domain/constant/event/EventNumberConstant.java
new file mode 100644
index 0000000..12cecd3
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/event/EventNumberConstant.java
@@ -0,0 +1,19 @@
+package christmas.domain.constant.event;
+
+public enum EventNumberConstant {
+ EVENT_APPLICABLE_AMOUNT(10_000),
+ GIFT_EVENT_APPLICABLE_AMOUNT(120_000),
+ GIFT_CHAMPAGNE_COUNT(1),
+ CHRISTMAS_PROMOTION_INCREASING_AMOUNT(100),
+ NONE_PROMOTION_APPLIED_AMOUNT(0);
+
+ private final int value;
+
+ EventNumberConstant(final int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/event/EventSymbolConstant.java b/src/main/java/christmas/domain/constant/event/EventSymbolConstant.java
new file mode 100644
index 0000000..e7fc013
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/event/EventSymbolConstant.java
@@ -0,0 +1,14 @@
+package christmas.domain.constant.event;
+
+public enum EventSymbolConstant {
+ NO_BADGE_SYMBOL("");
+ private final String symbol;
+
+ EventSymbolConstant(final String symbol) {
+ this.symbol = symbol;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/event/Promotion.java b/src/main/java/christmas/domain/constant/event/Promotion.java
new file mode 100644
index 0000000..898c630
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/event/Promotion.java
@@ -0,0 +1,24 @@
+package christmas.domain.constant.event;
+
+public enum Promotion {
+ WEEKDAY_PROMOTION("ํ์ผ ํ ์ธ", 2_023),
+ WEEKEND_PROMOTION("์ฃผ๋ง ํ ์ธ", 2_023),
+ SPECIAL_PROMOTION("ํน๋ณ ํ ์ธ", 1_000),
+ GIFT_PROMOTION("์ฆ์ ์ด๋ฒคํธ", 25_000);
+
+ private final String name;
+ private final int benefitAmount;
+
+ Promotion(final String name, final int benefitAmount) {
+ this.name = name;
+ this.benefitAmount = benefitAmount;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getBenefitAmount() {
+ return benefitAmount;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/orders/FoodType.java b/src/main/java/christmas/domain/constant/orders/FoodType.java
new file mode 100644
index 0000000..4679658
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/orders/FoodType.java
@@ -0,0 +1,25 @@
+package christmas.domain.constant.orders;
+
+public enum FoodType {
+
+ APPETIZER(false, false),
+ MAIN(false, true),
+ DESSERT(true, false),
+ BEVERAGE(false, false);
+
+ private final boolean isWeekdayPromotionApplicable;
+ private final boolean isWeekendPromotionApplicable;
+
+ FoodType(final boolean isWeekdayPromotionApplicable, final boolean isWeekendPromotionApplicable) {
+ this.isWeekdayPromotionApplicable = isWeekdayPromotionApplicable;
+ this.isWeekendPromotionApplicable = isWeekendPromotionApplicable;
+ }
+
+ public boolean isWeekdayPromotionApplicable() {
+ return isWeekdayPromotionApplicable;
+ }
+
+ public boolean isWeekendPromotionApplicable() {
+ return isWeekendPromotionApplicable;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/orders/Menu.java b/src/main/java/christmas/domain/constant/orders/Menu.java
new file mode 100644
index 0000000..223997c
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/orders/Menu.java
@@ -0,0 +1,65 @@
+package christmas.domain.constant.orders;
+
+import static christmas.domain.constant.orders.FoodType.APPETIZER;
+import static christmas.domain.constant.orders.FoodType.BEVERAGE;
+import static christmas.domain.constant.orders.FoodType.DESSERT;
+import static christmas.domain.constant.orders.FoodType.MAIN;
+import static christmas.domain.exception.message.InvalidOrdersExceptionMessage.NOT_EXISTING_MENU;
+
+import christmas.domain.exception.InvalidOrdersException;
+import java.util.Arrays;
+
+public enum Menu {
+ MUSHROOM_SOUP("์์ก์ด์ํ", 6_000, APPETIZER),
+ TAPAS("ํํ์ค", 5_500, APPETIZER),
+ CAESAR_SALAD("์์ ์๋ฌ๋", 8_000, APPETIZER),
+
+ T_BONE_STAKE("ํฐ๋ณธ์คํ
์ดํฌ", 55_000, MAIN),
+ BARBECUE_RIB("๋ฐ๋นํ๋ฆฝ", 54_000, MAIN),
+ SEAFOOD_PASTA("ํด์ฐ๋ฌผํ์คํ", 35_000, MAIN),
+ CHRISTMAS_PASTA("ํฌ๋ฆฌ์ค๋ง์คํ์คํ", 25_000, MAIN),
+
+ CHOCOLATE_CAKE("์ด์ฝ์ผ์ดํฌ", 15_000, DESSERT),
+ ICE_CREAM("์์ด์คํฌ๋ฆผ", 5_000, DESSERT),
+
+ ZERO_COKE("์ ๋ก์ฝ๋ผ", 3_000, BEVERAGE),
+ RED_WINE("๋ ๋์์ธ", 60_000, BEVERAGE),
+ CHAMPAGNE("์ดํ์ธ", 25_000, BEVERAGE);
+
+ private final String name;
+ private final int price;
+ private final FoodType foodType;
+
+ Menu(final String name, final int price, final FoodType foodType) {
+ this.name = name;
+ this.price = price;
+ this.foodType = foodType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getPrice() {
+ return price;
+ }
+
+ public FoodType getFoodType() {
+ return foodType;
+ }
+
+ public boolean isWeekDayPromotionApplicable() {
+ return foodType.isWeekdayPromotionApplicable();
+ }
+
+ public boolean isWeekendPromotionApplicable() {
+ return foodType.isWeekendPromotionApplicable();
+ }
+
+ public static Menu searchByName(final String name) {
+ return Arrays.stream(Menu.values())
+ .filter(menu -> menu.name.equalsIgnoreCase(name))
+ .findFirst()
+ .orElseThrow(() -> InvalidOrdersException.of(NOT_EXISTING_MENU.getMessage()));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/orders/OrdersConstant.java b/src/main/java/christmas/domain/constant/orders/OrdersConstant.java
new file mode 100644
index 0000000..df44a44
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/orders/OrdersConstant.java
@@ -0,0 +1,15 @@
+package christmas.domain.constant.orders;
+
+public enum OrdersConstant {
+ MAX_MENU_COUNTS(20);
+
+ private final int value;
+
+ OrdersConstant(final int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/constant/reservationday/ReservationDayConstant.java b/src/main/java/christmas/domain/constant/reservationday/ReservationDayConstant.java
new file mode 100644
index 0000000..66e9fbc
--- /dev/null
+++ b/src/main/java/christmas/domain/constant/reservationday/ReservationDayConstant.java
@@ -0,0 +1,23 @@
+package christmas.domain.constant.reservationday;
+
+public enum ReservationDayConstant {
+ DEFAULT_FIRST_DAY(1),
+ DEFAULT_LAST_DAY(30),
+ DECEMBER_FIRST_DAY(1),
+ DECEMBER_LAST_DAY(31),
+ DECEMBER_CHRISTMAS_DAY(25),
+ WEEKDAY_LENGTH(7),
+ FRIDAY_VALUE(1),
+ SATURDAY_VALUE(2),
+ SUNDAY_VALUE(3);
+
+ private final int value;
+
+ ReservationDayConstant(final int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/exception/InvalidOrdersException.java b/src/main/java/christmas/domain/exception/InvalidOrdersException.java
new file mode 100644
index 0000000..e0e25ae
--- /dev/null
+++ b/src/main/java/christmas/domain/exception/InvalidOrdersException.java
@@ -0,0 +1,11 @@
+package christmas.domain.exception;
+
+public class InvalidOrdersException extends IllegalArgumentException {
+ private InvalidOrdersException(final String invalidMenuExceptionMessage) {
+ super(invalidMenuExceptionMessage);
+ }
+
+ public static InvalidOrdersException of(final String invalidMenuExceptionMessage) {
+ return new InvalidOrdersException(invalidMenuExceptionMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/exception/InvalidReservationDayException.java b/src/main/java/christmas/domain/exception/InvalidReservationDayException.java
new file mode 100644
index 0000000..e4ff894
--- /dev/null
+++ b/src/main/java/christmas/domain/exception/InvalidReservationDayException.java
@@ -0,0 +1,11 @@
+package christmas.domain.exception;
+
+public class InvalidReservationDayException extends IllegalArgumentException {
+ private InvalidReservationDayException(final String invalidDayExceptionMessage) {
+ super(invalidDayExceptionMessage);
+ }
+
+ public static InvalidReservationDayException of(final String invalidDayExceptionMessage) {
+ return new InvalidReservationDayException(invalidDayExceptionMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/exception/message/InvalidOrdersExceptionMessage.java b/src/main/java/christmas/domain/exception/message/InvalidOrdersExceptionMessage.java
new file mode 100644
index 0000000..b479cb4
--- /dev/null
+++ b/src/main/java/christmas/domain/exception/message/InvalidOrdersExceptionMessage.java
@@ -0,0 +1,19 @@
+package christmas.domain.exception.message;
+
+import static christmas.global.ApplicationConstant.ERROR_PREFIX;
+
+public enum InvalidOrdersExceptionMessage {
+ NOT_EXISTING_MENU("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ EXCEED_MENU_COUNTS_UPPER_LIMIT("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ MENUS_ONLY_CONTAIN_BEVERAGE("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.");
+
+ private final String message;
+
+ InvalidOrdersExceptionMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return ERROR_PREFIX + message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/domain/exception/message/InvalidReservationDayExceptionMessage.java b/src/main/java/christmas/domain/exception/message/InvalidReservationDayExceptionMessage.java
new file mode 100644
index 0000000..23b0f05
--- /dev/null
+++ b/src/main/java/christmas/domain/exception/message/InvalidReservationDayExceptionMessage.java
@@ -0,0 +1,17 @@
+package christmas.domain.exception.message;
+
+import static christmas.global.ApplicationConstant.ERROR_PREFIX;
+
+public enum InvalidReservationDayExceptionMessage {
+ NOT_IN_APPROPRIATE_RANGE("์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.");
+
+ private final String message;
+
+ InvalidReservationDayExceptionMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return ERROR_PREFIX + message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/BenefitsDetailsDto.java b/src/main/java/christmas/dto/BenefitsDetailsDto.java
new file mode 100644
index 0000000..44d606f
--- /dev/null
+++ b/src/main/java/christmas/dto/BenefitsDetailsDto.java
@@ -0,0 +1,24 @@
+package christmas.dto;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class BenefitsDetailsDto {
+ private final Map benefitsDetails;
+
+ private BenefitsDetailsDto(Map benefitsDetails) {
+ this.benefitsDetails = benefitsDetails;
+ }
+
+ public static BenefitsDetailsDto from(Map benefitsDetails) {
+ return new BenefitsDetailsDto(benefitsDetails);
+ }
+
+ public Map getBenefitsDetails() {
+ return Collections.unmodifiableMap(benefitsDetails);
+ }
+
+ public boolean isEmpty() {
+ return benefitsDetails.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/EstimatedAmountWithDiscountDto.java b/src/main/java/christmas/dto/EstimatedAmountWithDiscountDto.java
new file mode 100644
index 0000000..6e459e7
--- /dev/null
+++ b/src/main/java/christmas/dto/EstimatedAmountWithDiscountDto.java
@@ -0,0 +1,17 @@
+package christmas.dto;
+
+public class EstimatedAmountWithDiscountDto {
+ private final int amount;
+
+ public EstimatedAmountWithDiscountDto(final int amount) {
+ this.amount = amount;
+ }
+
+ public static EstimatedAmountWithDiscountDto from(final int amount) {
+ return new EstimatedAmountWithDiscountDto(amount);
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/EventBadgeDto.java b/src/main/java/christmas/dto/EventBadgeDto.java
new file mode 100644
index 0000000..038140b
--- /dev/null
+++ b/src/main/java/christmas/dto/EventBadgeDto.java
@@ -0,0 +1,21 @@
+package christmas.dto;
+
+public class EventBadgeDto {
+ private final String badgeName;
+
+ public EventBadgeDto(final String badgeName) {
+ this.badgeName = badgeName;
+ }
+
+ public static EventBadgeDto from(final String badgeName) {
+ return new EventBadgeDto(badgeName);
+ }
+
+ public String getBadgeName() {
+ return badgeName;
+ }
+
+ public boolean isEmpty() {
+ return badgeName.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/EventBenefitsPreviewDto.java b/src/main/java/christmas/dto/EventBenefitsPreviewDto.java
new file mode 100644
index 0000000..9fc1315
--- /dev/null
+++ b/src/main/java/christmas/dto/EventBenefitsPreviewDto.java
@@ -0,0 +1,17 @@
+package christmas.dto;
+
+public class EventBenefitsPreviewDto {
+ private final int day;
+
+ public EventBenefitsPreviewDto(final int day) {
+ this.day = day;
+ }
+
+ public static EventBenefitsPreviewDto from(final int day) {
+ return new EventBenefitsPreviewDto(day);
+ }
+
+ public int getDay() {
+ return day;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/GiftDto.java b/src/main/java/christmas/dto/GiftDto.java
new file mode 100644
index 0000000..6ffd78a
--- /dev/null
+++ b/src/main/java/christmas/dto/GiftDto.java
@@ -0,0 +1,24 @@
+package christmas.dto;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class GiftDto {
+ private final Map gift;
+
+ private GiftDto(Map gift) {
+ this.gift = gift;
+ }
+
+ public static GiftDto from(Map gift) {
+ return new GiftDto(gift);
+ }
+
+ public Map getGift() {
+ return Collections.unmodifiableMap(gift);
+ }
+
+ public boolean isEmpty() {
+ return gift.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/OrderedMenusDto.java b/src/main/java/christmas/dto/OrderedMenusDto.java
new file mode 100644
index 0000000..4b79253
--- /dev/null
+++ b/src/main/java/christmas/dto/OrderedMenusDto.java
@@ -0,0 +1,20 @@
+package christmas.dto;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class OrderedMenusDto {
+ private final Map orders;
+
+ public OrderedMenusDto(Map orders) {
+ this.orders = orders;
+ }
+
+ public static OrderedMenusDto from(Map orders) {
+ return new OrderedMenusDto(orders);
+ }
+
+ public Map getOrders() {
+ return Collections.unmodifiableMap(orders);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/TotalAmountWithNoDiscountDto.java b/src/main/java/christmas/dto/TotalAmountWithNoDiscountDto.java
new file mode 100644
index 0000000..5cabde5
--- /dev/null
+++ b/src/main/java/christmas/dto/TotalAmountWithNoDiscountDto.java
@@ -0,0 +1,17 @@
+package christmas.dto;
+
+public class TotalAmountWithNoDiscountDto {
+ private final int amount;
+
+ public TotalAmountWithNoDiscountDto(final int amount) {
+ this.amount = amount;
+ }
+
+ public static TotalAmountWithNoDiscountDto from(final int amount) {
+ return new TotalAmountWithNoDiscountDto(amount);
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/dto/TotalBenefitedAmountDto.java b/src/main/java/christmas/dto/TotalBenefitedAmountDto.java
new file mode 100644
index 0000000..5cbbbbd
--- /dev/null
+++ b/src/main/java/christmas/dto/TotalBenefitedAmountDto.java
@@ -0,0 +1,17 @@
+package christmas.dto;
+
+public class TotalBenefitedAmountDto {
+ private final int amount;
+
+ public TotalBenefitedAmountDto(final int amount) {
+ this.amount = amount;
+ }
+
+ public static TotalBenefitedAmountDto from(final int amount) {
+ return new TotalBenefitedAmountDto(amount);
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/global/ApplicationConstant.java b/src/main/java/christmas/global/ApplicationConstant.java
new file mode 100644
index 0000000..d544ca2
--- /dev/null
+++ b/src/main/java/christmas/global/ApplicationConstant.java
@@ -0,0 +1,9 @@
+package christmas.global;
+
+public class ApplicationConstant {
+ public static final int CURRENT_PROMOTION_MONTH = 12;
+ public static final String ERROR_PREFIX = "[ERROR] ";
+
+ private ApplicationConstant() {
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/service/EventManagerService.java b/src/main/java/christmas/service/EventManagerService.java
new file mode 100644
index 0000000..b3e3808
--- /dev/null
+++ b/src/main/java/christmas/service/EventManagerService.java
@@ -0,0 +1,45 @@
+package christmas.service;
+
+
+import static christmas.domain.constant.event.EventNumberConstant.GIFT_CHAMPAGNE_COUNT;
+
+import christmas.domain.EventManager;
+import christmas.domain.Orders;
+import christmas.domain.constant.orders.Menu;
+import christmas.dto.BenefitsDetailsDto;
+import christmas.dto.EstimatedAmountWithDiscountDto;
+import christmas.dto.EventBadgeDto;
+import christmas.dto.GiftDto;
+import christmas.dto.TotalBenefitedAmountDto;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class EventManagerService {
+ public GiftDto createGiftDto(Orders orders) {
+ Map gifts = new LinkedHashMap<>();
+ if (orders.isGiftEventApplicable()) {
+ makeGifts(gifts);
+ }
+ return GiftDto.from(gifts);
+ }
+
+ private void makeGifts(Map gifts) {
+ gifts.put(Menu.CHAMPAGNE.getName(), GIFT_CHAMPAGNE_COUNT.getValue());
+ }
+
+ public BenefitsDetailsDto createBenefitsDetailsDto(EventManager eventManager) {
+ return BenefitsDetailsDto.from(eventManager.createBenefitsDetails());
+ }
+
+ public TotalBenefitedAmountDto createTotalBenefitedAmountDto(EventManager eventManager) {
+ return TotalBenefitedAmountDto.from(eventManager.calculateTotalBenefitedAmount());
+ }
+
+ public EstimatedAmountWithDiscountDto createEstimatedAmountWithDiscountDto(EventManager eventManager) {
+ return EstimatedAmountWithDiscountDto.from(eventManager.calculateEstimatedOrdersAmountWithDiscount());
+ }
+
+ public EventBadgeDto createEventBadgeDto(EventManager eventManager) {
+ return EventBadgeDto.from(eventManager.issueEventBadge());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/service/OrdersService.java b/src/main/java/christmas/service/OrdersService.java
new file mode 100644
index 0000000..447ce0f
--- /dev/null
+++ b/src/main/java/christmas/service/OrdersService.java
@@ -0,0 +1,42 @@
+package christmas.service;
+
+import christmas.domain.Order;
+import christmas.domain.Orders;
+import christmas.domain.exception.InvalidOrdersException;
+import christmas.dto.OrderedMenusDto;
+import christmas.dto.TotalAmountWithNoDiscountDto;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class OrdersService {
+ public Orders createOrders(Map orders) throws InvalidOrdersException {
+ return Orders.from(makeOrders(orders));
+ }
+
+ private List makeOrders(Map orders) throws InvalidOrdersException {
+ return orders.entrySet().stream()
+ .map(order -> createOrder(order.getKey(), order.getValue()))
+ .toList();
+ }
+
+ private Order createOrder(final String menuName, final int menuCount) throws InvalidOrdersException {
+ return Order.of(menuName, menuCount);
+ }
+
+ public OrderedMenusDto createOrdersHistoryDto(Orders orders) {
+ return OrderedMenusDto.from(makeOrdersHistory(orders));
+ }
+
+ private Map makeOrdersHistory(Orders orders) {
+ return orders.getOrders().stream()
+ .collect(Collectors.toUnmodifiableMap(
+ Order::getMenuName,
+ Order::getMenuCount
+ ));
+ }
+
+ public TotalAmountWithNoDiscountDto createTotalAmountWithNoDiscountDto(Orders orders) {
+ return TotalAmountWithNoDiscountDto.from(orders.calculateTotalAmountWithNoDiscount());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/service/ReservationDayService.java b/src/main/java/christmas/service/ReservationDayService.java
new file mode 100644
index 0000000..c2a7cf7
--- /dev/null
+++ b/src/main/java/christmas/service/ReservationDayService.java
@@ -0,0 +1,15 @@
+package christmas.service;
+
+import christmas.domain.ReservationDay;
+import christmas.domain.exception.InvalidReservationDayException;
+import christmas.dto.EventBenefitsPreviewDto;
+
+public class ReservationDayService {
+ public ReservationDay createReservationDay(final int day) throws InvalidReservationDayException {
+ return ReservationDay.from(day);
+ }
+
+ public EventBenefitsPreviewDto createEventBenefitsPreviewDto(ReservationDay day) {
+ return EventBenefitsPreviewDto.from(day.getDay());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/InputView.java b/src/main/java/christmas/view/input/InputView.java
new file mode 100644
index 0000000..9901e42
--- /dev/null
+++ b/src/main/java/christmas/view/input/InputView.java
@@ -0,0 +1,28 @@
+package christmas.view.input;
+
+import camp.nextstep.edu.missionutils.Console;
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.DayInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.input.parser.InputParser;
+import java.util.Map;
+
+public class InputView {
+ private final InputParser inputParser;
+
+ public InputView() {
+ inputParser = new InputParser();
+ }
+
+ public int getReservationDay() throws BasicInputException, DayInputException {
+ return inputParser.parseReservationDay(readLine());
+ }
+
+ public Map getOrders() throws BasicInputException, OrdersInputException {
+ return inputParser.parseOrders(readLine());
+ }
+
+ private String readLine() {
+ return Console.readLine();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/constant/InputNumberConstant.java b/src/main/java/christmas/view/input/constant/InputNumberConstant.java
new file mode 100644
index 0000000..d9d8df0
--- /dev/null
+++ b/src/main/java/christmas/view/input/constant/InputNumberConstant.java
@@ -0,0 +1,23 @@
+package christmas.view.input.constant;
+
+public enum InputNumberConstant {
+ APPLICATION_MAX_INPUT_LENGTH(2000),
+ ORDERS_MAX_INPUT_LENGTH(1000),
+ ORDER_MAX_INPUT_LENGTH(33),
+ MENU_NAME_MAX_INPUT_LENGTH(30),
+ MENU_COUNT_MAX_INPUT_LENGTH(2),
+ DAY_MAX_INPUT_LENGTH(2),
+ MENU_NAME_INDEX(0),
+ MENU_COUNT_INDEX(1),
+ POSITIVE_BOUNDARY_VALUE(0);
+
+ private final int value;
+
+ InputNumberConstant(final int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/constant/InputSymbolConstant.java b/src/main/java/christmas/view/input/constant/InputSymbolConstant.java
new file mode 100644
index 0000000..f7b9bee
--- /dev/null
+++ b/src/main/java/christmas/view/input/constant/InputSymbolConstant.java
@@ -0,0 +1,20 @@
+package christmas.view.input.constant;
+
+public enum InputSymbolConstant {
+ BLANK(" "),
+ VOID(""),
+ ORDERS_DELIMITER(","),
+ ORDER_DELIMITER("-"),
+ DAY_SYMBOL("๋ ์ง"),
+ ORDER_SYMBOL("์ฃผ๋ฌธ");
+
+ private final String symbol;
+
+ InputSymbolConstant(final String symbol) {
+ this.symbol = symbol;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/BasicInputException.java b/src/main/java/christmas/view/input/exception/BasicInputException.java
new file mode 100644
index 0000000..23d5a58
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/BasicInputException.java
@@ -0,0 +1,11 @@
+package christmas.view.input.exception;
+
+public class BasicInputException extends IllegalArgumentException {
+ private BasicInputException(final String invalidDayExceptionMessage) {
+ super(invalidDayExceptionMessage);
+ }
+
+ public static BasicInputException of(final String basicInputExceptionMessage) {
+ return new BasicInputException(basicInputExceptionMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/DayInputException.java b/src/main/java/christmas/view/input/exception/DayInputException.java
new file mode 100644
index 0000000..6820be7
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/DayInputException.java
@@ -0,0 +1,11 @@
+package christmas.view.input.exception;
+
+public class DayInputException extends IllegalArgumentException {
+ private DayInputException(final String dayInputExceptionMessage) {
+ super(dayInputExceptionMessage);
+ }
+
+ public static DayInputException of(final String dayInputExceptionMessage) {
+ return new DayInputException(dayInputExceptionMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/OrdersInputException.java b/src/main/java/christmas/view/input/exception/OrdersInputException.java
new file mode 100644
index 0000000..3c94983
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/OrdersInputException.java
@@ -0,0 +1,11 @@
+package christmas.view.input.exception;
+
+public class OrdersInputException extends IllegalArgumentException {
+ private OrdersInputException(final String ordersInputExceptionMessage) {
+ super(ordersInputExceptionMessage);
+ }
+
+ public static OrdersInputException of(final String ordersInputExceptionMessage) {
+ return new OrdersInputException(ordersInputExceptionMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/message/BasicInputExceptionMessageFormat.java b/src/main/java/christmas/view/input/exception/message/BasicInputExceptionMessageFormat.java
new file mode 100644
index 0000000..26444fc
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/message/BasicInputExceptionMessageFormat.java
@@ -0,0 +1,19 @@
+package christmas.view.input.exception.message;
+
+import static christmas.global.ApplicationConstant.ERROR_PREFIX;
+
+public enum BasicInputExceptionMessageFormat {
+ TOO_LONG_WITH_BLANKS_FORMAT("์ ํจํ์ง ์์ %s์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ EMPTY_FORMAT("์ ํจํ์ง ์์ %s์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ TOO_LONG_FORMAT("์ ํจํ์ง ์์ %s์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.");
+
+ private final String format;
+
+ BasicInputExceptionMessageFormat(final String format) {
+ this.format = format;
+ }
+
+ public String getFormat() {
+ return ERROR_PREFIX + format;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/message/DayInputExceptionMessage.java b/src/main/java/christmas/view/input/exception/message/DayInputExceptionMessage.java
new file mode 100644
index 0000000..cb12a99
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/message/DayInputExceptionMessage.java
@@ -0,0 +1,18 @@
+package christmas.view.input.exception.message;
+
+import static christmas.global.ApplicationConstant.ERROR_PREFIX;
+
+public enum DayInputExceptionMessage {
+ NOT_NUMERIC_TYPE("์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ NOT_POSITIVE("์ ํจํ์ง ์์ ๋ ์ง์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.");
+
+ private final String message;
+
+ DayInputExceptionMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return ERROR_PREFIX + message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/exception/message/OrdersInputExceptionMessage.java b/src/main/java/christmas/view/input/exception/message/OrdersInputExceptionMessage.java
new file mode 100644
index 0000000..322b140
--- /dev/null
+++ b/src/main/java/christmas/view/input/exception/message/OrdersInputExceptionMessage.java
@@ -0,0 +1,21 @@
+package christmas.view.input.exception.message;
+
+import static christmas.global.ApplicationConstant.ERROR_PREFIX;
+
+public enum OrdersInputExceptionMessage {
+ INVALID_ORDER_FORMAT("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ EMPTY_MENU_COUNT("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ NOT_NUMERIC_TYPE("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ NOT_POSITIVE("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์."),
+ DUPLICATED_MENUS("์ ํจํ์ง ์์ ์ฃผ๋ฌธ์
๋๋ค. ๋ค์ ์
๋ ฅํด ์ฃผ์ธ์.");
+
+ private final String message;
+
+ OrdersInputExceptionMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return ERROR_PREFIX + message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/parser/InputParser.java b/src/main/java/christmas/view/input/parser/InputParser.java
new file mode 100644
index 0000000..75e925a
--- /dev/null
+++ b/src/main/java/christmas/view/input/parser/InputParser.java
@@ -0,0 +1,89 @@
+package christmas.view.input.parser;
+
+import static christmas.view.input.constant.InputNumberConstant.APPLICATION_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputNumberConstant.MENU_COUNT_INDEX;
+import static christmas.view.input.constant.InputNumberConstant.MENU_NAME_INDEX;
+import static christmas.view.input.constant.InputSymbolConstant.BLANK;
+import static christmas.view.input.constant.InputSymbolConstant.DAY_SYMBOL;
+import static christmas.view.input.constant.InputSymbolConstant.ORDERS_DELIMITER;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_DELIMITER;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static christmas.view.input.constant.InputSymbolConstant.VOID;
+import static christmas.view.input.exception.message.BasicInputExceptionMessageFormat.TOO_LONG_WITH_BLANKS_FORMAT;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.DayInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.input.validator.DayInputValidator;
+import christmas.view.input.validator.OrderInputValidator;
+import christmas.view.input.validator.OrdersInputValidator;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class InputParser {
+ private final DayInputValidator dayInputValidator;
+ private final OrdersInputValidator ordersInputValidator;
+ private final OrderInputValidator orderInputValidator;
+
+ public InputParser() {
+ this.dayInputValidator = new DayInputValidator();
+ this.ordersInputValidator = new OrdersInputValidator();
+ this.orderInputValidator = new OrderInputValidator();
+ }
+
+ public int parseReservationDay(String userInput) throws BasicInputException, DayInputException {
+ checkDayLengthIsUnderUpperLimit(userInput);
+ userInput = removeBlank(userInput);
+ dayInputValidator.validate(userInput);
+ return parseToInt(userInput);
+ }
+
+ public Map parseOrders(String userInput) throws BasicInputException, OrdersInputException {
+ checkOrdersLengthIsUnderUpperLimit(userInput);
+ userInput = removeBlank(userInput);
+ ordersInputValidator.preValidate(userInput);
+ validateEachOrder(userInput);
+ ordersInputValidator.postValidate(userInput);
+ return parseToOrderMap(userInput);
+ }
+
+ private void checkDayLengthIsUnderUpperLimit(final String userInput) {
+ if (userInput.length() > APPLICATION_MAX_INPUT_LENGTH.getValue()) {
+ throw BasicInputException.of(
+ String.format(TOO_LONG_WITH_BLANKS_FORMAT.getFormat(), DAY_SYMBOL.getSymbol()));
+ }
+ }
+
+ private void checkOrdersLengthIsUnderUpperLimit(final String userInput) {
+ if (userInput.length() > APPLICATION_MAX_INPUT_LENGTH.getValue()) {
+ throw BasicInputException.of(
+ String.format(TOO_LONG_WITH_BLANKS_FORMAT.getFormat(), ORDER_SYMBOL.getSymbol()));
+ }
+ }
+
+ private int parseToInt(String userInput) {
+ return Integer.parseInt(userInput);
+ }
+
+ private String removeBlank(String userInput) {
+ if (userInput.contains(BLANK.getSymbol())) {
+ userInput = userInput.replace(BLANK.getSymbol(), VOID.getSymbol());
+ }
+ return userInput;
+ }
+
+ private void validateEachOrder(final String userInput) throws BasicInputException, OrdersInputException {
+ Arrays.stream(userInput.split(ORDERS_DELIMITER.getSymbol()))
+ .forEach(orderInputValidator::validate);
+ }
+
+ private Map parseToOrderMap(final String userInput) {
+ return Arrays.stream(userInput.split(ORDERS_DELIMITER.getSymbol()))
+ .map(orders -> orders.split(ORDER_DELIMITER.getSymbol()))
+ .collect(Collectors.toUnmodifiableMap(
+ order -> order[MENU_NAME_INDEX.getValue()],
+ order -> parseToInt(order[MENU_COUNT_INDEX.getValue()])
+ ));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/BasicValidator.java b/src/main/java/christmas/view/input/validator/BasicValidator.java
new file mode 100644
index 0000000..16d834d
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/BasicValidator.java
@@ -0,0 +1,27 @@
+package christmas.view.input.validator;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+
+public abstract class BasicValidator {
+
+ protected void validate(final String userInput, final String inputType, final int maxLength)
+ throws BasicInputException {
+ validateNotEmpty(userInput, inputType);
+ validateLengthUnderMaxLength(userInput, inputType, maxLength);
+ }
+
+ protected void validateNotEmpty(final String userInput, final String inputType) {
+ if (userInput.isEmpty()) {
+ throw BasicInputException.of(
+ String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(), inputType));
+ }
+ }
+
+ protected void validateLengthUnderMaxLength(final String userInput, final String inputType, final int maxLength) {
+ if (userInput.length() > maxLength) {
+ throw BasicInputException.of(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(), inputType));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/DayInputValidator.java b/src/main/java/christmas/view/input/validator/DayInputValidator.java
new file mode 100644
index 0000000..a5b2f30
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/DayInputValidator.java
@@ -0,0 +1,39 @@
+package christmas.view.input.validator;
+
+import static christmas.view.input.constant.InputNumberConstant.DAY_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputNumberConstant.POSITIVE_BOUNDARY_VALUE;
+import static christmas.view.input.constant.InputSymbolConstant.DAY_SYMBOL;
+import static christmas.view.input.exception.message.DayInputExceptionMessage.NOT_NUMERIC_TYPE;
+import static christmas.view.input.exception.message.DayInputExceptionMessage.NOT_POSITIVE;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.DayInputException;
+
+public class DayInputValidator extends BasicValidator implements PositiveIntegerCheckable {
+ public void validate(final String dayInput) throws BasicInputException, DayInputException {
+ super.validate(dayInput, DAY_SYMBOL.getSymbol(), DAY_MAX_INPUT_LENGTH.getValue());
+ validateNumeric(dayInput);
+ validatePositive(dayInput);
+ }
+
+ @Override
+ public void validateNumeric(final String dayInput) {
+ try {
+ parseToInt(dayInput);
+ } catch (NumberFormatException e) {
+ throw DayInputException.of(NOT_NUMERIC_TYPE.getMessage());
+ }
+ }
+
+ @Override
+ public void validatePositive(final String dayInput) {
+ int day = parseToInt(dayInput);
+ if (day < POSITIVE_BOUNDARY_VALUE.getValue()) {
+ throw DayInputException.of(NOT_POSITIVE.getMessage());
+ }
+ }
+
+ private int parseToInt(final String dayInput) {
+ return Integer.parseInt(dayInput);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/MenuCountInputValidator.java b/src/main/java/christmas/view/input/validator/MenuCountInputValidator.java
new file mode 100644
index 0000000..cee80cf
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/MenuCountInputValidator.java
@@ -0,0 +1,38 @@
+package christmas.view.input.validator;
+
+import static christmas.view.input.constant.InputNumberConstant.MENU_COUNT_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputNumberConstant.POSITIVE_BOUNDARY_VALUE;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static christmas.view.input.exception.message.OrdersInputExceptionMessage.NOT_NUMERIC_TYPE;
+import static christmas.view.input.exception.message.OrdersInputExceptionMessage.NOT_POSITIVE;
+
+import christmas.view.input.exception.OrdersInputException;
+
+public class MenuCountInputValidator extends BasicValidator implements PositiveIntegerCheckable {
+ public void validate(final String menuCountInput) throws OrdersInputException {
+ super.validate(menuCountInput, ORDER_SYMBOL.getSymbol(), MENU_COUNT_MAX_INPUT_LENGTH.getValue());
+ validateNumeric(menuCountInput);
+ validatePositive(menuCountInput);
+ }
+
+ @Override
+ public void validateNumeric(final String menuCountInput) {
+ try {
+ parseToInt(menuCountInput);
+ } catch (NumberFormatException e) {
+ throw OrdersInputException.of(NOT_NUMERIC_TYPE.getMessage());
+ }
+ }
+
+ @Override
+ public void validatePositive(final String menuCountInput) {
+ int menuCount = parseToInt(menuCountInput);
+ if (menuCount < POSITIVE_BOUNDARY_VALUE.getValue()) {
+ throw OrdersInputException.of(NOT_POSITIVE.getMessage());
+ }
+ }
+
+ private int parseToInt(final String menuCountInput) {
+ return Integer.parseInt(menuCountInput);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/MenuNameInputValidator.java b/src/main/java/christmas/view/input/validator/MenuNameInputValidator.java
new file mode 100644
index 0000000..9f7e071
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/MenuNameInputValidator.java
@@ -0,0 +1,12 @@
+package christmas.view.input.validator;
+
+import static christmas.view.input.constant.InputNumberConstant.MENU_NAME_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+
+import christmas.view.input.exception.BasicInputException;
+
+public class MenuNameInputValidator extends BasicValidator {
+ public void validate(final String menuNameInput) throws BasicInputException {
+ super.validate(menuNameInput, ORDER_SYMBOL.getSymbol(), MENU_NAME_MAX_INPUT_LENGTH.getValue());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/OrderInputValidator.java b/src/main/java/christmas/view/input/validator/OrderInputValidator.java
new file mode 100644
index 0000000..684bcdd
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/OrderInputValidator.java
@@ -0,0 +1,61 @@
+package christmas.view.input.validator;
+
+import static christmas.view.input.constant.InputNumberConstant.MENU_COUNT_INDEX;
+import static christmas.view.input.constant.InputNumberConstant.MENU_NAME_INDEX;
+import static christmas.view.input.constant.InputNumberConstant.ORDER_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_DELIMITER;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static christmas.view.input.exception.message.OrdersInputExceptionMessage.EMPTY_MENU_COUNT;
+import static christmas.view.input.exception.message.OrdersInputExceptionMessage.INVALID_ORDER_FORMAT;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import java.util.Arrays;
+import java.util.List;
+
+public class OrderInputValidator extends BasicValidator {
+ private final MenuNameInputValidator menuNameInputValidator;
+ private final MenuCountInputValidator menuCountInputValidator;
+
+ public OrderInputValidator() {
+ this.menuNameInputValidator = new MenuNameInputValidator();
+ this.menuCountInputValidator = new MenuCountInputValidator();
+ }
+
+ public void validate(final String orderInput) throws BasicInputException, OrdersInputException {
+ super.validate(orderInput, ORDER_SYMBOL.getSymbol(), ORDER_MAX_INPUT_LENGTH.getValue());
+ validateContainingDelimiter(orderInput);
+ validateNotEndsWithDelimiter(orderInput);
+ validateMenu(splitToMenuInput(orderInput));
+ }
+
+ private void validateContainingDelimiter(final String orderInput) {
+ if (!containsDelimiter(orderInput)) {
+ throw OrdersInputException.of(INVALID_ORDER_FORMAT.getMessage());
+ }
+ }
+
+ private boolean containsDelimiter(final String orderInput) {
+ return orderInput.contains(ORDER_DELIMITER.getSymbol());
+ }
+
+ private void validateNotEndsWithDelimiter(final String orderInput) {
+ if (endsWithDelimiter(orderInput)) {
+ throw OrdersInputException.of(EMPTY_MENU_COUNT.getMessage());
+ }
+ }
+
+ private boolean endsWithDelimiter(final String orderInput) {
+ return orderInput.endsWith(ORDER_DELIMITER.getSymbol());
+ }
+
+ private List splitToMenuInput(final String orderInput) {
+ return Arrays.stream(orderInput.split(ORDER_DELIMITER.getSymbol()))
+ .toList();
+ }
+
+ private void validateMenu(List menuInput) throws BasicInputException, OrdersInputException {
+ menuNameInputValidator.validate(menuInput.get(MENU_NAME_INDEX.getValue()));
+ menuCountInputValidator.validate(menuInput.get(MENU_COUNT_INDEX.getValue()));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/OrdersInputValidator.java b/src/main/java/christmas/view/input/validator/OrdersInputValidator.java
new file mode 100644
index 0000000..31c3054
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/OrdersInputValidator.java
@@ -0,0 +1,41 @@
+package christmas.view.input.validator;
+
+import static christmas.view.input.constant.InputNumberConstant.MENU_NAME_INDEX;
+import static christmas.view.input.constant.InputNumberConstant.ORDERS_MAX_INPUT_LENGTH;
+import static christmas.view.input.constant.InputSymbolConstant.ORDERS_DELIMITER;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_DELIMITER;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static christmas.view.input.exception.message.OrdersInputExceptionMessage.DUPLICATED_MENUS;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class OrdersInputValidator extends BasicValidator {
+ public void preValidate(final String ordersInput) throws BasicInputException {
+ super.validate(ordersInput, ORDER_SYMBOL.getSymbol(), ORDERS_MAX_INPUT_LENGTH.getValue());
+ }
+
+ public void postValidate(final String ordersInput) throws OrdersInputException {
+ validateNotExistDuplicatedMenus(ordersInput);
+ }
+
+ private void validateNotExistDuplicatedMenus(final String ordersInput) {
+ Set uniqueMenuNames = makeUniqueMenuNames(ordersInput);
+ if (haveDuplicatedMenus(ordersInput, uniqueMenuNames)) {
+ throw OrdersInputException.of(DUPLICATED_MENUS.getMessage());
+ }
+ }
+
+ private Set makeUniqueMenuNames(final String ordersInput) {
+ return Arrays.stream(ordersInput.split(ORDERS_DELIMITER.getSymbol()))
+ .map(order -> order.split(ORDER_DELIMITER.getSymbol())[MENU_NAME_INDEX.getValue()])
+ .collect(Collectors.toUnmodifiableSet());
+ }
+
+ private boolean haveDuplicatedMenus(final String ordersInput, Set uniqueMenuNames) {
+ return uniqueMenuNames.size() < ordersInput.split(ORDERS_DELIMITER.getSymbol()).length;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/input/validator/PositiveIntegerCheckable.java b/src/main/java/christmas/view/input/validator/PositiveIntegerCheckable.java
new file mode 100644
index 0000000..e203f43
--- /dev/null
+++ b/src/main/java/christmas/view/input/validator/PositiveIntegerCheckable.java
@@ -0,0 +1,7 @@
+package christmas.view.input.validator;
+
+public interface PositiveIntegerCheckable {
+ void validateNumeric(final String userInput);
+
+ void validatePositive(final String userInput);
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/output/OutputView.java b/src/main/java/christmas/view/output/OutputView.java
new file mode 100644
index 0000000..c3313ee
--- /dev/null
+++ b/src/main/java/christmas/view/output/OutputView.java
@@ -0,0 +1,171 @@
+package christmas.view.output;
+
+import static christmas.view.output.constant.OutputFormatConstant.BENEFITS_DETAILS_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.ESTIMATED_AMOUNT_WITH_DISCOUNT_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.GIFT_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.ORDERED_MENUS_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.PRICE_FORMAT_STYLE;
+import static christmas.view.output.constant.OutputFormatConstant.SHOW_RESULT_INTRO_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.TOTAL_AMOUNT_WITH_NO_DISCOUNT_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputFormatConstant.TOTAL_BENEFITED_AMOUNT_PRINT_FORMAT;
+import static christmas.view.output.constant.OutputMessageConstant.GREETING;
+import static christmas.view.output.constant.OutputMessageConstant.INSERT_ORDERS;
+import static christmas.view.output.constant.OutputMessageConstant.INSERT_RESERVATION_DAY;
+import static christmas.view.output.constant.OutputSymbolConstant.BENEFITS_DETAILS;
+import static christmas.view.output.constant.OutputSymbolConstant.ESTIMATED_AMOUNT_WITH_DISCOUNT;
+import static christmas.view.output.constant.OutputSymbolConstant.EVENT_BADGE;
+import static christmas.view.output.constant.OutputSymbolConstant.GIFT_MENU;
+import static christmas.view.output.constant.OutputSymbolConstant.NEW_LINE;
+import static christmas.view.output.constant.OutputSymbolConstant.NO_BENEFITS;
+import static christmas.view.output.constant.OutputSymbolConstant.NO_EVENT_BADGE;
+import static christmas.view.output.constant.OutputSymbolConstant.NO_GIFT;
+import static christmas.view.output.constant.OutputSymbolConstant.ORDERED_MENUS;
+import static christmas.view.output.constant.OutputSymbolConstant.TOTAL_AMOUNT_WITH_NO_DISCOUNT;
+import static christmas.view.output.constant.OutputSymbolConstant.TOTAL_BENEFITED_AMOUNT;
+
+import christmas.dto.BenefitsDetailsDto;
+import christmas.dto.EstimatedAmountWithDiscountDto;
+import christmas.dto.EventBadgeDto;
+import christmas.dto.EventBenefitsPreviewDto;
+import christmas.dto.GiftDto;
+import christmas.dto.OrderedMenusDto;
+import christmas.dto.TotalAmountWithNoDiscountDto;
+import christmas.dto.TotalBenefitedAmountDto;
+import java.text.DecimalFormat;
+
+public class OutputView {
+ public void printGreetingMessage() {
+ print(GREETING.getMessage());
+ printLine();
+ }
+
+ public void askToInsertReservationDay() {
+ print(INSERT_RESERVATION_DAY.getMessage());
+ printLine();
+ }
+
+ public void askToInsertOrders() {
+ print(INSERT_ORDERS.getMessage());
+ printLine();
+ }
+
+ public void printIntroMessage(EventBenefitsPreviewDto eventBenefitsPreviewDto) {
+ printFormatted(SHOW_RESULT_INTRO_FORMAT.getFormat(), eventBenefitsPreviewDto.getDay());
+ printLine();
+ printLine();
+ }
+
+ public void printOrderedMenus(OrderedMenusDto orderedMenusDto) {
+ print(ORDERED_MENUS.getSymbol());
+ printLine();
+ orderedMenusDto.getOrders().forEach(this::printOrderedMenu);
+ }
+
+ private void printOrderedMenu(final String menuName, final int menuCount) {
+ printFormatted(ORDERED_MENUS_PRINT_FORMAT.getFormat(), menuName, menuCount);
+ printLine();
+ }
+
+ public void printTotalAmountWithNoDiscount(TotalAmountWithNoDiscountDto totalAmountWithNoDiscountDto) {
+ printLine();
+ print(TOTAL_AMOUNT_WITH_NO_DISCOUNT.getSymbol());
+ printLine();
+ printFormatted(TOTAL_AMOUNT_WITH_NO_DISCOUNT_PRINT_FORMAT.getFormat(),
+ formatPrice(totalAmountWithNoDiscountDto.getAmount()));
+ printLine();
+ }
+
+ public void printGiftMenu(GiftDto giftDto) {
+ printLine();
+ print(GIFT_MENU.getSymbol());
+ printLine();
+ printGift(giftDto);
+ }
+
+ private void printGift(GiftDto giftDto) {
+ if (giftDto.isEmpty()) {
+ print(NO_GIFT.getSymbol());
+ printLine();
+ }
+ giftDto.getGift().forEach((giftName, giftCount) -> {
+ printFormatted(GIFT_PRINT_FORMAT.getFormat(), giftName, giftCount);
+ printLine();
+ }
+ );
+ }
+
+ public void printBenefitsDetails(BenefitsDetailsDto benefitsDetailsDto) {
+ printLine();
+ print(BENEFITS_DETAILS.getSymbol());
+ printLine();
+ printBenefitNamesAndAmount(benefitsDetailsDto);
+ }
+
+ private void printBenefitNamesAndAmount(BenefitsDetailsDto benefitsDetailsDto) {
+ if (benefitsDetailsDto.isEmpty()) {
+ print(NO_BENEFITS.getSymbol());
+ printLine();
+ }
+ benefitsDetailsDto.getBenefitsDetails().forEach((benefitName, benefitAmount) -> {
+ printFormatted(BENEFITS_DETAILS_PRINT_FORMAT.getFormat(), benefitName, formatPrice(benefitAmount));
+ printLine();
+ }
+ );
+ }
+
+ public void printTotalBenefitedAmount(TotalBenefitedAmountDto totalBenefitedAmountDto) {
+ printLine();
+ print(TOTAL_BENEFITED_AMOUNT.getSymbol());
+ printLine();
+ printFormatted(TOTAL_BENEFITED_AMOUNT_PRINT_FORMAT.getFormat(),
+ formatPrice(-totalBenefitedAmountDto.getAmount()));
+ printLine();
+ }
+
+ public void printEstimatedAmountWithDiscount(EstimatedAmountWithDiscountDto estimatedAmountWithDiscountDto) {
+ printLine();
+ print(ESTIMATED_AMOUNT_WITH_DISCOUNT.getSymbol());
+ printLine();
+ printFormatted(ESTIMATED_AMOUNT_WITH_DISCOUNT_PRINT_FORMAT.getFormat(),
+ formatPrice(estimatedAmountWithDiscountDto.getAmount()));
+ printLine();
+ }
+
+ public void printEventBadge(EventBadgeDto eventBadgeDto) {
+ printLine();
+ print(EVENT_BADGE.getSymbol());
+ printLine();
+ printEventBadgeName(eventBadgeDto);
+ }
+
+ private void printEventBadgeName(EventBadgeDto eventBadgeDto) {
+ if (eventBadgeDto.isEmpty()) {
+ print(NO_EVENT_BADGE.getSymbol());
+ }
+ if (!eventBadgeDto.isEmpty()) {
+ print(eventBadgeDto.getBadgeName());
+ }
+ }
+
+ public void printErrorMessage(final String message) {
+ print(message);
+ printLine();
+ }
+
+ private void print(final String message) {
+ System.out.print(message);
+ }
+
+ private void printLine() {
+ System.out.print(NEW_LINE.getSymbol());
+ }
+
+ private void printFormatted(final String format, final Object... args) {
+ print(String.format(format, args));
+ }
+
+ private String formatPrice(final int price) {
+ return new DecimalFormat(PRICE_FORMAT_STYLE.getFormat())
+ .format(price);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/output/constant/OutputFormatConstant.java b/src/main/java/christmas/view/output/constant/OutputFormatConstant.java
new file mode 100644
index 0000000..47d4b07
--- /dev/null
+++ b/src/main/java/christmas/view/output/constant/OutputFormatConstant.java
@@ -0,0 +1,24 @@
+package christmas.view.output.constant;
+
+import static christmas.global.ApplicationConstant.CURRENT_PROMOTION_MONTH;
+
+public enum OutputFormatConstant {
+ SHOW_RESULT_INTRO_FORMAT(CURRENT_PROMOTION_MONTH + "์ %d์ผ์ ์ฐํ
์ฝ ์๋น์์ ๋ฐ์ ์ด๋ฒคํธ ํํ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ!"),
+ ORDERED_MENUS_PRINT_FORMAT("%s %d๊ฐ"),
+ TOTAL_AMOUNT_WITH_NO_DISCOUNT_PRINT_FORMAT("%s์"),
+ PRICE_FORMAT_STYLE("###,###"),
+ GIFT_PRINT_FORMAT("%s %d๊ฐ"),
+ BENEFITS_DETAILS_PRINT_FORMAT("%s: -%s์"),
+ TOTAL_BENEFITED_AMOUNT_PRINT_FORMAT("%s์"),
+ ESTIMATED_AMOUNT_WITH_DISCOUNT_PRINT_FORMAT("%s์");
+
+ private final String format;
+
+ OutputFormatConstant(final String format) {
+ this.format = format;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/output/constant/OutputMessageConstant.java b/src/main/java/christmas/view/output/constant/OutputMessageConstant.java
new file mode 100644
index 0000000..5c825ba
--- /dev/null
+++ b/src/main/java/christmas/view/output/constant/OutputMessageConstant.java
@@ -0,0 +1,19 @@
+package christmas.view.output.constant;
+
+import static christmas.global.ApplicationConstant.CURRENT_PROMOTION_MONTH;
+
+public enum OutputMessageConstant {
+ GREETING("์๋
ํ์ธ์! ์ฐํ
์ฝ ์๋น " + CURRENT_PROMOTION_MONTH + "์ ์ด๋ฒคํธ ํ๋๋์
๋๋ค."),
+ INSERT_RESERVATION_DAY(CURRENT_PROMOTION_MONTH + "์ ์ค ์๋น ๋ฐฉ๋ฌธ ๋ ์ง๋ ์ธ์ ์ธ๊ฐ์? (์ซ์๋ง ์
๋ ฅํด ์ฃผ์ธ์!)"),
+ INSERT_ORDERS("์ฃผ๋ฌธํ์ค ๋ฉ๋ด๋ฅผ ๋ฉ๋ด์ ๊ฐ์๋ฅผ ์๋ ค ์ฃผ์ธ์. (e.g. ํด์ฐ๋ฌผํ์คํ-2,๋ ๋์์ธ-1,์ด์ฝ์ผ์ดํฌ-1)");
+
+ private final String message;
+
+ OutputMessageConstant(final String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/christmas/view/output/constant/OutputSymbolConstant.java b/src/main/java/christmas/view/output/constant/OutputSymbolConstant.java
new file mode 100644
index 0000000..5849c15
--- /dev/null
+++ b/src/main/java/christmas/view/output/constant/OutputSymbolConstant.java
@@ -0,0 +1,24 @@
+package christmas.view.output.constant;
+
+public enum OutputSymbolConstant {
+ NEW_LINE(System.lineSeparator()),
+ ORDERED_MENUS("<์ฃผ๋ฌธ ๋ฉ๋ด>"),
+ TOTAL_AMOUNT_WITH_NO_DISCOUNT("<ํ ์ธ ์ ์ด์ฃผ๋ฌธ ๊ธ์ก>"),
+ GIFT_MENU("<์ฆ์ ๋ฉ๋ด>"),
+ BENEFITS_DETAILS("<ํํ ๋ด์ญ>"),
+ TOTAL_BENEFITED_AMOUNT("<์ดํํ ๊ธ์ก>"),
+ ESTIMATED_AMOUNT_WITH_DISCOUNT("<ํ ์ธ ํ ์์ ๊ฒฐ์ ๊ธ์ก>"),
+ EVENT_BADGE("<12์ ์ด๋ฒคํธ ๋ฐฐ์ง>"),
+ NO_GIFT("์์"),
+ NO_BENEFITS("์์"),
+ NO_EVENT_BADGE("์์");
+ private final String symbol;
+
+ OutputSymbolConstant(final String symbol) {
+ this.symbol = symbol;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/ChristmasPromotionTest.java b/src/test/java/christmas/domain/ChristmasPromotionTest.java
new file mode 100644
index 0000000..08a6da6
--- /dev/null
+++ b/src/test/java/christmas/domain/ChristmasPromotionTest.java
@@ -0,0 +1,21 @@
+package christmas.domain;
+
+import static christmas.domain.constant.event.ChristmasPromotion.CHRISTMAS_D_DAY_PROMOTION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class ChristmasPromotionTest {
+ @DisplayName("25์ผ ์ด์ ์ ๋ ์ง๊ฐ ์
๋ ฅ๋๋ฉด, ํด๋นํ๋ ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ๋ก๋ชจ์
๊ธ์ก์ ๊ณ์ฐํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {
+ "1:1000", "2:1100", "3:1200", "25:3400", "24:3300", "23:3200",
+ "15:2400", "16:2500", "19:2800", "7:1600", "11:2000", "13:2200"
+ }, delimiter = ':')
+ void ๋ ์ง๊ฐ_์
๋ ฅ๋๋ฉด_ํด๋นํ๋_ํฌ๋ฆฌ์ค๋ง์ค_๋๋ฐ์ด_ํ๋ก๋ชจ์
_๊ธ์ก์_๊ณ์ฐ(int day, int expectedBenefitAmount) {
+ assertThat(CHRISTMAS_D_DAY_PROMOTION.getBenefitAmount(day))
+ .isEqualTo(expectedBenefitAmount);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/EventBadgeTest.java b/src/test/java/christmas/domain/EventBadgeTest.java
new file mode 100644
index 0000000..40f9d14
--- /dev/null
+++ b/src/test/java/christmas/domain/EventBadgeTest.java
@@ -0,0 +1,21 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import christmas.domain.constant.event.EventBadge;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class EventBadgeTest {
+ @DisplayName("ํํ ๊ธ์ก์ ๋ฐ๋ผ ์ด๋ฒคํธ ๋ฐฐ์ง๋ฅผ ๋ฐ๊ธํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {
+ "1000:''", "4999:''", "5000:๋ณ", "8230:๋ณ", "9999:๋ณ", "10000:ํธ๋ฆฌ", "13200:ํธ๋ฆฌ",
+ "14999:ํธ๋ฆฌ", "15000:ํธ๋ฆฌ", "19999:ํธ๋ฆฌ", "20000:์ฐํ", "20001:์ฐํ", "83000:์ฐํ"
+ }, delimiter = ':')
+ void ํํ_๊ธ์ก์_๋ฐ๋ผ_์ด๋ฒคํธ_๋ฐฐ์ง_๋ฐ๊ธ(int totalBenefitedAmount, String eventBadgeName) {
+ assertThat(EventBadge.getBadgeNameByBenefitedPrice(totalBenefitedAmount))
+ .isEqualTo(eventBadgeName);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/EventManagerTest.java b/src/test/java/christmas/domain/EventManagerTest.java
new file mode 100644
index 0000000..b45fd57
--- /dev/null
+++ b/src/test/java/christmas/domain/EventManagerTest.java
@@ -0,0 +1,101 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class EventManagerTest {
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ๊ณผ ๋ ์ง๋ฅผ ๋น๊ตํด์, ํํ ๋ด์ญ์ ์์ฐํ๋ค.")
+ @ParameterizedTest
+ @CsvSource({
+ "4, '์์ ์๋ฌ๋,3|์ ๋ก์ฝ๋ผ,2|๋ ๋์์ธ,1|ํฐ๋ณธ์คํ
์ดํฌ,3|์ด์ฝ์ผ์ดํฌ,4','ํ์ผ ํ ์ธ,8092|ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ,1300|์ฆ์ ์ด๋ฒคํธ,25000'",
+ "3,'ํฐ๋ณธ์คํ
์ดํฌ,1|๋ฐ๋นํ๋ฆฝ,1|์ด์ฝ์ผ์ดํฌ,2|์ ๋ก์ฝ๋ผ,1','ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ,1200|ํ์ผ ํ ์ธ,4046|ํน๋ณ ํ ์ธ,1000|์ฆ์ ์ด๋ฒคํธ,25000'",
+ "25,'ํํ์ค,1|ํฐ๋ณธ์คํ
์ดํฌ,1|์์ด์คํฌ๋ฆผ,3|์ ๋ก์ฝ๋ผ,3','ํฌ๋ฆฌ์ค๋ง์ค ๋๋ฐ์ด ํ ์ธ,3400|ํ์ผ ํ ์ธ,6069|ํน๋ณ ํ ์ธ,1000'"
+ })
+ void ์ฃผ๋ฌธ_๋ด์ญ๊ณผ_๋ ์ง๋ฅผ_๋น๊ตํด์_ํํ_๋ด์ญ์_์์ฐ(int day, String menuAndCounts, String expectedBenefitDetails) {
+ // given
+ EventManager eventManager = createEventManager(day, menuAndCounts);
+ // when
+ Map benefitsDetails = eventManager.createBenefitsDetails();
+ // then
+ for (String benefit : expectedBenefitDetails.split("\\|")) {
+ String[] parts = benefit.split(",");
+ String benefitName = parts[0];
+ int expectedAmount = Integer.parseInt(parts[1]);
+ assertThat(benefitsDetails.get(benefitName)).isEqualTo(expectedAmount);
+ }
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ๋ ์ง์ ๋ฐ๋ฅธ ํ ์ธ ์ฌ๋ถ๋ฅผ ์ ์ฉํด์, ํ ์ธ ๊ธ์ก์ ๊ณ์ฐํ๋ค.")
+ @ParameterizedTest
+ @CsvSource({
+ "4, '์์ ์๋ฌ๋,3|์ ๋ก์ฝ๋ผ,2|๋ ๋์์ธ,1|ํฐ๋ณธ์คํ
์ดํฌ,3|์ด์ฝ์ผ์ดํฌ,4','9392'",
+ "3,'ํฐ๋ณธ์คํ
์ดํฌ,1|๋ฐ๋นํ๋ฆฝ,1|์ด์ฝ์ผ์ดํฌ,2|์ ๋ก์ฝ๋ผ,1','6246'",
+ "25,'ํํ์ค,1|ํฐ๋ณธ์คํ
์ดํฌ,1|์์ด์คํฌ๋ฆผ,3|์ ๋ก์ฝ๋ผ,3','10469'"
+ })
+ void ์ฃผ๋ฌธ_๋ด์ญ์_๋ ์ง์_๋ฐ๋ฅธ_ํ ์ธ_์ฌ๋ถ๋ฅผ_์ ์ฉํด์_ํ ์ธ_๊ธ์ก_๊ณ์ฐ(int day, String menuAndCounts, int expectedDiscountAmount) {
+ // given
+ Orders orders = Orders.from(parseMenuAndCounts(menuAndCounts));
+ EventManager eventManager = createEventManager(day, menuAndCounts);
+ // when
+ int discountAmount =
+ orders.calculateTotalAmountWithNoDiscount() - eventManager.calculateEstimatedOrdersAmountWithDiscount();
+ // then
+ assertThat(discountAmount).isEqualTo(expectedDiscountAmount);
+ }
+
+ @DisplayName("ํํ ๋ด์ญ์ ๊ธ์ก์ ํฉ์ณ์, ์ด ํํ ๊ธ์ก์ ๊ณ์ฐํ๋ค.")
+ @ParameterizedTest
+ @CsvSource({
+ "4, '์์ ์๋ฌ๋,3|์ ๋ก์ฝ๋ผ,2|๋ ๋์์ธ,1|ํฐ๋ณธ์คํ
์ดํฌ,3|์ด์ฝ์ผ์ดํฌ,4','34392'",
+ "3,'ํฐ๋ณธ์คํ
์ดํฌ,1|๋ฐ๋นํ๋ฆฝ,1|์ด์ฝ์ผ์ดํฌ,2|์ ๋ก์ฝ๋ผ,1','31246'",
+ "25,'ํํ์ค,1|ํฐ๋ณธ์คํ
์ดํฌ,1|์์ด์คํฌ๋ฆผ,3|์ ๋ก์ฝ๋ผ,3','10469'"
+ })
+ void ํํ_๋ด์ญ์_๊ธ์ก์_ํฉ์ณ์_์ด_ํํ_๊ธ์ก์_๊ณ์ฐ(int day, String menuAndCounts, int expectedDiscountAmount) {
+ // given
+ EventManager eventManager = createEventManager(day, menuAndCounts);
+ // when
+ int discountAmount = eventManager.calculateTotalBenefitedAmount();
+ // then
+ assertThat(discountAmount).isEqualTo(expectedDiscountAmount);
+ }
+
+ @DisplayName("์ด ํํ ๊ธ์ก์ ๊ธฐ๋ฐ์ผ๋ก 12์ ์ด๋ฒคํธ ๋ฐฐ์ง๋ฅผ ๋ฐ๊ธํ๋ค.")
+ @ParameterizedTest
+ @CsvSource({
+ "4, '์์ ์๋ฌ๋,3|์ ๋ก์ฝ๋ผ,2|๋ ๋์์ธ,1|ํฐ๋ณธ์คํ
์ดํฌ,3|์ด์ฝ์ผ์ดํฌ,4','์ฐํ'",
+ "3,'ํฐ๋ณธ์คํ
์ดํฌ,1|๋ฐ๋นํ๋ฆฝ,1|์ด์ฝ์ผ์ดํฌ,2|์ ๋ก์ฝ๋ผ,1','์ฐํ'",
+ "25,'ํํ์ค,1|ํฐ๋ณธ์คํ
์ดํฌ,1|์์ด์คํฌ๋ฆผ,3|์ ๋ก์ฝ๋ผ,3','ํธ๋ฆฌ'",
+ "26,'ํํ์ค,1|ํฌ๋ฆฌ์ค๋ง์คํ์คํ,1|์์ด์คํฌ๋ฆผ,3|','๋ณ'",
+ "26,'์์ก์ด์ํ,3|ํฌ๋ฆฌ์ค๋ง์คํ์คํ,1|์์ด์คํฌ๋ฆผ,1|',''"
+ })
+ void ์ด_ํํ_๊ธ์ก์_๊ธฐ๋ฐ์ผ๋ก_12์_์ด๋ฒคํธ_๋ฐฐ์ง๋ฅผ_๋ฐ๊ธ(int day, String menuAndCounts, String expectedEventBadge) {
+ // given
+ EventManager eventManager = createEventManager(day, menuAndCounts);
+ // when
+ String eventBadge = eventManager.issueEventBadge();
+ // then
+ assertThat(eventBadge).isEqualTo(expectedEventBadge);
+ }
+
+ private EventManager createEventManager(int day, String menuAndCounts) {
+ ReservationDay reservationDay = ReservationDay.from(day);
+ Orders orders = Orders.from(parseMenuAndCounts(menuAndCounts));
+ return EventManager.of(reservationDay, orders);
+ }
+
+ private List parseMenuAndCounts(String menuAndCounts) {
+ List orders = new ArrayList<>();
+ String[] splitedMenusAndCounts = menuAndCounts.split("\\|");
+ for (String splitedMenusAndCount : splitedMenusAndCounts) {
+ String[] menuNameAndCount = splitedMenusAndCount.split(",");
+ orders.add(Order.of(menuNameAndCount[0], Integer.parseInt(menuNameAndCount[1])));
+ }
+ return orders;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/MenuTest.java b/src/test/java/christmas/domain/MenuTest.java
new file mode 100644
index 0000000..05b602d
--- /dev/null
+++ b/src/test/java/christmas/domain/MenuTest.java
@@ -0,0 +1,34 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.domain.constant.orders.Menu;
+import christmas.domain.exception.InvalidOrdersException;
+import christmas.domain.exception.message.InvalidOrdersExceptionMessage;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class MenuTest {
+ @DisplayName("๋ฉ๋ด ์ด๋ฆ์ด ๋ฉ๋ดํ์ ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {"์์ธ์๋ฌ๋", "๋์์ก์ด์ํ", "๋ฌผํ์ค", "๋ฐฑํผ์ฝ๋ผ", "์์ด๋ณธ์คํ
์ดํฌ", "๋ฐ๋นํ์นํจ", "ํฌ๋ฆผ", "๋น๊ทผ์ผ์ดํฌ"})
+ void ๋ฉ๋ด_์ด๋ฆ์ด_๋ฉ๋ดํ์_์์ผ๋ฉด_์์ธ_๋ฐ์(String menuName) {
+ assertThatThrownBy(() -> Menu.searchByName(menuName))
+ .isInstanceOf(InvalidOrdersException.class)
+ .hasMessageContaining(InvalidOrdersExceptionMessage.NOT_EXISTING_MENU.getMessage());
+ }
+
+ @DisplayName("๋ฉ๋ด ์ด๋ฆ์ด ๋ฉ๋ดํ์ ์์ผ๋ฉด, ๋ฉ๋ด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐํ๋๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {"์์ ์๋ฌ๋", "ํํ์ค", "์์ก์ด์ํ", "ํฐ๋ณธ์คํ
์ดํฌ", "๋ฐ๋นํ๋ฆฝ", "ํด์ฐ๋ฌผํ์คํ", "ํฌ๋ฆฌ์ค๋ง์คํ์คํ", "์ด์ฝ์ผ์ดํฌ", "์์ด์คํฌ๋ฆผ", "์ ๋ก์ฝ๋ผ",
+ "๋ ๋์์ธ", "์ดํ์ธ"})
+ void ๋ฉ๋ด_์ด๋ฆ์ด_๋ฉ๋ดํ์_์์ผ๋ฉด_๋ฉ๋ด๋ฅผ_์ฌ๋ฐ๋ฅด๊ฒ_๋ฐํ(String menuName) {
+ // given, when
+ Menu menu = Menu.searchByName(menuName);
+ // then
+ assertThat(menu).isInstanceOf(Menu.class);
+ assertThat(menu.getName()).isEqualTo(menuName);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/OrderTest.java b/src/test/java/christmas/domain/OrderTest.java
new file mode 100644
index 0000000..88f000e
--- /dev/null
+++ b/src/test/java/christmas/domain/OrderTest.java
@@ -0,0 +1,31 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.domain.exception.InvalidOrdersException;
+import christmas.domain.exception.message.InvalidOrdersExceptionMessage;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class OrderTest {
+ @DisplayName("๋ฉ๋ดํ์ ์๋ ๋ฉ๋ด ์ด๋ฆ๊ณผ ์๋์ ์ฃผ๋ฌธํ๋ฉด ์ฃผ๋ฌธ์ด ์์ฑ๋๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"์์ก์ด์ํ-10", "ํํ์ค-3", "๋ ๋์์ธ-5", "์ ๋ก์ฝ๋ผ-3", "์ดํ์ธ-7", "๋ฐ๋นํ๋ฆฝ-10"}, delimiter = '-')
+ void ๋ฉ๋ดํ์_์๋_๋ฉ๋ด_์ด๋ฆ๊ณผ_์๋์_์ฃผ๋ฌธ์_์ฃผ๋ฌธ_์์ฑ(String menuName, int count) {
+ // given, when
+ Order order = Order.of(menuName, count);
+ // then
+ assertThat(order).isInstanceOf(Order.class);
+ }
+
+ @DisplayName("๋ฉ๋ดํ์ ์๋ ๋ฉ๋ด๋ฅผ ์ฃผ๋ฌธํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"์์ ธ์๋ฌ๋-10", "ํฐ์คํ
์ดํฌ-3", "์ฐ๋๋ฌผํ์คํ-2", "๋
ผ์์ฝ์ฝ๋ผ-3", "๋จ์คํ์คํ-7", "์ฐ๊ทผ์ผ์ดํฌ-10"}, delimiter = '-')
+ void ๋ฉ๋ดํ์_์๋_๋ฉ๋ด์ด๋ฆ์ผ๋ก_์ฃผ๋ฌธ์_์์ธ_๋ฐ์(String menuName, int count) {
+ assertThatThrownBy(() -> Order.of(menuName, count))
+ .isInstanceOf(InvalidOrdersException.class)
+ .hasMessageContaining(InvalidOrdersExceptionMessage.NOT_EXISTING_MENU.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/OrdersTest.java b/src/test/java/christmas/domain/OrdersTest.java
new file mode 100644
index 0000000..9f77ad6
--- /dev/null
+++ b/src/test/java/christmas/domain/OrdersTest.java
@@ -0,0 +1,114 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.domain.exception.InvalidOrdersException;
+import christmas.domain.exception.message.InvalidOrdersExceptionMessage;
+import java.util.List;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class OrdersTest {
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ๋ฉ๋ด ๊ฐ์๊ฐ 20๊ฐ๊ฐ ๋์ด๊ฐ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_๋ฉ๋ด_๊ฐ์๊ฐ_20๊ฐ๊ฐ_๋์ด๊ฐ๋ฉด_์์ธ_๋ฐ์() {
+ // given
+ List orders = List.of(
+ Order.of("์์ ์๋ฌ๋", 3),
+ Order.of("์ ๋ก์ฝ๋ผ", 10),
+ Order.of("ํํ์ค", 2),
+ Order.of("ํฐ๋ณธ์คํ
์ดํฌ", 3),
+ Order.of("์ด์ฝ์ผ์ดํฌ", 4)
+ );
+ // when, then
+ assertThatThrownBy(() -> Orders.from(orders))
+ .isInstanceOf(InvalidOrdersException.class)
+ .hasMessageContaining(InvalidOrdersExceptionMessage.EXCEED_MENU_COUNTS_UPPER_LIMIT.getMessage());
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๋ด์ญ์ ์๋ฃ์๋ง ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_์ฃผ๋ฌธ_๋ด์ญ์_์๋ฃ์๋ง_์์ผ๋ฉด_์์ธ_๋ฐ์() {
+ // given
+ List orders = List.of(
+ Order.of("๋ ๋์์ธ", 3),
+ Order.of("์ ๋ก์ฝ๋ผ", 4),
+ Order.of("์ดํ์ธ", 5)
+ );
+ // when, then
+ assertThatThrownBy(() -> Orders.from(orders))
+ .isInstanceOf(InvalidOrdersException.class)
+ .hasMessageContaining(InvalidOrdersExceptionMessage.MENUS_ONLY_CONTAIN_BEVERAGE.getMessage());
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด 10000์ ์ดํ๋ฉด ๋ชจ๋ ์ด๋ฒคํธ ์ ์ฉ ๋์์์ ์ ์ธ๋๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_์ฃผ๋ฌธ_๊ธ์ก์ด_10000์_์ดํ๋ฉด_๋ชจ๋ _์ด๋ฒคํธ_์ ์ฉ_๋์์์_์ ์ธ() {
+ // given
+ List orders = List.of(
+ Order.of("์์ก์ด์ํ", 1),
+ Order.of("์ ๋ก์ฝ๋ผ", 1)
+ );
+ // when, then
+ assertThat(Orders.from(orders).isEventApplicable()).isEqualTo(false);
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด 10000์ ์ด๊ณผ๋ฉด ์ด๋ฒคํธ ์ ์ฉ ๋์์ ํฌํจํ๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_์ฃผ๋ฌธ_๊ธ์ก์ด_10000์_์ด๊ณผ๋ฉด_์ด๋ฒคํธ_์ ์ฉ_๋์์_ํฌํจ() {
+ // given
+ List orders = List.of(
+ Order.of("์์ ์๋ฌ๋", 2),
+ Order.of("ํฐ๋ณธ์คํ
์ดํฌ", 3)
+ );
+ // when, then
+ assertThat(Orders.from(orders).isEventApplicable()).isEqualTo(true);
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด 12๋ง์ ๋ฏธ๋ง์ด๋ฉด ์ฆ์ ์ด๋ฒคํธ ์ ์ฉ ๋์์ ์ ์ธ๋๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_์ฃผ๋ฌธ_๊ธ์ก์ด_12๋ง์_๋ฏธ๋ง์ด๋ฉด_์ฆ์ _์ด๋ฒคํธ_์ ์ฉ_๋์์_ํฌํจ() {
+ // given
+ List orders = List.of(
+ Order.of("์์ ์๋ฌ๋", 1),
+ Order.of("ํฌ๋ฆฌ์ค๋ง์คํ์คํ", 1),
+ Order.of("์์ด์คํฌ๋ฆผ", 1),
+ Order.of("์ ๋ก์ฝ๋ผ", 1)
+ );
+ // when, then
+ assertThat(Orders.from(orders).isGiftEventApplicable()).isEqualTo(false);
+ }
+
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ฃผ๋ฌธ ๊ธ์ก์ด 12๋ง์ ์ด์์ด๋ฉด ์ฆ์ ์ด๋ฒคํธ ์ ์ฉ ๋์์ ํฌํจํ๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ทจํฉํ์๋_์ฃผ๋ฌธ_๊ธ์ก์ด_12๋ง์_์ด์์ด๋ฉด_์ฆ์ _์ด๋ฒคํธ_์ ์ฉ_๋์์_ํฌํจ() {
+ // given
+ List orders = List.of(
+ Order.of("์์ ์๋ฌ๋", 2),
+ Order.of("๋ฐ๋นํ๋ฆฝ", 2),
+ Order.of("ํฐ๋ณธ์คํ
์ดํฌ", 1),
+ Order.of("์ด์ฝ์ผ์ดํฌ", 1),
+ Order.of("๋ ๋์์ธ", 1)
+ );
+ // when, then
+ assertThat(Orders.from(orders).isGiftEventApplicable()).isEqualTo(true);
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ด์ฉํด์ ํ ์ธ ์ ์ด ์ฃผ๋ฌธ ๊ธ์ก์ ๊ณ์ฐํ๋ค.")
+ @Test
+ public void ์ฃผ๋ฌธ_๋ด์ญ์_์ด์ฉํด์_ํ ์ธ_์ _์ด_์ฃผ๋ฌธ_๊ธ์ก์_๊ณ์ฐ() {
+ // given
+ List orders = List.of(
+ Order.of("์์ ์๋ฌ๋", 1),
+ Order.of("ํฐ๋ณธ์คํ
์ดํฌ", 1),
+ Order.of("์์ด์คํฌ๋ฆผ", 1),
+ Order.of("์ด์ฝ์ผ์ดํฌ", 1),
+ Order.of("๋ ๋์์ธ", 1)
+ );
+ // when, then
+ assertThat(Orders.from(orders).calculateTotalAmountWithNoDiscount()).isEqualTo(143000);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/domain/ReservationDayTest.java b/src/test/java/christmas/domain/ReservationDayTest.java
new file mode 100644
index 0000000..275520a
--- /dev/null
+++ b/src/test/java/christmas/domain/ReservationDayTest.java
@@ -0,0 +1,65 @@
+package christmas.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.domain.exception.InvalidReservationDayException;
+import christmas.domain.exception.message.InvalidReservationDayExceptionMessage;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class ReservationDayTest {
+ @DisplayName("์ ํจํ์ง ์์ ๋ ์ง ( 1 ~ 31 ์ฌ์ด์ ์ซ์๊ฐ ์๋ ์ซ์ )๋ฅผ ์
๋ ฅํ๋ฉด ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค.")
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1, -10, 300, 350, 500, 32})
+ void ์ ํจํ์ง_์์_๋ ์ง_์
๋ ฅ์_์์ธ_๋ฐ์(int day) {
+ assertThatThrownBy(() -> ReservationDay.from(day))
+ .isInstanceOf(InvalidReservationDayException.class)
+ .hasMessageContaining(InvalidReservationDayExceptionMessage.NOT_IN_APPROPRIATE_RANGE.getMessage());
+ }
+
+ @DisplayName("๋ ์ง๋ฅผ ์
๋ ฅํ๋ฉด ํฌ๋ฆฌ์ค๋ง์ค D-Day ํ๋ก๋ชจ์
์ด ์ ์ฉ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ํ๋จ ๊ฐ๋ฅํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"1:true", "10:true", "24:true", "31:false", "25:true", "26:false"}, delimiter = ':')
+ void ๋ ์ง_์
๋ ฅ์_ํฌ๋ฆฌ์ค๋ง์ค_๋๋ฐ์ด_ํ๋ก๋ชจ์
_์ ์ฉ_๊ฐ๋ฅ_์ฌ๋ถ_ํ๋จ_๊ฐ๋ฅ(int day, boolean expected) {
+ // given, when
+ ReservationDay reservationDay = ReservationDay.from(day);
+ // then
+ assertThat(reservationDay.isChristmasPromotionApplicable()).isEqualTo(expected);
+ }
+
+ @DisplayName("๋ ์ง๋ฅผ ์
๋ ฅํ๋ฉด ํ์ผ ํ ์ธ์ด ์ ์ฉ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ํ๋จ ๊ฐ๋ฅํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"5:true", "6:true", "7:true", "8:false", "25:true", "29:false", "30:false",
+ "31:true"}, delimiter = ':')
+ void ๋ ์ง_์
๋ ฅ์_ํ์ผ_ํ ์ธ_์ ์ฉ_๊ฐ๋ฅ_์ฌ๋ถ_ํ๋จ_๊ฐ๋ฅ(int day, boolean expected) {
+ // given, when
+ ReservationDay reservationDay = ReservationDay.from(day);
+ // then
+ assertThat(reservationDay.isWeekdayPromotionApplicable()).isEqualTo(expected);
+ }
+
+ @DisplayName("๋ ์ง๋ฅผ ์
๋ ฅํ๋ฉด ์ฃผ๋ง ํ ์ธ์ด ์ ์ฉ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ํ๋จ ๊ฐ๋ฅํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"1:true", "9:true", "15:true", "24:false", "30:true", "28:false", "31:false",
+ "23:true"}, delimiter = ':')
+ void ๋ ์ง_์
๋ ฅ์_์ฃผ๋ง_ํ ์ธ_์ ์ฉ_๊ฐ๋ฅ_์ฌ๋ถ_ํ๋จ_๊ฐ๋ฅ(int day, boolean expected) {
+ // given, when
+ ReservationDay reservationDay = ReservationDay.from(day);
+ // then
+ assertThat(reservationDay.isWeekendPromotionApplicable()).isEqualTo(expected);
+ }
+
+ @DisplayName("๋ ์ง๋ฅผ ์
๋ ฅํ๋ฉด ํน๋ณ ํ ์ธ์ด ์ ์ฉ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ํ๋จ ๊ฐ๋ฅํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"3:true", "10:true", "24:true", "26:false", "25:true", "27:false", "14:false",
+ "17:true", "31:true"}, delimiter = ':')
+ void ๋ ์ง_์
๋ ฅ์_ํน๋ณ_ํ ์ธ_์ ์ฉ_๊ฐ๋ฅ_์ฌ๋ถ_ํ๋จ_๊ฐ๋ฅ(int day, boolean expected) {
+ // given, when
+ ReservationDay reservationDay = ReservationDay.from(day);
+ // then
+ assertThat(reservationDay.isSpecialPromotionApplicable()).isEqualTo(expected);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/parser/InputParserTest.java b/src/test/java/christmas/parser/InputParserTest.java
new file mode 100644
index 0000000..6a6d205
--- /dev/null
+++ b/src/test/java/christmas/parser/InputParserTest.java
@@ -0,0 +1,65 @@
+package christmas.parser;
+
+import static christmas.view.input.constant.InputSymbolConstant.DAY_SYMBOL;
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.parser.InputParser;
+import java.util.Collections;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class InputParserTest {
+ private InputParser inputParser;
+
+ @BeforeEach
+ void setUp() {
+ inputParser = new InputParser();
+ }
+
+ @DisplayName("์์ฝ ๋ ์ง์ ๊ณต๋ฐฑ์ด ํฌํจ๋ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํ ๊ฐ์ ์ซ์ ํ์์ผ๋ก ๋ฐ๊พธ์ด ๋๋ ค์ค๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"1 0:10", "2 3:23", " 1 7:17", "3 1:31", " 1 :1",
+ " 3 0 :30"}, delimiter = ':')
+ void ์์ฝ_๋ ์ง์_๊ณต๋ฐฑ์ด_ํฌํจ๋_๊ฒฝ์ฐ_๊ณต๋ฐฑ์_์ ๊ฑฐํ_์ซ์๋ก_๋ฐํ(String userInput, int expected) {
+ assertThat(inputParser.parseReservationDay(userInput)).isEqualTo(expected);
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ๊ณต๋ฐฑ์ด ํฌํจ๋ ๊ฒฝ์ฐ, ๊ณต๋ฐฑ์ ์ ๊ฑฐํ ๊ฐ์ Mapํ์์ผ๋ก ๋ฐ๊พธ์ด ๋๋ ค์ค๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"ํ ํ ์ค - 1,ํํ์ค,1", " ํฐ ๋ณธ ์คํ
์ด ํฌ - 2,ํฐ๋ณธ์คํ
์ดํฌ,2", "์ ๋ก ์ฝ ๋ผ-10,์ ๋ก์ฝ๋ผ,10"}, delimiter = ',')
+ void ์ฃผ๋ฌธ_๋ด์ญ์_๊ณต๋ฐฑ์ด_ํฌํจ๋_๊ฒฝ์ฐ_๊ณต๋ฐฑ์_์ ๊ฑฐํ_๊ฐ์_๋งต์ผ๋ก_๋ฐํ(String userInput, String menuName, int menuCount) {
+ assertThat(inputParser.parseOrders(userInput))
+ .isEqualTo(Collections.singletonMap(menuName, menuCount));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ํฌํจ ๋ ์ง ์
๋ ฅ๊ฐ์ ๊ธธ์ด๊ฐ 2000๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ๊ณต๋ฐฑ_ํฌํจ_๋ ์ง_์
๋ ฅ๊ฐ์ด_2000๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์() {
+ String safeDayInput = "1" + " ".repeat(1000);
+ String illegalDayInput = "1" + " ".repeat(2000);
+ assertThat(inputParser.parseReservationDay(safeDayInput)).isEqualTo(1);
+ assertThatThrownBy(() -> inputParser.parseReservationDay(illegalDayInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_WITH_BLANKS_FORMAT.getFormat(),
+ DAY_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ํฌํจ ์ฃผ๋ฌธ๋ด์ญ ์
๋ ฅ๊ฐ์ ๊ธธ์ด๊ฐ 2000๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ๊ณต๋ฐฑ_ํฌํจ_์ฃผ๋ฌธ๋ด์ญ_์
๋ ฅ๊ฐ์ด_2000๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์() {
+ String userInput = "ํํ์ค-1" + " ".repeat(2000);
+ assertThatThrownBy(() -> inputParser.parseOrders(userInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_WITH_BLANKS_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/validator/DayInputValidatorTest.java b/src/test/java/christmas/validator/DayInputValidatorTest.java
new file mode 100644
index 0000000..b61452d
--- /dev/null
+++ b/src/test/java/christmas/validator/DayInputValidatorTest.java
@@ -0,0 +1,62 @@
+package christmas.validator;
+
+import static christmas.view.input.constant.InputSymbolConstant.DAY_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.DayInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.exception.message.DayInputExceptionMessage;
+import christmas.view.input.validator.DayInputValidator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class DayInputValidatorTest {
+ private DayInputValidator dayInputValidator;
+
+ @BeforeEach
+ void setUp() {
+ dayInputValidator = new DayInputValidator();
+ }
+
+ @DisplayName("์์ฝ ๋ ์ง๊ฐ ๋น์ด์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ์์ฝ_๋ ์ง๊ฐ_๋น์ด์๋_๊ฐ์ผ๋_์์ธ_๋ฐ์() {
+ assertThatThrownBy(() -> dayInputValidator.validate(""))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(),
+ DAY_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ์ ๊ฑฐ ํ ๋ ์ง ๊ธธ์ด๊ฐ 3๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {" 0 3 0 ", "0 0 2", "0 0 0 0 4"})
+ void ๊ณต๋ฐฑ_์ ๊ฑฐ_ํ_์์ฝ_๋ ์ง_์
๋ ฅ๊ฐ์ด_3๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> dayInputValidator.validate(userInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(),
+ DAY_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("์์ฝ ๋ ์ง๊ฐ ์ซ์ํ์์ด ์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"1a", "1s", "kw", "@!", "-", "a-", "dy", "!a"})
+ void ์์ฝ_๋ ์ง๊ฐ_์ซ์_ํ์์ด_์๋_์
๋ ฅ๊ฐ์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> dayInputValidator.validate(userInput))
+ .isInstanceOf(DayInputException.class)
+ .hasMessageContaining(DayInputExceptionMessage.NOT_NUMERIC_TYPE.getMessage());
+ }
+
+ @DisplayName("์์ฝ ๋ ์ง๊ฐ ์์๊ฐ ์๋ ์ซ์์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"-1", "-2", "-5", "-7", "-9", "-8", "-3", "-4"})
+ void ์์ฝ_๋ ์ง๊ฐ_์์๊ฐ_์๋_์ซ์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> dayInputValidator.validate(userInput))
+ .isInstanceOf(DayInputException.class)
+ .hasMessageContaining(DayInputExceptionMessage.NOT_POSITIVE.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/validator/MenuCountInputValidatorTest.java b/src/test/java/christmas/validator/MenuCountInputValidatorTest.java
new file mode 100644
index 0000000..3d6c818
--- /dev/null
+++ b/src/test/java/christmas/validator/MenuCountInputValidatorTest.java
@@ -0,0 +1,62 @@
+package christmas.validator;
+
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.exception.message.OrdersInputExceptionMessage;
+import christmas.view.input.validator.MenuCountInputValidator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class MenuCountInputValidatorTest {
+ private MenuCountInputValidator menuCountInputValidator;
+
+ @BeforeEach
+ void setUp() {
+ menuCountInputValidator = new MenuCountInputValidator();
+ }
+
+ @DisplayName("๋ฉ๋ด ๊ฐ์๊ฐ ๋น์ด์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ๋ฉ๋ด_๊ฐ์๊ฐ_๋น์ด์๋_๊ฐ์ผ๋_์์ธ_๋ฐ์() {
+ assertThatThrownBy(() -> menuCountInputValidator.validate(""))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ์ ๊ฑฐ ํ ๋ฉ๋ด ๊ฐ์๊ฐ 3๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {" 1 3 2 ", "4 3 2", "2 5 3 7 4"})
+ void ๊ณต๋ฐฑ_์ ๊ฑฐ_ํ_๋ฉ๋ด_๊ฐ์_์
๋ ฅ๊ฐ์ด_3๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> menuCountInputValidator.validate(userInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๋ฉ๋ด ๊ฐ์๊ฐ ์ซ์ํ์์ด ์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"a1", "s1", "wk", "!@", "-/", "-a", "yd", "a!"})
+ void ๋ฉ๋ด_๊ฐ์๊ฐ_์ซ์_ํ์์ด_์๋_์
๋ ฅ๊ฐ์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> menuCountInputValidator.validate(userInput))
+ .isInstanceOf(OrdersInputException.class)
+ .hasMessageContaining(OrdersInputExceptionMessage.NOT_NUMERIC_TYPE.getMessage());
+ }
+
+ @DisplayName("๋ฉ๋ด ๊ฐ์๊ฐ ์์๊ฐ ์๋ ์ซ์์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"-1", "-2", "-5", "-7", "-9", "-8", "-3", "-4"})
+ void ๋ฉ๋ด_๊ฐ์๊ฐ_์์๊ฐ_์๋_์ซ์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> menuCountInputValidator.validate(userInput))
+ .isInstanceOf(OrdersInputException.class)
+ .hasMessageContaining(OrdersInputExceptionMessage.NOT_POSITIVE.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/validator/MenuNameInputValidatorTest.java b/src/test/java/christmas/validator/MenuNameInputValidatorTest.java
new file mode 100644
index 0000000..ee7878a
--- /dev/null
+++ b/src/test/java/christmas/validator/MenuNameInputValidatorTest.java
@@ -0,0 +1,44 @@
+package christmas.validator;
+
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.validator.MenuNameInputValidator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class MenuNameInputValidatorTest {
+ private MenuNameInputValidator menuNameInputValidator;
+
+ @BeforeEach
+ void setUp() {
+ menuNameInputValidator = new MenuNameInputValidator();
+ }
+
+ @DisplayName("๋ฉ๋ด ์ด๋ฆ์ด ๋น์ด์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ๋ฉ๋ด_์ด๋ฆ์ด_๋น์ด์๋_๊ฐ์ผ๋_์์ธ_๋ฐ์() {
+ assertThatThrownBy(() -> menuNameInputValidator.validate(""))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ์ ๊ฑฐ ํ ๋ฉ๋ด ์ด๋ฆ ๊ธธ์ด๊ฐ 31๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {"ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ํํ์ค ",
+ "ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ ํฐ๋ณธ์คํ
์ดํฌ "
+ , "๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ ๋ ๋์์ธ "})
+ void ๊ณต๋ฐฑ_์ ๊ฑฐ_ํ_๋ฉ๋ด_์ด๋ฆ_๊ธธ์ด๊ฐ_31๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> menuNameInputValidator.validate(userInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/validator/OrderInputValidatorTest.java b/src/test/java/christmas/validator/OrderInputValidatorTest.java
new file mode 100644
index 0000000..19c1d3a
--- /dev/null
+++ b/src/test/java/christmas/validator/OrderInputValidatorTest.java
@@ -0,0 +1,65 @@
+package christmas.validator;
+
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.exception.message.OrdersInputExceptionMessage;
+import christmas.view.input.validator.OrderInputValidator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class OrderInputValidatorTest {
+ private OrderInputValidator orderInputValidator;
+
+ @BeforeEach
+ void setUp() {
+ orderInputValidator = new OrderInputValidator();
+ }
+
+ @DisplayName("์ฃผ๋ฌธ์ด ๋น์ด์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ์ฃผ๋ฌธ์ด_๋น์ด์๋_๊ฐ์ผ๋_์์ธ_๋ฐ์() {
+ assertThatThrownBy(() -> orderInputValidator.validate(""))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ์ ๊ฑฐ ํ ์ฃผ๋ฌธ ๊ธธ์ด๊ฐ 34๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @CsvSource(value = {"ํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์คํํ์ค-13",
+ "ํฐ๋ณธ์คํ
์ดํฌํฐ๋ณธ์คํ
์ดํฌํฐ๋ณธ์คํ
์ดํฌํฐ๋ณธ์คํ
์ดํฌํฐ๋ณธ์คํ
์ดํฌํฐ๋ณธ์คํ
์ดํฌ-14",
+ "์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ์์ด์คํฌ๋ฆผ-11"})
+ void ๊ณต๋ฐฑ_์ ๊ฑฐ_ํ_์ฃผ๋ฌธ_์
๋ ฅ๊ฐ์ด_34๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> orderInputValidator.validate(userInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ String.format(BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("์ฃผ๋ฌธ์ ๊ตฌ๋ถ์(-)๊ฐ ํฌํจ๋์ด ์์ง ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {"ํํ์ค1", "ํฐ๋ณธ์คํ
์ดํฌ~2", "๋ฐ๋นํ๋ฆฝ@12", "์์ด์คํฌ๋ฆผ", "์์ ์๋ฌ๋#3", "์ด์ฝ์ผ์ดํฌ*4", "์ ๋ก์ฝ๋ผ!!", "๋ ๋์์ธ$3"})
+ void ์ฃผ๋ฌธ_์
๋ ฅ๊ฐ์_๊ตฌ๋ถ์๊ฐ_ํฌํจ๋์ด_์์ง_์์ผ๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> orderInputValidator.validate(userInput))
+ .isInstanceOf(OrdersInputException.class)
+ .hasMessageContaining(OrdersInputExceptionMessage.INVALID_ORDER_FORMAT.getMessage());
+ }
+
+ @DisplayName("์ฃผ๋ฌธ์ ๋ง์ง๋ง ๋จ์ด๊ฐ ๊ตฌ๋ถ์(-)์ธ ๊ฒฝ์ฐ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {"ํํ์ค1-", "ํฐ๋ณธ์คํ
์ดํฌ-", "ํฐ๋ณธ์คํ
์ดํฌ-1-", "์์ ์๋ฌ๋-", "์ด์ฝ-์ผ์ดํฌ-"})
+ void ์ฃผ๋ฌธ_์
๋ ฅ๊ฐ์_๋ง์ง๋ง_๋จ์ด๊ฐ_๊ตฌ๋ถ์_์ด๋ฉด_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> orderInputValidator.validate(userInput))
+ .isInstanceOf(OrdersInputException.class)
+ .hasMessageContaining(OrdersInputExceptionMessage.EMPTY_MENU_COUNT.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/christmas/validator/OrdersInputValidatorTest.java b/src/test/java/christmas/validator/OrdersInputValidatorTest.java
new file mode 100644
index 0000000..c24df9d
--- /dev/null
+++ b/src/test/java/christmas/validator/OrdersInputValidatorTest.java
@@ -0,0 +1,57 @@
+package christmas.validator;
+
+import static christmas.view.input.constant.InputSymbolConstant.ORDER_SYMBOL;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import christmas.view.input.exception.BasicInputException;
+import christmas.view.input.exception.OrdersInputException;
+import christmas.view.input.exception.message.BasicInputExceptionMessageFormat;
+import christmas.view.input.exception.message.OrdersInputExceptionMessage;
+import christmas.view.input.validator.OrdersInputValidator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class OrdersInputValidatorTest {
+ private OrdersInputValidator ordersInputValidator;
+
+ @BeforeEach
+ void setUp() {
+ ordersInputValidator = new OrdersInputValidator();
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ด ๋น์ด์๋ ์
๋ ฅ๊ฐ์ผ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ์ฃผ๋ฌธ_๋ด์ญ์ด_๋น์ด์๋_๊ฐ์ผ๋_์์ธ_๋ฐ์() {
+ assertThatThrownBy(() -> ordersInputValidator.preValidate(""))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(String.format(BasicInputExceptionMessageFormat.EMPTY_FORMAT.getFormat(),
+ ORDER_SYMBOL.getSymbol()));
+ }
+
+ @DisplayName("๊ณต๋ฐฑ ์ ๊ฑฐ ํ ์ฃผ๋ฌธ ๋ด์ญ ๊ธธ์ด๊ฐ 1000๊ธ์ ์ด์์ด๋ฉด, ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @Test
+ void ๊ณต๋ฐฑ_์ ๊ฑฐ_ํ_์ฃผ๋ฌธ๋ด์ญ_์
๋ ฅ๊ฐ์ด_1000๊ธ์_์ด์์ด๋ฉด_์์ธ_๋ฐ์() {
+ String illegalOrdersInput = "์์ ์๋ฌ๋-1,".repeat(200);
+ assertThatThrownBy(() -> ordersInputValidator.preValidate(illegalOrdersInput))
+ .isInstanceOf(BasicInputException.class)
+ .hasMessageContaining(
+ BasicInputExceptionMessageFormat.TOO_LONG_FORMAT.getFormat(), ORDER_SYMBOL.getSymbol());
+ }
+
+ @DisplayName("์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ์ ๋, ์ค๋ณต๋ ์ฃผ๋ฌธ ๋ฉ๋ด๊ฐ ์กด์ฌํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "ํํ์ค-1,ํํ์ค-4",
+ "ํํ์ค-1,์ด์ฝ์ผ์ดํฌ-2,๋ ๋์์ธ-1,์ดํ์ธ-1,์์ด์คํฌ๋ฆผ-2,ํฐ๋ณธ์คํ
์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1",
+ "์ด์ฝ์ผ์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1,์ด์ฝ์ผ์ดํฌ-1",
+ "์์ ์๋ฌ๋-1,์์ก์ด์ํ-1,์ ๋ก์ฝ๋ผ-1,์ดํ์ธ-1,ํฌ๋ฆฌ์ค๋ง์คํ์คํ-2,ํด์ฐ๋ฌผํ์คํ-1,์์ ์๋ฌ๋-4"
+ })
+ void ์ค๋ณต_์ฃผ๋ฌธ_๋ฉ๋ด_์กด์ฌ_์_์์ธ_๋ฐ์(String userInput) {
+ assertThatThrownBy(() -> ordersInputValidator.postValidate(userInput))
+ .isInstanceOf(OrdersInputException.class)
+ .hasMessageContaining(OrdersInputExceptionMessage.DUPLICATED_MENUS.getMessage());
+ }
+}
\ No newline at end of file