diff --git a/build.gradle b/build.gradle index 5aa86890..9d087b14 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,22 @@ -apply plugin: 'java' -apply plugin: 'eclipse' - -version = '1.0.0' -sourceCompatibility = 1.8 +plugins { + id 'java' +} repositories { mavenCentral() + maven { url 'https://jitpack.io' } } dependencies { - testCompile('org.junit.jupiter:junit-jupiter:5.5.2') - testCompile('org.assertj:assertj-core:3.14.0') -} \ No newline at end of file + implementation 'com.github.woowacourse-projects:mission-utils:1.0.0' +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} + +test { + useJUnitPlatform() +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..184477de --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +# 구현할 기능 목록 + +- 간단한 포스(POS) 프로그램을 구현한다 + +## 1. 주문등록 + +### 메뉴 +- (메뉴 기본 정보) +- [x] 메뉴 번호 +- [x] 종류 +- [x] 이름 +- [x] 가격 + +### 테이블 +- (테이블 기본 정보) +- [x] 테이블 번호 + - [x] 테이블 당, 한 메뉴 최대 주문 가능 수량 99개 + - [x] 주문이 등록된 테이블은 결제가 이루어지기 전까지 테이블 목록에 별도로 표시 + +## 2. 결제 + +- 결제 유형에 따라 할인율이 달라진다 + - [x] 치킨 종류 메뉴의 수량의 합이 10개가 넘는 경우 10,000원씩 할인된다 + - ex) 10개는 10,000원 할인, 20개는 20,000원 할인 + - [x] 현금 결제는 5% 할인, 할인된 금액에서 한 번 더 할인이 가능 +- [x] 주문 혹은 결제가 불가능한 경우 그 이유를 보여 주고, 다시 주문 혹은 결제가 가능하도록 한다 +- [x] 최종 결제 금액을 보여준다 + +## 3. 프로그램 종료 diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..16e868ee --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Dfile.encoding=UTF-8 +org.gradle.console=plain diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cb..249e5832 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 44e7c4d1..8049c684 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708ff..a69d9cb6 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,101 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 0f8d5937..53a6b238 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,22 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +64,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index c5b1159b..ab587789 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ -rootProject.name = 'java-chicken' - +rootProject.name = 'java-chicken-2019' diff --git a/src/main/java/Application.java b/src/main/java/Application.java index ea0d34fd..e7447b12 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,21 +1,8 @@ -import domain.Menu; -import domain.MenuRepository; -import domain.Table; -import domain.TableRepository; -import view.InputView; -import view.OutputView; - -import java.util.List; +import controller.MenuController; public class Application { - // TODO 구현 진행 public static void main(String[] args) { - final List tables = TableRepository.tables(); - OutputView.printTables(tables); - - final int tableNumber = InputView.inputTableNumber(); - - final List menus = MenuRepository.menus(); - OutputView.printMenus(menus); + MenuController menuController = new MenuController(); + menuController.start(); } } diff --git a/src/main/java/controller/Command.java b/src/main/java/controller/Command.java new file mode 100644 index 00000000..f717a7fe --- /dev/null +++ b/src/main/java/controller/Command.java @@ -0,0 +1,29 @@ +package controller; + +import java.util.Arrays; + +public enum Command { + REGISTER(1, "주문등록"), + PAY(2, "결제하기"), + QUIT(3, "프로그램 종료"); + + private int choice; + private String explanation; + + Command(int choice, String explanation) { + this.choice = choice; + this.explanation = explanation; + } + + public static Command findCommandByNumber(int number) { + return Arrays.stream(values()) + .filter(command -> command.choice == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("1, 2, 3 중에 한 가지 기능만 선택할 수 있습니다.")); + } + + @Override + public String toString() { + return choice + " - " + explanation; + } +} diff --git a/src/main/java/controller/MenuController.java b/src/main/java/controller/MenuController.java new file mode 100644 index 00000000..07944fd3 --- /dev/null +++ b/src/main/java/controller/MenuController.java @@ -0,0 +1,60 @@ +package controller; + +import domain.order.OrderRepository; +import java.util.function.Function; +import java.util.function.Supplier; +import view.InputView; +import view.OutputView; + +public class MenuController { + + private boolean isRun = true; + + public void start() { + while (isRun) { + runPosController(); + } + } + + private void runPosController() { + OutputView.printMain(); + Command command = repeat(Command::findCommandByNumber, InputView::inputFunctionNumber); + chooseFunction(command); + } + + private void chooseFunction(Command command) { + if (command == Command.REGISTER) { + PosController.registerOrder(); + } + if (command == Command.QUIT) { + isRun = false; + } + if (command == Command.PAY) { + executePay(); + } + } + + private void executePay() { + try { + validateAnyOrderExist(); + PosController.payTable(); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + } + } + + private static void validateAnyOrderExist() { + if (!OrderRepository.hasAnyOrders()) { + throw new IllegalArgumentException("등록된 주문이 하나도 없습니다. 주문을 먼저 등록해주세요."); + } + } + + private static R repeat(Function object, Supplier reader) { + try { + return object.apply(reader.get()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return repeat(object, reader); + } + } +} diff --git a/src/main/java/controller/PosController.java b/src/main/java/controller/PosController.java new file mode 100644 index 00000000..8a0c1972 --- /dev/null +++ b/src/main/java/controller/PosController.java @@ -0,0 +1,83 @@ +package controller; + +import domain.menu.Menu; +import domain.menu.MenuRepository; +import domain.order.Order; +import domain.order.OrderRepository; +import domain.pay.Pay; +import domain.pay.PayMethod; +import domain.table.Table; +import domain.table.TableRepository; +import java.util.List; +import view.InputView; +import view.OutputView; + +public class PosController { + + private static final List
tables = TableRepository.tables(); + private static final List menus = MenuRepository.menus(); + + public static void registerOrder() { + Table table = getTable(); + Menu menu = getMenu(); + Order order = makeOrder(table, menu); + OrderRepository.add(order); + } + + public static void payTable() { + Pay pay = makePay(); + OutputView.printOrderList(pay); + OutputView.printPay(pay); + PayMethod payMethod = choosePayMethod(); + OutputView.printFinalCost(pay, payMethod); + OrderRepository.delete(pay); + } + + private static Table getTable() { + try { + OutputView.printTables(tables); + return TableRepository.findTableByNumber(InputView.inputTableNumber()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return getTable(); + } + } + + private static Menu getMenu() { + try { + OutputView.printMenus(menus); + return MenuRepository.findMenuByNumber(InputView.inputMenuChoice()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return getMenu(); + } + } + + private static Order makeOrder(Table table, Menu menu) { + try { + return new Order(table, menu, InputView.inputMenuAmount()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return makeOrder(table, menu); + } + } + + private static Pay makePay() { + try { + Table table = getTable(); + return new Pay(table); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return makePay(); + } + } + + private static PayMethod choosePayMethod() { + try { + return PayMethod.getMethodByNumber(InputView.inputPayMethod()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + return choosePayMethod(); + } + } +} diff --git a/src/main/java/domain/Menu.java b/src/main/java/domain/menu/Menu.java similarity index 63% rename from src/main/java/domain/Menu.java rename to src/main/java/domain/menu/Menu.java index 9f5a078e..07d9068e 100644 --- a/src/main/java/domain/Menu.java +++ b/src/main/java/domain/menu/Menu.java @@ -1,4 +1,6 @@ -package domain; +package domain.menu; + +import domain.Category; public class Menu { private final int number; @@ -17,4 +19,20 @@ public Menu(final int number, final String name, final Category category, final public String toString() { return category + " " + number + " - " + name + " : " + price + "원"; } + + public int getNumber() { + return number; + } + + public Category getCategory() { + return category; + } + + public int getPrice() { + return price; + } + + public String getName() { + return name; + } } diff --git a/src/main/java/domain/MenuRepository.java b/src/main/java/domain/menu/MenuRepository.java similarity index 70% rename from src/main/java/domain/MenuRepository.java rename to src/main/java/domain/menu/MenuRepository.java index fd3fe537..ba9e99ce 100644 --- a/src/main/java/domain/MenuRepository.java +++ b/src/main/java/domain/menu/MenuRepository.java @@ -1,5 +1,6 @@ -package domain; +package domain.menu; +import domain.Category; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -21,4 +22,11 @@ public class MenuRepository { public static List menus() { return Collections.unmodifiableList(menus); } + + public static Menu findMenuByNumber(int number) { + return menus.stream() + .filter(menu -> menu.getNumber() == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("등록되지 않은 메뉴입니다. 올바른 메뉴를 선택해주세요.")); + } } diff --git a/src/main/java/domain/order/Order.java b/src/main/java/domain/order/Order.java new file mode 100644 index 00000000..dd419f2a --- /dev/null +++ b/src/main/java/domain/order/Order.java @@ -0,0 +1,37 @@ +package domain.order; + +import domain.menu.Menu; +import domain.table.Table; + +public class Order { + public static final int AMOUNT_PER_MENU_UPPER_BOUND = 99; + private final Table table; + private final Menu menu; + private final int menuAmount; + + public Order(Table table, Menu menu, int menuAmount) throws IllegalArgumentException { + this.table = table; + this.menu = menu; + validateAmountOnMenu(table, menu, menuAmount); + this.menuAmount = menuAmount; + } + + private static void validateAmountOnMenu(Table table, Menu menu, int menuAmount) { + int orderedMenuAmount = OrderRepository.countMenuAmountByTable(table, menu); + if (orderedMenuAmount + menuAmount > AMOUNT_PER_MENU_UPPER_BOUND) { + throw new IllegalArgumentException("테이블 당 한 메뉴를 최대 99개까지만 주문할 수 있습니다."); + } + } + + public Table getTable() { + return table; + } + + public Menu getMenu() { + return menu; + } + + public int getMenuAmount() { + return menuAmount; + } +} diff --git a/src/main/java/domain/order/OrderRepository.java b/src/main/java/domain/order/OrderRepository.java new file mode 100644 index 00000000..8cdc1ed0 --- /dev/null +++ b/src/main/java/domain/order/OrderRepository.java @@ -0,0 +1,59 @@ +package domain.order; + +import domain.Category; +import domain.pay.Pay; +import domain.menu.Menu; +import domain.table.Table; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class OrderRepository { + private static final List orders = new ArrayList<>(); + + public static void add(Order order) { + orders.add(order); + } + + public static void delete(Pay pay) { + orders.removeAll(getOrdersByTable(pay.getTable())); + } + + public static void clear() { + orders.clear(); + } + + public static List getOrdersByTable(final Table table) { + return orders.stream() + .filter(order -> order.getTable().equals(table)) + .collect(Collectors.toUnmodifiableList()); + } + + public static int countMenuAmountByTable(final Table table, final Menu menu) { + return orders.stream() + .filter(order -> order.getTable().equals(table)) + .filter(order -> order.getMenu().equals(menu)) + .map(Order::getMenuAmount) + .mapToInt(menuAmount -> menuAmount) + .sum(); + } + + // TODO query를 효율적으로 보내도록 필드별 파라미터를 처음부터 설정할 수는? + public static int countMenuAmountByTableAndCategory(final Table table, final Category category) { + return orders.stream() + .filter(order -> order.getTable().equals(table)) + .filter(order -> order.getMenu().getCategory().equals(category)) + .map(Order::getMenuAmount) + .mapToInt(menuAmount -> menuAmount) + .sum(); + } + + public static boolean hasOrdersOnTable(final Table table) { + return orders.stream() + .anyMatch(order -> order.getTable().equals(table)); + } + + public static boolean hasAnyOrders() { + return !orders.isEmpty(); + } +} diff --git a/src/main/java/domain/pay/Pay.java b/src/main/java/domain/pay/Pay.java new file mode 100644 index 00000000..0f6b9914 --- /dev/null +++ b/src/main/java/domain/pay/Pay.java @@ -0,0 +1,81 @@ +package domain.pay; + +import domain.Category; +import domain.menu.Menu; +import domain.order.Order; +import domain.order.OrderRepository; +import domain.table.Table; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class Pay { + private static final int MENU_DISCOUNT_CRITERIA = 10; + private static final int DISCOUNT_PRICE = 10_000; + + private final Table table; + private final List orders; + + public Pay(Table table) throws IllegalArgumentException { + validateOrderOnTable(table); + this.table = table; + this.orders = OrderRepository.getOrdersByTable(table); + } + + private void validateOrderOnTable(Table table) { + if (!OrderRepository.hasOrdersOnTable(table)) { + throw new IllegalArgumentException("선택된 테이블은 주문 내역이 없어 결제할 수 없습니다."); + } + } + + // TODO 리팩터링 하기! + public Map aggregateMenus() { + Map menusCounts = new HashMap<>(); + for (Menu menu : getUniqueMenus()) { + menusCounts.put(menu, countMenusFormOrders(menu)); + } + return menusCounts; + } + + private Set getUniqueMenus() { + return orders.stream() + .map(Order::getMenu) + .collect(Collectors.toSet()); + } + + private int countMenusFormOrders(Menu menu) { + return orders.stream() + .filter(order -> order.getMenu().equals(menu)) + .map(Order::getMenuAmount) + .mapToInt(menuAmount -> menuAmount) + .sum(); + } + + public int getDiscountPrice(PayMethod payMethod) { + int cost = getOriginalTotalCost() - calculateMenuDiscount(); + return (int) calculatePayDiscount(cost, payMethod); + } + + private int getOriginalTotalCost() { + List orders = OrderRepository.getOrdersByTable(table); + return orders.stream() + .map(order -> order.getMenu().getPrice() * order.getMenuAmount()) + .mapToInt(cost -> cost) + .sum(); + } + + private int calculateMenuDiscount() { + int menuCount = OrderRepository.countMenuAmountByTableAndCategory(table, Category.CHICKEN); + return (menuCount / MENU_DISCOUNT_CRITERIA) * DISCOUNT_PRICE; + } + + private double calculatePayDiscount(int cost, PayMethod payMethod) { + return payMethod.getDiscountPrice(payMethod, cost); + } + + public Table getTable() { + return table; + } +} diff --git a/src/main/java/domain/pay/PayMethod.java b/src/main/java/domain/pay/PayMethod.java new file mode 100644 index 00000000..8e02709a --- /dev/null +++ b/src/main/java/domain/pay/PayMethod.java @@ -0,0 +1,27 @@ +package domain.pay; + +import java.util.Arrays; + +public enum PayMethod { + CREDIT_CARD(1, 1), + CASH(2, 0.95); + + private int choice; + private double discountPercentage; + + PayMethod(int choice, double discountPercentage) { + this.choice = choice; + this.discountPercentage = discountPercentage; + } + + public static PayMethod getMethodByNumber(int number) { + return Arrays.stream(PayMethod.values()) + .filter(payMethod -> payMethod.choice == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("결제 방법은 1또는 2중에 하나를 선택해야합니다.")); + } + + public double getDiscountPrice(PayMethod payMethod, int money) { + return payMethod.discountPercentage * money; + } +} diff --git a/src/main/java/domain/Table.java b/src/main/java/domain/table/Table.java similarity index 73% rename from src/main/java/domain/Table.java rename to src/main/java/domain/table/Table.java index 500c517e..dee2def1 100644 --- a/src/main/java/domain/Table.java +++ b/src/main/java/domain/table/Table.java @@ -1,4 +1,4 @@ -package domain; +package domain.table; public class Table { private final int number; @@ -11,4 +11,8 @@ public Table(final int number) { public String toString() { return Integer.toString(number); } + + public int getNumber() { + return number; + } } diff --git a/src/main/java/domain/TableRepository.java b/src/main/java/domain/table/TableRepository.java similarity index 56% rename from src/main/java/domain/TableRepository.java rename to src/main/java/domain/table/TableRepository.java index c9c791e2..c687101f 100644 --- a/src/main/java/domain/TableRepository.java +++ b/src/main/java/domain/table/TableRepository.java @@ -1,5 +1,6 @@ -package domain; +package domain.table; +import domain.table.Table; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -19,4 +20,11 @@ public class TableRepository { public static List
tables() { return Collections.unmodifiableList(tables); } + + public static Table findTableByNumber(int number) { + return tables.stream() + .filter(menu -> menu.getNumber() == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("등록되지 않은 테이블입니다. 올바른 테이블 번호를 입력해주세요.")); + } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index d5db24e2..bc0eb68d 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,12 +1,51 @@ package view; -import java.util.Scanner; +import camp.nextstep.edu.missionutils.Console; +import java.util.function.Supplier; public class InputView { - private static final Scanner scanner = new Scanner(System.in); - public static int inputTableNumber() { - System.out.println("## 주문할 테이블을 선택하세요."); - return scanner.nextInt(); + public static int inputFunctionNumber() throws IllegalArgumentException { + System.out.println("## 원하는 기능을 선택하세요."); + String input = breakOneLineAfterRead(Console::readLine); + return validateNumber(input); + } + + public static int inputTableNumber() throws IllegalArgumentException { + System.out.println("## 테이블을 선택하세요."); + String input = breakOneLineAfterRead(Console::readLine); + return validateNumber(input); + } + + public static int inputMenuChoice() throws IllegalArgumentException { + System.out.println("## 등록할 메뉴를 선택하세요."); + String input = breakOneLineAfterRead(Console::readLine); + return validateNumber(input); + } + + public static int inputMenuAmount() { + System.out.println("## 메뉴의 수량을 입력하세요."); + String input = breakOneLineAfterRead(Console::readLine); + return validateNumber(input); + } + + public static int inputPayMethod() { + System.out.println("## 신용 카드는 1번. 현금은 2번"); + String input = breakOneLineAfterRead(Console::readLine); + return validateNumber(input); + } + + private static int validateNumber(String input) { + try { + return Integer.parseInt(input.trim()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("숫자가 아닙니다. 올바른 숫자를 입력해주세요."); + } + } + + private static T breakOneLineAfterRead(Supplier reader) { + T input = reader.get(); + System.out.println(); + return input; } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index edb25cc4..6eeac72f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,27 +1,52 @@ package view; -import domain.Menu; -import domain.Table; +import controller.Command; +import domain.menu.Menu; +import domain.order.OrderRepository; +import domain.pay.Pay; +import domain.pay.PayMethod; +import domain.table.Table; import java.util.List; +import java.util.Map; public class OutputView { + public static final String ERROR = "[ERROR]"; private static final String TOP_LINE = "┌ ─ ┐"; private static final String TABLE_FORMAT = "| %s |"; - private static final String BOTTOM_LINE = "└ ─ ┘"; + private static final String BOTTOM_LINE_FORMAT = "└ %s ┘"; + private static final String UN_ORDERED_BOTTOM_LINE = "─"; + private static final String ORDERED_BOTTOM_LINE = "#"; + private static final String PAY_MESSAGE = "## %s번 테이블의 결제를 진행합니다."; + private static final String ORDER_LIST_FORMAT = "%s %s %s"; + + public static void printError(String message) { + System.out.println(ERROR + message); + System.out.println(); + } + + public static void printMain() { + System.out.println("## 메인화면"); + for (Command command : Command.values()) { + System.out.println(command.toString()); + } + System.out.println(); + } public static void printTables(final List
tables) { System.out.println("## 테이블 목록"); final int size = tables.size(); printLine(TOP_LINE, size); printTableNumbers(tables); - printLine(BOTTOM_LINE, size); + printBottomLine(tables); + System.out.println(); } public static void printMenus(final List menus) { for (final Menu menu : menus) { System.out.println(menu); } + System.out.println(); } private static void printLine(final String line, final int count) { @@ -31,10 +56,48 @@ private static void printLine(final String line, final int count) { System.out.println(); } + private static void printBottomLine(final List
tables) { + for (final Table table : tables) { + printTableBottom(table); + } + System.out.println(); + } + + private static void printTableBottom(Table table) { + if (OrderRepository.hasOrdersOnTable(table)) { + System.out.printf(BOTTOM_LINE_FORMAT, ORDERED_BOTTOM_LINE); + return; + } + System.out.printf(BOTTOM_LINE_FORMAT, UN_ORDERED_BOTTOM_LINE); + } + private static void printTableNumbers(final List
tables) { for (final Table table : tables) { System.out.printf(TABLE_FORMAT, table); } System.out.println(); } + + public static void printOrderList(final Pay pay) { + System.out.println("## 주문 내역"); + System.out.println("메뉴 수량 금액"); + Map menuCounts = pay.aggregateMenus(); + for (Menu menu : menuCounts.keySet()) { + System.out.printf(ORDER_LIST_FORMAT, menu.getName(), menuCounts.get(menu), + menu.getPrice() * menuCounts.get(menu)); + System.out.println(); + } + System.out.println(); + } + + public static void printPay(final Pay pay) { + System.out.printf(PAY_MESSAGE, pay.getTable().getNumber()); + System.out.println(); + } + + public static void printFinalCost(final Pay pay, PayMethod payMethod) { + System.out.println("## 최종 결제할 금액"); + System.out.println(pay.getDiscountPrice(payMethod) + "원"); + System.out.println(); + } } diff --git a/src/test/java/ApplicationTest.java b/src/test/java/ApplicationTest.java new file mode 100644 index 00000000..a7053c34 --- /dev/null +++ b/src/test/java/ApplicationTest.java @@ -0,0 +1,95 @@ +import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; +import static org.assertj.core.api.Assertions.*; + +import camp.nextstep.edu.missionutils.test.NsTest; +import domain.order.OrderRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ApplicationTest extends NsTest { + + private static final String ERROR_MESSAGE = "[ERROR]"; + + @BeforeEach + void setUp() { + OrderRepository.clear(); + } + + @Test + void 주문_등록_작동_테스트() { + assertSimpleTest( + () -> { + run("1", "1", "1", "1", "3"); + assertThat(output()).contains( + "## 원하는 기능을 선택하세요.", + "## 테이블 목록", + "┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐", + "| 1 || 2 || 3 || 5 || 6 || 8 |", + "└ ─ ┘└ ─ ┘└ ─ ┘└ ─ ┘└ ─ ┘└ ─ ┘", + "[치킨] 1 - 후라이드 : 16000원", + "[음료] 21 - 콜라 : 1000원", + "## 등록할 메뉴를 선택하세요.", + "## 메뉴의 수량을 입력하세요." + ); + } + ); + } + + @Test + void 주문_결제_작동_테스트() { + assertSimpleTest( + () -> { + run("1", "1", "1", "1", "1", "1", "21", "1", "2", "1", "1", "3"); + assertThat(output()).contains( + "## 테이블 목록", + "┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐┌ ─ ┐", + "| 1 || 2 || 3 || 5 || 6 || 8 |", + "└ # ┘└ ─ ┘└ ─ ┘└ ─ ┘└ ─ ┘└ ─ ┘", + "## 주문 내역", + "메뉴 수량 금액", + "후라이드 1 16000", + "콜라 1 1000", + "## 1번 테이블의 결제를 진행합니다.", + "## 신용 카드는 1번. 현금은 2번", + "## 최종 결제할 금액", + "17000원" + ); + } + ); + } + + @Test + void 주문_내역_없이_결제_테스트() { + assertSimpleTest( + () -> { + runException("2"); + assertThat(output()).contains(ERROR_MESSAGE); + } + ); + } + + @Test + void 주문_내역_없는_테이블_결제_테스트() { + assertSimpleTest( + () -> { + runException("1", "1", "1", "1", "2", "3"); + assertThat(output()).contains(ERROR_MESSAGE); + } + ); + } + + @Test + void 한_메뉴_최대_기준치_초과_주문_테스트() { + assertSimpleTest( + () -> { + runException("1", "1", "1", "85", "1", "1", "1", "15"); + assertThat(output()).contains(ERROR_MESSAGE); + } + ); + } + + @Override + protected void runMain() { + Application.main(new String[]{}); + } +} \ No newline at end of file diff --git a/src/test/java/domain/MenuRepositoryTest.java b/src/test/java/domain/MenuRepositoryTest.java new file mode 100644 index 00000000..007d727b --- /dev/null +++ b/src/test/java/domain/MenuRepositoryTest.java @@ -0,0 +1,26 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.menu.Menu; +import domain.menu.MenuRepository; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class MenuRepositoryTest { + + @Test + void 메뉴_번호_올바른_메뉴_반환() { + Assertions.assertThat(MenuRepository.findMenuByNumber(1)) + .isInstanceOf(Menu.class) + .satisfies(menu -> { + assertThat(menu.getName()).isEqualTo("후라이드"); + }); + } + + @Test + void 메뉴_번호_올바르지_않으면_에러_던지기() { + assertThatThrownBy(() -> MenuRepository.findMenuByNumber(100)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/domain/OrderRepositoryTest.java b/src/test/java/domain/OrderRepositoryTest.java new file mode 100644 index 00000000..057b5b73 --- /dev/null +++ b/src/test/java/domain/OrderRepositoryTest.java @@ -0,0 +1,73 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.menu.Menu; +import domain.menu.MenuRepository; +import domain.order.Order; +import domain.order.OrderRepository; +import domain.table.Table; +import domain.table.TableRepository; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class OrderRepositoryTest { + + static final Table table = TableRepository.findTableByNumber(1); + static final Menu menuOne = MenuRepository.findMenuByNumber(1); + static final Menu menuTwo = MenuRepository.findMenuByNumber(2); + static final Menu menuTwentyOne = MenuRepository.findMenuByNumber(21); + + + @BeforeAll + static void init() { + OrderRepository.add(new Order(table, menuOne, 5)); + OrderRepository.add(new Order(table, menuTwo, 6)); + OrderRepository.add(new Order(table, menuOne, 11)); + OrderRepository.add(new Order(table, menuTwentyOne, 7)); + } + + @org.junit.jupiter.api.Order(1) + @Test + void 테이블_메뉴_전체_주문_수량_추출_테스트() { + assertThat(OrderRepository.countMenuAmountByTable(table, menuOne)) + .isEqualTo(16); + } + + @org.junit.jupiter.api.Order(2) + @Test + void 테이블_특정_카테고리_메뉴_전체_주문_수량_추출_테스트() { + assertThat(OrderRepository.countMenuAmountByTableAndCategory(table, Category.CHICKEN)) + .isEqualTo(22); + } + + @org.junit.jupiter.api.Order(3) + @Test + void 테이블_주문_내역_있는_경우_확인_테스트() { + assertThat(OrderRepository.hasOrdersOnTable(table)) + .isTrue(); + } + + @org.junit.jupiter.api.Order(4) + @Test + void 테이블_주문_내역_없는_경우_확인_테스트() { + assertThat(OrderRepository.hasOrdersOnTable(TableRepository.findTableByNumber(3))) + .isFalse(); + } + + @org.junit.jupiter.api.Order(5) + @Test + void 전체_주문_내역_존재_여부_확인_테스트() { + // given + assertThat(OrderRepository.hasAnyOrders()) + .isTrue(); + // when + OrderRepository.clear(); + //then + assertThat(OrderRepository.hasAnyOrders()) + .isFalse(); + } +} \ No newline at end of file diff --git a/src/test/java/domain/OrderTest.java b/src/test/java/domain/OrderTest.java new file mode 100644 index 00000000..968977c6 --- /dev/null +++ b/src/test/java/domain/OrderTest.java @@ -0,0 +1,32 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.menu.Menu; +import domain.menu.MenuRepository; +import domain.order.Order; +import domain.order.OrderRepository; +import domain.table.Table; +import domain.table.TableRepository; +import org.junit.jupiter.api.Test; + +class OrderTest { + + @Test + void 테이블_최대_주문_가능_수량_에러_던지기() { + Table table = TableRepository.findTableByNumber(1); + Menu menu = MenuRepository.findMenuByNumber(1); + assertThatThrownBy(() -> new Order(table, menu, 100)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 합계_주문_최대_주문_가능_수량_에러_던지기() { + Table table = TableRepository.findTableByNumber(1); + Menu menu = MenuRepository.findMenuByNumber(1); + Order order = new Order(table, menu, 50); + OrderRepository.add(order); + assertThatThrownBy(() -> new Order(table, menu, 50)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PayMethodTest.java b/src/test/java/domain/PayMethodTest.java new file mode 100644 index 00000000..3a31331e --- /dev/null +++ b/src/test/java/domain/PayMethodTest.java @@ -0,0 +1,27 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.pay.PayMethod; +import org.junit.jupiter.api.Test; + +class PayMethodTest { + + @Test + void 올바르지_않은_숫자_에러_던지기() { + assertThatThrownBy(() -> PayMethod.getMethodByNumber(3)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 현금_결제_할인_테스트() { + assertThat(PayMethod.CASH.getDiscountPrice(PayMethod.CASH, 10_000)) + .isEqualTo(9_500); + } + + @Test + void 카드_결제_할인_없음_테스트() { + assertThat(PayMethod.CREDIT_CARD.getDiscountPrice(PayMethod.CREDIT_CARD, 10_000)) + .isEqualTo(10_000); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PayTest.java b/src/test/java/domain/PayTest.java new file mode 100644 index 00000000..7035fc2c --- /dev/null +++ b/src/test/java/domain/PayTest.java @@ -0,0 +1,53 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.menu.Menu; +import domain.menu.MenuRepository; +import domain.order.Order; +import domain.order.OrderRepository; +import domain.pay.Pay; +import domain.pay.PayMethod; +import domain.table.Table; +import domain.table.TableRepository; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class PayTest { + + static final Table table = TableRepository.findTableByNumber(1); + static final Menu menuOne = MenuRepository.findMenuByNumber(1); + static final Menu menuTwo = MenuRepository.findMenuByNumber(2); + static final Menu menuTwentyOne = MenuRepository.findMenuByNumber(21); + + static Pay pay; + + @BeforeAll + static void init() { + OrderRepository.add(new Order(table, menuOne, 5)); + OrderRepository.add(new Order(table, menuTwo, 6)); + OrderRepository.add(new Order(table, menuOne, 11)); + OrderRepository.add(new Order(table, menuTwentyOne, 7)); + pay = new Pay(table); + } + + @Test + void 주문_내역_없는_테이블_결제_에러_던지기() { + assertThatThrownBy(() -> new Pay(TableRepository.findTableByNumber(3))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 테이블_전체_주문_내역_반환_테스트() { + assertThat(pay.aggregateMenus()) + .containsOnlyKeys(menuOne, menuTwo, menuTwentyOne) + .containsValues(16, 6, 7); + } + + @Test + void 치킨_메뉴_할인_가격_테스트() { + assertThat(pay.getDiscountPrice(PayMethod.CREDIT_CARD)) + .isEqualTo((menuOne.getPrice() * 16) + (menuTwo.getPrice() * 6) + + (menuTwentyOne.getPrice() * 7) - 20_000); + } +} \ No newline at end of file diff --git a/src/test/java/domain/TableRepositoryTest.java b/src/test/java/domain/TableRepositoryTest.java new file mode 100644 index 00000000..fb3b09b9 --- /dev/null +++ b/src/test/java/domain/TableRepositoryTest.java @@ -0,0 +1,26 @@ +package domain; + +import static org.assertj.core.api.Assertions.*; + +import domain.table.Table; +import domain.table.TableRepository; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class TableRepositoryTest { + + @Test + void 테이블_번호_올바른_테이블_반환() { + Assertions.assertThat(TableRepository.findTableByNumber(1)) + .isInstanceOf(Table.class) + .satisfies(table -> { + assertThat(table.getNumber()).isEqualTo(1); + }); + } + + @Test + void 테이블_번호_올바르지_않으면_에러_던지기() { + assertThatThrownBy(() -> TableRepository.findTableByNumber(100)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt deleted file mode 100644 index e69de29b..00000000