From dc2e002d5313f4a75862dce3e6c9c86f354795fe Mon Sep 17 00:00:00 2001 From: viiviii Date: Fri, 6 May 2022 13:20:53 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20Only=20boolean=20?= =?UTF-8?q?(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Boolean 인수만 지원하던 초기 버전 / 목록 14-9 * test: Boolean 인수만 지원하던 초기 버전 테스트 추가 * :truck: Args 클래스 패키지 안으로 이동 --- src/main/java/chapter14/Application.java | 17 +++ src/main/java/chapter14/args/Args.java | 121 ++++++++++++++++++ src/test/java/chapter14/ApplicationTest.java | 37 ++++++ src/test/java/chapter14/MainMethodTest.java | 39 ++++++ src/test/java/chapter14/args/ArgsTest.java | 123 +++++++++++++++++++ 5 files changed, 337 insertions(+) create mode 100644 src/main/java/chapter14/Application.java create mode 100644 src/main/java/chapter14/args/Args.java create mode 100644 src/test/java/chapter14/ApplicationTest.java create mode 100644 src/test/java/chapter14/MainMethodTest.java create mode 100644 src/test/java/chapter14/args/ArgsTest.java diff --git a/src/main/java/chapter14/Application.java b/src/main/java/chapter14/Application.java new file mode 100644 index 0000000..e5bf584 --- /dev/null +++ b/src/main/java/chapter14/Application.java @@ -0,0 +1,17 @@ +package chapter14; + +import chapter14.args.Args; + +class Application { + + public static void main(String[] args) { + Args arg = new Args("l", args); + boolean logging = arg.getBoolean('l'); + executeApplication(logging); + } + + // stub + private static void executeApplication(boolean logging) { + System.out.printf("logging: %b\n", logging); + } +} diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java new file mode 100644 index 0000000..6f75c8e --- /dev/null +++ b/src/main/java/chapter14/args/Args.java @@ -0,0 +1,121 @@ +package chapter14.args; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public class Args { + private String scheme; + private String[] args; + private boolean valid; + private Set unexpectedArguments = new TreeSet<>(); + private Map booleanArgs = new HashMap<>(); + private int numberOfArguments = 0; + + public Args(String schema, String[] args) { + this.scheme = schema; + this.args = args; + valid = parse(); + } + + public boolean isValid() { + return valid; + } + + private boolean parse() { + if (scheme.length() == 0 && args.length == 0) + return true; + parseSchema(); + parseArguments(); + return unexpectedArguments.size() == 0; + } + + private boolean parseSchema() { + for (String element : scheme.split(",")) { + parseSchemaElement(element); + } + return true; + } + + private void parseSchemaElement(String element) { + if (element.length() == 1) { + parseBooleanSchemeElement(element); + } + } + + private void parseBooleanSchemeElement(String element) { + char c = element.charAt(0); + if (Character.isLetter(c)) { + booleanArgs.put(c, false); + } + } + + private boolean parseArguments() { + for (String arg : args) { + parseArgument(arg); + } + return true; + } + + private void parseArgument(String arg) { + if (arg.startsWith("-")) + parseElements(arg); + } + + private void parseElements(String arg) { + for (int i = 1; i < arg.length(); i++) { + parseElement(arg.charAt(i)); + } + } + + private void parseElement(char argChar) { + if (isBoolean(argChar)) { + numberOfArguments++; + setBooleanArg(argChar, true); + } else { + unexpectedArguments.add(argChar); + } + } + + private void setBooleanArg(char argChar, boolean value) { + booleanArgs.put(argChar, value); + } + + private boolean isBoolean(char argChar) { + return booleanArgs.containsKey(argChar); + } + + public int cardinality() { + return numberOfArguments; + } + + public String usage() { + if (scheme.length() > 0) + return "-[" + scheme + "]"; + else + return ""; + } + + public String errorMessage() { + if (unexpectedArguments.size() > 0) { + return unexpectedArgumentMessage(); + } else { + return ""; + } + } + + private String unexpectedArgumentMessage() { + StringBuffer message = new StringBuffer("Argument(s) -"); + for (char c : unexpectedArguments) { + message.append(c); + } + message.append(" unexpected."); + + return message.toString(); + } + + public boolean getBoolean(char arg) { + return booleanArgs.get(arg); + } +} diff --git a/src/test/java/chapter14/ApplicationTest.java b/src/test/java/chapter14/ApplicationTest.java new file mode 100644 index 0000000..101aeb8 --- /dev/null +++ b/src/test/java/chapter14/ApplicationTest.java @@ -0,0 +1,37 @@ +package chapter14; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ApplicationTest extends MainMethodTest { + + @Test + void validBooleanArgs() { + //given + String arg = "-l"; + + //when + runMain(arg); + + //then + assertThat(output()).contains("logging: true"); + } + + @Test + void invalidBooleanArgs() { + //given + String notStartWithHyphen = "l"; + + //when + runMain(notStartWithHyphen); + + //then + assertThat(output()).contains("logging: false"); + } + + @Override + protected void runMain(String... args) { + Application.main(args); + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/MainMethodTest.java b/src/test/java/chapter14/MainMethodTest.java new file mode 100644 index 0000000..e0bf861 --- /dev/null +++ b/src/test/java/chapter14/MainMethodTest.java @@ -0,0 +1,39 @@ +package chapter14; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +abstract class MainMethodTest { + private final PrintStream standardOut = System.out; + private OutputStream captor; + + @BeforeEach + protected final void init() { + setSystemOutToMyPrintStreamForCaptor(); + } + + private void setSystemOutToMyPrintStreamForCaptor() { + captor = new ByteArrayOutputStream(); + System.setOut(new PrintStream(captor)); + } + + @AfterEach + protected final void printOutput() { + setSystemOutToStandard(); + System.out.println(output()); + } + + private void setSystemOutToStandard() { + System.setOut(standardOut); + } + + protected final String output() { + return captor.toString().trim(); + } + + protected abstract void runMain(String... args); +} diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java new file mode 100644 index 0000000..f1a2e4c --- /dev/null +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -0,0 +1,123 @@ +package chapter14.args; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ArgsTest { + + @DisplayName("scheme와 arguments가 없는 경우") + @Test + void noSchemaAndArguments() { + //given + String schema = ""; + String[] arguments = new String[0]; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + } + + @DisplayName("scheme가 없고 argument가 1개 있는 경우") + @Test + void noSchemaButWithOneArgument() { + //given + String schema = ""; + String[] arguments = new String[]{"-x"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isZero(); + assertThat(args.errorMessage()).isEqualTo("Argument(s) -x unexpected."); + } + + @DisplayName("scheme가 없고 argument가 여러 개 있는 경우") + @Test + void noSchemaButWithMultipleArguments() { + //given + String schema = ""; + String[] arguments = new String[]{"-x", "-y"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isZero(); + assertThat(args.errorMessage()).isEqualTo("Argument(s) -xy unexpected."); + } + + @DisplayName("boolean 값이 없는 경우") + @Test + void simpleBooleanNotPresent() { + //given + String schema = "x"; + String[] arguments = new String[]{}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + assertThat(args.getBoolean('x')).isFalse(); + } + + @DisplayName("boolean 값이 있는 경우") + @Test + void simpleBooleanPresent() { + //given + String schema = "x"; + String[] arguments = new String[]{"-x"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isOne(); + assertThat(args.getBoolean('x')).isTrue(); + } + + @DisplayName("boolean 값이 여러 개 있는 경우") + @Test + void simpleBooleanMultiplePresent() { + //given + String schema = "x,y"; + String[] arguments = new String[]{"-x", "-y"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isEqualTo(2); + assertThat(args.getBoolean('x')).isTrue(); + assertThat(args.getBoolean('y')).isTrue(); + } + + @DisplayName("boolean 값이 여러 개 중 하나만 있는 경우") + @Test + void simpleBooleanOnlyOnePresent() { + //given + String schema = "x,y,z"; + String[] arguments = new String[]{"-z"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isOne(); + assertThat(args.getBoolean('x')).isFalse(); + assertThat(args.getBoolean('y')).isFalse(); + assertThat(args.getBoolean('z')).isTrue(); + } +} \ No newline at end of file From 2bf8e175489b8fa81faf3751515af3fdd6b6a94d Mon Sep 17 00:00:00 2001 From: viiviii Date: Fri, 6 May 2022 15:54:59 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20Add=20String=20(#?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: String 인수 유형 추가 버전 / 목록 14-10 * test: String 인수 유형 추가 버전 테스트 추가 * fix: schema 오타 수정 --- src/main/java/chapter14/Application.java | 17 +- src/main/java/chapter14/args/Args.java | 155 ++++++++++++++----- src/test/java/chapter14/ApplicationTest.java | 40 ++++- src/test/java/chapter14/args/ArgsTest.java | 128 +++++++++++++-- 4 files changed, 273 insertions(+), 67 deletions(-) diff --git a/src/main/java/chapter14/Application.java b/src/main/java/chapter14/Application.java index e5bf584..e01e518 100644 --- a/src/main/java/chapter14/Application.java +++ b/src/main/java/chapter14/Application.java @@ -2,16 +2,23 @@ import chapter14.args.Args; +import java.text.ParseException; + class Application { public static void main(String[] args) { - Args arg = new Args("l", args); - boolean logging = arg.getBoolean('l'); - executeApplication(logging); + try { + Args arg = new Args("l,d*", args); + boolean logging = arg.getBoolean('l'); + String directory = arg.getString('d'); + executeApplication(logging, directory); + } catch (ParseException e) { + System.out.printf("Parse error: %s\n", e.getMessage()); + } } // stub - private static void executeApplication(boolean logging) { - System.out.printf("logging: %b\n", logging); + private static void executeApplication(boolean logging, String directory) { + System.out.printf("logging: %b, directory: %s\n", logging, directory); } } diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index 6f75c8e..add22cc 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -1,58 +1,85 @@ package chapter14.args; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.text.ParseException; +import java.util.*; public class Args { - private String scheme; + private String schema; private String[] args; - private boolean valid; + private boolean valid = true; private Set unexpectedArguments = new TreeSet<>(); private Map booleanArgs = new HashMap<>(); - private int numberOfArguments = 0; + private Map stringArgs = new HashMap<>(); + private Set argsFound = new HashSet<>(); + private int currentArgument; + private char errorArgument = '\0'; - public Args(String schema, String[] args) { - this.scheme = schema; - this.args = args; - valid = parse(); + enum ErrorCode { + OK, MISSING_STRING } - public boolean isValid() { - return valid; + private ErrorCode errorCode = ErrorCode.OK; + + public Args(String schema, String[] args) throws ParseException { + this.schema = schema; + this.args = args; + valid = parse(); } - private boolean parse() { - if (scheme.length() == 0 && args.length == 0) + private boolean parse() throws ParseException { + if (schema.length() == 0 && args.length == 0) return true; parseSchema(); parseArguments(); - return unexpectedArguments.size() == 0; + return valid; } - private boolean parseSchema() { - for (String element : scheme.split(",")) { - parseSchemaElement(element); + private boolean parseSchema() throws ParseException { + for (String element : schema.split(",")) { + if (element.length() > 0) { + String trimmedElement = element.trim(); + parseSchemaElement(trimmedElement); + } } return true; } - private void parseSchemaElement(String element) { - if (element.length() == 1) { - parseBooleanSchemeElement(element); - } + private void parseSchemaElement(String element) throws ParseException { + char elementId = element.charAt(0); + String elementTail = element.substring(1); + validateSchemaElementId(elementId); + if (isBooleanSchemaElement(elementTail)) + parseBooleanSchemaElement(elementId); + else if (isStringSchemaElement(elementTail)) + parseStringSchemaElement(elementId); } - private void parseBooleanSchemeElement(String element) { - char c = element.charAt(0); - if (Character.isLetter(c)) { - booleanArgs.put(c, false); + private void validateSchemaElementId(char elementId) throws ParseException { + if (!Character.isLetter(elementId)) { + throw new ParseException( + "Bad character: " + elementId + " in Args format: " + schema, 0); } } + private void parseStringSchemaElement(char elementId) { + stringArgs.put(elementId, ""); + } + + private boolean isStringSchemaElement(String elementTail) { + return elementTail.equals("*"); + } + + private boolean isBooleanSchemaElement(String elementTail) { + return elementTail.length() == 0; + } + + private void parseBooleanSchemaElement(char elementId) { + booleanArgs.put(elementId, false); + } + private boolean parseArguments() { - for (String arg : args) { + for (currentArgument = 0; currentArgument < args.length; currentArgument++) { + String arg = args[currentArgument]; parseArgument(arg); } return true; @@ -70,14 +97,41 @@ private void parseElements(String arg) { } private void parseElement(char argChar) { - if (isBoolean(argChar)) { - numberOfArguments++; - setBooleanArg(argChar, true); - } else { + if (setArgument(argChar)) + argsFound.add(argChar); + else { unexpectedArguments.add(argChar); + valid = false; } } + private boolean setArgument(char argChar) { + boolean set = true; + if (isBoolean(argChar)) + setBooleanArg(argChar, true); + else if (isString(argChar)) + setStringArg(argChar, ""); + else + set = false; + + return set; + } + + private void setStringArg(char argChar, String s) { + currentArgument++; + try { + stringArgs.put(argChar, args[currentArgument]); + } catch (ArrayIndexOutOfBoundsException e) { + valid = false; + errorArgument = argChar; + errorCode = ErrorCode.MISSING_STRING; + } + } + + private boolean isString(char argChar) { + return stringArgs.containsKey(argChar); + } + private void setBooleanArg(char argChar, boolean value) { booleanArgs.put(argChar, value); } @@ -87,20 +141,27 @@ private boolean isBoolean(char argChar) { } public int cardinality() { - return numberOfArguments; + return argsFound.size(); } public String usage() { - if (scheme.length() > 0) - return "-[" + scheme + "]"; + if (schema.length() > 0) + return "-[" + schema + "]"; else return ""; } - public String errorMessage() { + public String errorMessage() throws Exception { if (unexpectedArguments.size() > 0) { return unexpectedArgumentMessage(); } else { + switch (errorCode) { + case MISSING_STRING: + return String.format("Could not find string parameter for -%c.", + errorArgument); + case OK: + throw new Exception("TILT: Should not get here."); + } return ""; } } @@ -116,6 +177,26 @@ private String unexpectedArgumentMessage() { } public boolean getBoolean(char arg) { - return booleanArgs.get(arg); + return falseIfNull(booleanArgs.get(arg)); + } + + private boolean falseIfNull(Boolean b) { + return b == null ? false : b; + } + + public String getString(char arg) { + return blankIfNull(stringArgs.get(arg)); + } + + private String blankIfNull(String s) { + return s == null ? "" : s; + } + + public boolean has(char arg) { + return argsFound.contains(arg); + } + + public boolean isValid() { + return valid; } } diff --git a/src/test/java/chapter14/ApplicationTest.java b/src/test/java/chapter14/ApplicationTest.java index 101aeb8..680ed1c 100644 --- a/src/test/java/chapter14/ApplicationTest.java +++ b/src/test/java/chapter14/ApplicationTest.java @@ -7,27 +7,51 @@ class ApplicationTest extends MainMethodTest { @Test - void validBooleanArgs() { + void booleanArguments() { //given - String arg = "-l"; + String[] args = new String[]{"-l"}; //when - runMain(arg); + runMain(args); //then - assertThat(output()).contains("logging: true"); + assertThat(output()).contains("true"); } @Test - void invalidBooleanArgs() { + void stringArguments() { //given - String notStartWithHyphen = "l"; + String[] args = new String[]{"-d", "root"}; //when - runMain(notStartWithHyphen); + runMain(args); //then - assertThat(output()).contains("logging: false"); + assertThat(output()).contains("root"); + } + + @Test + void allArgumentsPresent() { + //given + String[] args = new String[]{"-l", "-d", "user"}; + + //when + runMain(args); + + //then + assertThat(output()).isEqualTo("logging: true, directory: user"); + } + + @Test + void noArguments() { + //given + String[] args = new String[0]; + + //when + runMain(args); + + //then + assertThat(output()).isEqualTo("logging: false, directory:"); } @Override diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index f1a2e4c..d62504b 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -3,13 +3,16 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.text.ParseException; + import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; class ArgsTest { - @DisplayName("scheme와 arguments가 없는 경우") + @DisplayName("schema와 arguments가 없는 경우") @Test - void noSchemaAndArguments() { + void noSchemaAndArguments() throws Exception { //given String schema = ""; String[] arguments = new String[0]; @@ -22,9 +25,9 @@ void noSchemaAndArguments() { assertThat(args.cardinality()).isZero(); } - @DisplayName("scheme가 없고 argument가 1개 있는 경우") + @DisplayName("schema가 없고 argument가 1개 있는 경우") @Test - void noSchemaButWithOneArgument() { + void noSchemaButWithOneArgument() throws Exception { //given String schema = ""; String[] arguments = new String[]{"-x"}; @@ -38,9 +41,9 @@ void noSchemaButWithOneArgument() { assertThat(args.errorMessage()).isEqualTo("Argument(s) -x unexpected."); } - @DisplayName("scheme가 없고 argument가 여러 개 있는 경우") + @DisplayName("schema가 없고 argument가 여러 개 있는 경우") @Test - void noSchemaButWithMultipleArguments() { + void noSchemaButWithMultipleArguments() throws Exception { //given String schema = ""; String[] arguments = new String[]{"-x", "-y"}; @@ -56,7 +59,7 @@ void noSchemaButWithMultipleArguments() { @DisplayName("boolean 값이 없는 경우") @Test - void simpleBooleanNotPresent() { + void simpleBooleanNotPresent() throws Exception { //given String schema = "x"; String[] arguments = new String[]{}; @@ -72,7 +75,7 @@ void simpleBooleanNotPresent() { @DisplayName("boolean 값이 있는 경우") @Test - void simpleBooleanPresent() { + void simpleBooleanPresent() throws Exception { //given String schema = "x"; String[] arguments = new String[]{"-x"}; @@ -88,9 +91,9 @@ void simpleBooleanPresent() { @DisplayName("boolean 값이 여러 개 있는 경우") @Test - void simpleBooleanMultiplePresent() { + void simpleBooleanMultiplePresent() throws Exception { //given - String schema = "x,y"; + String schema = "x,y,z"; String[] arguments = new String[]{"-x", "-y"}; //when @@ -99,16 +102,37 @@ void simpleBooleanMultiplePresent() { //then assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isEqualTo(2); + assertThat(args.has('x')).isTrue(); + assertThat(args.has('y')).isTrue(); + assertThat(args.has('z')).isFalse(); assertThat(args.getBoolean('x')).isTrue(); assertThat(args.getBoolean('y')).isTrue(); + assertThat(args.getBoolean('z')).isFalse(); } - @DisplayName("boolean 값이 여러 개 중 하나만 있는 경우") + @DisplayName("String 값이 없는 경우") @Test - void simpleBooleanOnlyOnePresent() { + void simpleStringNotPresent() throws Exception { //given - String schema = "x,y,z"; - String[] arguments = new String[]{"-z"}; + String schema = "x*"; + String[] arguments = new String[]{}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getString('x')).isEmpty(); + } + + @DisplayName("String 값이 있는 경우") + @Test + void simpleStringPresent() throws Exception { + //given + String schema = "x*"; + String[] arguments = new String[]{"-x", "param"}; //when Args args = new Args(schema, arguments); @@ -116,8 +140,78 @@ void simpleBooleanOnlyOnePresent() { //then assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isOne(); - assertThat(args.getBoolean('x')).isFalse(); - assertThat(args.getBoolean('y')).isFalse(); - assertThat(args.getBoolean('z')).isTrue(); + assertThat(args.has('x')).isTrue(); + assertThat(args.getString('x')).isEqualTo("param"); + } + + @DisplayName("String 값이 여러 개 있는 경우") + @Test + void simpleStringMultiplePresent() throws Exception { + //given + String schema = "x*,y*,z*"; + String[] arguments = new String[]{"-x", "param1", "-y", "param2"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isEqualTo(2); + assertThat(args.has('x')).isTrue(); + assertThat(args.has('y')).isTrue(); + assertThat(args.has('z')).isFalse(); + assertThat(args.getString('x')).isEqualTo("param1"); + assertThat(args.getString('y')).isEqualTo("param2"); + assertThat(args.getString('z')).isEmpty(); + } + + @DisplayName("String Argument 값이 없는 경우") + @Test + void missingStringArgument() throws Exception { + //given + String schema = "x*"; + String[] arguments = new String[]{"-x"}; // missing + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isOne(); + assertThat(args.has('x')).isTrue(); + assertThat(args.getString('x')).isEmpty(); + assertThat(args.errorMessage()).isEqualTo("Could not find string parameter for -x."); + } + + @DisplayName("Schema의 ElementId가 문자가 아니면 ParseException이 발생한다") + @Test + void throwParseExceptionWhenInvalidSchemaElementId() { + //given + String containsNonLetterElementId = "l,d*,#"; + String[] arguments = new String[0]; + + //when + Exception exception = catchException(() -> new Args(containsNonLetterElementId, arguments)); + + //then + assertThat(exception) + .isInstanceOf(ParseException.class) + .hasMessage("Bad character: # in Args format: l,d*,#"); + } + + @DisplayName("유효한 args에서 errorMessage를 조회할 경우 Excpetion이 발생한다") + @Test + void errorMessageThrowExceptionWhenErrorCodeIsOK() throws Exception { + //given + Args args = new Args("x", new String[]{"-x"}); + assertThat(args.isValid()).isTrue(); + + //when + Exception exception = catchException(args::errorMessage); + + //then + assertThat(exception) + .isInstanceOf(Exception.class) + .hasMessage("TILT: Should not get here."); } } \ No newline at end of file From d59d861a0d2e9b72109aefd31d333887c611be16 Mon Sep 17 00:00:00 2001 From: viiviii Date: Wed, 11 May 2022 18:32:33 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20Add=20Integer=20(?= =?UTF-8?q?&before=20refactoring=20ver)=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: int 유형 추가 * test: int 유형 테스트 추가 * test: 기존 테스트를 책에 나온 테스트와 메서드명 및 순서 맞춤 * feat: 유효하지 않은 Schema element를 예외 처리 * refactor: 책과 순서 맞춤 및 메서드명 변경 등 작은 리팩토링 * refactor: UNEXPECTED_ARGUMENT errorCode 추가하여 리팩토링 * feat: ArgsException 추가 * refactor: errorArgument -> errorArgumentId로 변수명 변경 --- src/main/java/chapter14/Application.java | 9 +- src/main/java/chapter14/args/Args.java | 139 +++++++++++++----- src/test/java/chapter14/ApplicationTest.java | 18 ++- src/test/java/chapter14/args/ArgsTest.java | 146 ++++++++++++++++--- 4 files changed, 246 insertions(+), 66 deletions(-) diff --git a/src/main/java/chapter14/Application.java b/src/main/java/chapter14/Application.java index e01e518..ca77f84 100644 --- a/src/main/java/chapter14/Application.java +++ b/src/main/java/chapter14/Application.java @@ -8,17 +8,18 @@ class Application { public static void main(String[] args) { try { - Args arg = new Args("l,d*", args); + Args arg = new Args("l,p#,d*", args); boolean logging = arg.getBoolean('l'); + int port = arg.getInt('p'); String directory = arg.getString('d'); - executeApplication(logging, directory); + executeApplication(logging, port, directory); } catch (ParseException e) { System.out.printf("Parse error: %s\n", e.getMessage()); } } // stub - private static void executeApplication(boolean logging, String directory) { - System.out.printf("logging: %b, directory: %s\n", logging, directory); + private static void executeApplication(boolean logging, int port, String directory) { + System.out.printf("logging: %b, port: %d, directory: %s\n", logging, port, directory); } } diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index add22cc..1f4429a 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -10,16 +10,17 @@ public class Args { private Set unexpectedArguments = new TreeSet<>(); private Map booleanArgs = new HashMap<>(); private Map stringArgs = new HashMap<>(); + private Map intArgs = new HashMap<>(); private Set argsFound = new HashSet<>(); private int currentArgument; - private char errorArgument = '\0'; + private char errorArgumentId = '\0'; + private String errorParameter = "TILT"; + private ErrorCode errorCode = ErrorCode.OK; enum ErrorCode { - OK, MISSING_STRING + OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT } - private ErrorCode errorCode = ErrorCode.OK; - public Args(String schema, String[] args) throws ParseException { this.schema = schema; this.args = args; @@ -30,7 +31,10 @@ private boolean parse() throws ParseException { if (schema.length() == 0 && args.length == 0) return true; parseSchema(); - parseArguments(); + try { + parseArguments(); + } catch (ArgsException e) { + } return valid; } @@ -52,6 +56,13 @@ private void parseSchemaElement(String element) throws ParseException { parseBooleanSchemaElement(elementId); else if (isStringSchemaElement(elementTail)) parseStringSchemaElement(elementId); + else if (isIntegerSchemaElement(elementTail)) + parseIntegerSchemaElement(elementId); + else { + throw new ParseException( + String.format("Argument: %c has invalid format: %s.", + elementId, elementTail), 0); + } } private void validateSchemaElementId(char elementId) throws ParseException { @@ -61,6 +72,14 @@ private void validateSchemaElementId(char elementId) throws ParseException { } } + private void parseBooleanSchemaElement(char elementId) { + booleanArgs.put(elementId, false); + } + + private void parseIntegerSchemaElement(char elementId) { + intArgs.put(elementId, 0); + } + private void parseStringSchemaElement(char elementId) { stringArgs.put(elementId, ""); } @@ -73,11 +92,11 @@ private boolean isBooleanSchemaElement(String elementTail) { return elementTail.length() == 0; } - private void parseBooleanSchemaElement(char elementId) { - booleanArgs.put(elementId, false); + private boolean isIntegerSchemaElement(String elementTail) { + return elementTail.equals("#"); } - private boolean parseArguments() { + private boolean parseArguments() throws ArgsException { for (currentArgument = 0; currentArgument < args.length; currentArgument++) { String arg = args[currentArgument]; parseArgument(arg); @@ -85,50 +104,76 @@ private boolean parseArguments() { return true; } - private void parseArgument(String arg) { + private void parseArgument(String arg) throws ArgsException { if (arg.startsWith("-")) parseElements(arg); } - private void parseElements(String arg) { + private void parseElements(String arg) throws ArgsException { for (int i = 1; i < arg.length(); i++) { parseElement(arg.charAt(i)); } } - private void parseElement(char argChar) { + private void parseElement(char argChar) throws ArgsException { if (setArgument(argChar)) argsFound.add(argChar); else { unexpectedArguments.add(argChar); + errorCode = ErrorCode.UNEXPECTED_ARGUMENT; valid = false; } } - private boolean setArgument(char argChar) { - boolean set = true; - if (isBoolean(argChar)) + private boolean setArgument(char argChar) throws ArgsException { + if (isBooleanArg(argChar)) setBooleanArg(argChar, true); - else if (isString(argChar)) - setStringArg(argChar, ""); + else if (isStringArg(argChar)) + setStringArg(argChar); + else if (isIntArg(argChar)) + setIntArg(argChar); else - set = false; + return false; + + return true; + } + + private boolean isIntArg(char argChar) { + return intArgs.containsKey(argChar); + } - return set; + private void setIntArg(char argChar) throws ArgsException { + currentArgument++; + String parameter = null; + try { + parameter = args[currentArgument]; + intArgs.put(argChar, new Integer(parameter)); + } catch (ArrayIndexOutOfBoundsException e) { + valid = false; + errorArgumentId = argChar; + errorCode = ErrorCode.MISSING_INTEGER; + throw new ArgsException(); + } catch (NumberFormatException e) { + valid = false; + errorArgumentId = argChar; + errorParameter = parameter; + errorCode = ErrorCode.INVALID_INTEGER; + throw new ArgsException(); + } } - private void setStringArg(char argChar, String s) { + private void setStringArg(char argChar) { currentArgument++; try { stringArgs.put(argChar, args[currentArgument]); } catch (ArrayIndexOutOfBoundsException e) { valid = false; - errorArgument = argChar; + errorArgumentId = argChar; errorCode = ErrorCode.MISSING_STRING; } } - private boolean isString(char argChar) { + private boolean isStringArg(char argChar) { return stringArgs.containsKey(argChar); } @@ -136,7 +181,7 @@ private void setBooleanArg(char argChar, boolean value) { booleanArgs.put(argChar, value); } - private boolean isBoolean(char argChar) { + private boolean isBooleanArg(char argChar) { return booleanArgs.containsKey(argChar); } @@ -152,18 +197,23 @@ public String usage() { } public String errorMessage() throws Exception { - if (unexpectedArguments.size() > 0) { - return unexpectedArgumentMessage(); - } else { - switch (errorCode) { - case MISSING_STRING: - return String.format("Could not find string parameter for -%c.", - errorArgument); - case OK: - throw new Exception("TILT: Should not get here."); - } - return ""; + switch (errorCode) { + case OK: + throw new Exception("TILT: Should not get here."); + case UNEXPECTED_ARGUMENT: + return unexpectedArgumentMessage(); + case MISSING_STRING: + return String.format("Could not find string parameter for -%c.", + errorArgumentId); + case INVALID_INTEGER: + return String.format("Argument -%c expects an integer but was '%s'.", + errorArgumentId, errorParameter); + case MISSING_INTEGER: + return String.format("Could not find integer parameter for -%c.", + errorArgumentId); } + return ""; + } private String unexpectedArgumentMessage() { @@ -176,22 +226,30 @@ private String unexpectedArgumentMessage() { return message.toString(); } - public boolean getBoolean(char arg) { - return falseIfNull(booleanArgs.get(arg)); - } - private boolean falseIfNull(Boolean b) { return b == null ? false : b; } - public String getString(char arg) { - return blankIfNull(stringArgs.get(arg)); + private int zeroIfNull(Integer i) { + return i == null ? 0 : i; } private String blankIfNull(String s) { return s == null ? "" : s; } + public String getString(char arg) { + return blankIfNull(stringArgs.get(arg)); + } + + public int getInt(char arg) { + return zeroIfNull(intArgs.get(arg)); + } + + public boolean getBoolean(char arg) { + return falseIfNull(booleanArgs.get(arg)); + } + public boolean has(char arg) { return argsFound.contains(arg); } @@ -199,4 +257,7 @@ public boolean has(char arg) { public boolean isValid() { return valid; } + + private class ArgsException extends Exception { + } } diff --git a/src/test/java/chapter14/ApplicationTest.java b/src/test/java/chapter14/ApplicationTest.java index 680ed1c..c000de9 100644 --- a/src/test/java/chapter14/ApplicationTest.java +++ b/src/test/java/chapter14/ApplicationTest.java @@ -30,16 +30,28 @@ void stringArguments() { assertThat(output()).contains("root"); } + @Test + void integerArguments() { + //given + String[] args = new String[]{"-p", "42"}; + + //when + runMain(args); + + //then + assertThat(output()).contains("42"); + } + @Test void allArgumentsPresent() { //given - String[] args = new String[]{"-l", "-d", "user"}; + String[] args = new String[]{"-l", "-p", "8080", "-d", "user"}; //when runMain(args); //then - assertThat(output()).isEqualTo("logging: true, directory: user"); + assertThat(output()).isEqualTo("logging: true, port: 8080, directory: user"); } @Test @@ -51,7 +63,7 @@ void noArguments() { runMain(args); //then - assertThat(output()).isEqualTo("logging: false, directory:"); + assertThat(output()).isEqualTo("logging: false, port: 0, directory:"); } @Override diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index d62504b..7cc50f5 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -57,20 +57,36 @@ void noSchemaButWithMultipleArguments() throws Exception { assertThat(args.errorMessage()).isEqualTo("Argument(s) -xy unexpected."); } - @DisplayName("boolean 값이 없는 경우") + @DisplayName("schema가 문자가 아닌 경우") @Test - void simpleBooleanNotPresent() throws Exception { + void nonLetterSchema() { //given - String schema = "x"; + String nonLetterSchemaElementId = "*"; String[] arguments = new String[]{}; //when - Args args = new Args(schema, arguments); + Exception exception = catchException(() -> new Args(nonLetterSchemaElementId, arguments)); //then - assertThat(args.isValid()).isTrue(); - assertThat(args.cardinality()).isZero(); - assertThat(args.getBoolean('x')).isFalse(); + assertThat(exception) + .isInstanceOf(ParseException.class) + .hasMessage("Bad character: * in Args format: *"); + } + + @DisplayName("schema format이 유효하지 않은 경우") + @Test + void invalidArgumentFormat() { + //given + String invalidSchemeFormat = "f~"; + String[] arguments = new String[]{}; + + //when + Exception exception = catchException(() -> new Args(invalidSchemeFormat, arguments)); + + //then + assertThat(exception) + .isInstanceOf(ParseException.class) + .hasMessage("Argument: f has invalid format: ~."); } @DisplayName("boolean 값이 있는 경우") @@ -110,11 +126,11 @@ void simpleBooleanMultiplePresent() throws Exception { assertThat(args.getBoolean('z')).isFalse(); } - @DisplayName("String 값이 없는 경우") + @DisplayName("boolean 값이 없는 경우") @Test - void simpleStringNotPresent() throws Exception { + void simpleBooleanNotPresent() throws Exception { //given - String schema = "x*"; + String schema = "x"; String[] arguments = new String[]{}; //when @@ -123,8 +139,7 @@ void simpleStringNotPresent() throws Exception { //then assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getString('x')).isEmpty(); + assertThat(args.getBoolean('x')).isFalse(); } @DisplayName("String 값이 있는 경우") @@ -165,6 +180,23 @@ void simpleStringMultiplePresent() throws Exception { assertThat(args.getString('z')).isEmpty(); } + @DisplayName("String 값이 없는 경우") + @Test + void simpleStringNotPresent() throws Exception { + //given + String schema = "x*"; + String[] arguments = new String[]{}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getString('x')).isEmpty(); + } + @DisplayName("String Argument 값이 없는 경우") @Test void missingStringArgument() throws Exception { @@ -183,20 +215,94 @@ void missingStringArgument() throws Exception { assertThat(args.errorMessage()).isEqualTo("Could not find string parameter for -x."); } - @DisplayName("Schema의 ElementId가 문자가 아니면 ParseException이 발생한다") + @DisplayName("int 값이 있는 경우") @Test - void throwParseExceptionWhenInvalidSchemaElementId() { + void simpleIntPresent() throws Exception { //given - String containsNonLetterElementId = "l,d*,#"; - String[] arguments = new String[0]; + String schema = "x#"; + String[] arguments = new String[]{"-x", "42"}; //when - Exception exception = catchException(() -> new Args(containsNonLetterElementId, arguments)); + Args args = new Args(schema, arguments); //then - assertThat(exception) - .isInstanceOf(ParseException.class) - .hasMessage("Bad character: # in Args format: l,d*,#"); + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isOne(); + assertThat(args.has('x')).isTrue(); + assertThat(args.getInt('x')).isEqualTo(42); + } + + @DisplayName("int 값이 여러 개 있는 경우") + @Test + void simpleIntMultiplePresent() throws Exception { + //given + String schema = "x#,y#,z#"; + String[] arguments = new String[]{"-x", "8001", "-y", "8002"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isEqualTo(2); + assertThat(args.has('x')).isTrue(); + assertThat(args.has('y')).isTrue(); + assertThat(args.has('z')).isFalse(); + assertThat(args.getInt('x')).isEqualTo(8001); + assertThat(args.getInt('y')).isEqualTo(8002); + assertThat(args.getInt('z')).isZero(); + } + + @DisplayName("int 값이 없는 경우") + @Test + void simpleIntNotPresent() throws Exception { + //given + String schema = "x#"; + String[] arguments = new String[]{}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getInt('x')).isZero(); + } + + @DisplayName("Integer Argument 값이 없는 경우") + @Test + void missingInteger() throws Exception { + //given + String schema = "x#"; + String[] arguments = new String[]{"-x"}; // missing + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getInt('x')).isZero(); + assertThat(args.errorMessage()).isEqualTo("Could not find integer parameter for -x."); + } + + @DisplayName("Integer Argument 값을 파싱할 수 없는 경우") + @Test + void invalidInteger() throws Exception { + //given + String schema = "x#"; + String[] arguments = new String[]{"-x", "Forty two"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getInt('x')).isZero(); + assertThat(args.errorMessage()).isEqualTo("Argument -x expects an integer but was 'Forty two'."); } @DisplayName("유효한 args에서 errorMessage를 조회할 경우 Excpetion이 발생한다") From c7a916d25874ace04d91f87ce12f2962c169fefe Mon Sep 17 00:00:00 2001 From: viiviii Date: Wed, 11 May 2022 18:54:18 +0900 Subject: [PATCH 04/11] =?UTF-8?q?test:=20=EB=B9=A0=EC=A7=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8spacesInFormat()=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/chapter14/args/ArgsTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index 7cc50f5..8ca362f 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -89,6 +89,23 @@ void invalidArgumentFormat() { .hasMessage("Argument: f has invalid format: ~."); } + @DisplayName("Schema format에 스페이스가 있는 경우") + @Test + void spacesInFormat() throws Exception { + //given + String schema = "x, y"; + String[] arguments = new String[]{"-xy"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isEqualTo(2); + assertThat(args.has('x')).isTrue(); + assertThat(args.has('y')).isTrue(); + } + @DisplayName("boolean 값이 있는 경우") @Test void simpleBooleanPresent() throws Exception { From 42fe301ffe6c4b77ef51f95aa17b627e2e5250fa Mon Sep 17 00:00:00 2001 From: viiviii Date: Wed, 11 May 2022 19:48:33 +0900 Subject: [PATCH 05/11] =?UTF-8?q?test:=20=EA=B0=92=EC=9D=B4=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/chapter14/args/ArgsTest.java | 53 ++++++++++++---------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index 8ca362f..de25ef5 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -57,6 +57,27 @@ void noSchemaButWithMultipleArguments() throws Exception { assertThat(args.errorMessage()).isEqualTo("Argument(s) -xy unexpected."); } + @DisplayName("Schema가 있고, arugment가 없는 경우") + @Test + void multipleSchemasButNoArguments() throws Exception { + //given + String schema = "x,y#,z*"; + String[] arguments = new String[]{}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.has('y')).isFalse(); + assertThat(args.has('z')).isFalse(); + assertThat(args.getBoolean('x')).isFalse(); + assertThat(args.getInt('y')).isZero(); + assertThat(args.getString('z')).isEmpty(); + } + @DisplayName("schema가 문자가 아닌 경우") @Test void nonLetterSchema() { @@ -147,16 +168,13 @@ void simpleBooleanMultiplePresent() throws Exception { @Test void simpleBooleanNotPresent() throws Exception { //given - String schema = "x"; - String[] arguments = new String[]{}; + Args args = new Args("x", new String[]{}); //when - Args args = new Args(schema, arguments); + boolean actual = args.getBoolean('y'); //then - assertThat(args.isValid()).isTrue(); - assertThat(args.cardinality()).isZero(); - assertThat(args.getBoolean('x')).isFalse(); + assertThat(actual).isFalse(); } @DisplayName("String 값이 있는 경우") @@ -201,17 +219,13 @@ void simpleStringMultiplePresent() throws Exception { @Test void simpleStringNotPresent() throws Exception { //given - String schema = "x*"; - String[] arguments = new String[]{}; + Args args = new Args("x*", new String[]{}); //when - Args args = new Args(schema, arguments); + String actual = args.getString('y'); //then - assertThat(args.isValid()).isTrue(); - assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getString('x')).isEmpty(); + assertThat(actual).isEmpty(); } @DisplayName("String Argument 값이 없는 경우") @@ -226,8 +240,6 @@ void missingStringArgument() throws Exception { //then assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isOne(); - assertThat(args.has('x')).isTrue(); assertThat(args.getString('x')).isEmpty(); assertThat(args.errorMessage()).isEqualTo("Could not find string parameter for -x."); } @@ -274,17 +286,13 @@ void simpleIntMultiplePresent() throws Exception { @Test void simpleIntNotPresent() throws Exception { //given - String schema = "x#"; - String[] arguments = new String[]{}; + Args args = new Args("x#", new String[]{}); //when - Args args = new Args(schema, arguments); + int actual = args.getInt('y'); //then - assertThat(args.isValid()).isTrue(); - assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getInt('x')).isZero(); + assertThat(actual).isZero(); } @DisplayName("Integer Argument 값이 없는 경우") @@ -299,7 +307,6 @@ void missingInteger() throws Exception { //then assertThat(args.isValid()).isFalse(); - assertThat(args.has('x')).isFalse(); assertThat(args.getInt('x')).isZero(); assertThat(args.errorMessage()).isEqualTo("Could not find integer parameter for -x."); } From b0b7ce4b31b49c2f83207b3f9177af9abf9b9e73 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 09:10:32 +0900 Subject: [PATCH 06/11] =?UTF-8?q?test:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9C=BC=EB=A1=9C=20=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=ED=95=9C=20=EA=B2=BD=EC=9A=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/chapter14/args/ArgsTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index de25ef5..ab97b0e 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -329,6 +329,22 @@ void invalidInteger() throws Exception { assertThat(args.errorMessage()).isEqualTo("Argument -x expects an integer but was 'Forty two'."); } + @DisplayName("잘못된 타입으로 호출한 경우") + @Test + void invalidType() throws Exception { + //given + String schema = "x#,y*"; + String[] arguments = new String[]{"-x", "42", "-y", "param"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.getBoolean('x')).isFalse(); // x is type int + assertThat(args.getString('x')).isEmpty(); // x is type int + assertThat(args.getInt('y')).isZero(); // y is type String + } + @DisplayName("유효한 args에서 errorMessage를 조회할 경우 Excpetion이 발생한다") @Test void errorMessageThrowExceptionWhenErrorCodeIsOK() throws Exception { From 235c96c9351a4054f4e16a596171ea0401702519 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 09:57:38 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20version=201=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1. ArgumentMarshaler class 골격 추가 (목록 14-11) * 2. booleanArgs의 인수 타입을 ArgumentMarshaler로 변경 * 3. getBoolean() NullPointException 발생하는 경우 처리 * 4. StringArgs도 이전 단계처럼 변경 * 5. intArgs도 이전 단계처럼 변경 * 6. ArgumentMarshaler에 있는 boolean 관련 로직을 subclass인 BooleanArgumentMarshaler로 이동 * 7. String 로직도 StringArgumentMarshaler로 이동 * 8. int 로직도 IntergerArgumentMarshaler로 이동 * 9. Args Map 3개를 없애기 위해 marshalers map을 만들어 교체 * 10: marshalers.get() 호출 코드 제거하여 한 곳에서 처리 * 11. 불필요해진 isxxxArgs 메서드를 인라인 코드로 만들고 제거 * 12. setxxx()가 ArgumentMarshaler를 파라미터로 받아 사용하도록 * 13. booleanArgs Map 제거 * 14. stringArgs, intArgs Map도 모두 제거 * 15. 이제 잘 사용하지 않는 parse 메서드들을 인라인으로 변경하여 제거 --- src/main/java/chapter14/args/Args.java | 179 +++++++++++++++---------- 1 file changed, 107 insertions(+), 72 deletions(-) diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index 1f4429a..0e79af4 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -8,9 +8,7 @@ public class Args { private String[] args; private boolean valid = true; private Set unexpectedArguments = new TreeSet<>(); - private Map booleanArgs = new HashMap<>(); - private Map stringArgs = new HashMap<>(); - private Map intArgs = new HashMap<>(); + private Map marshalers = new HashMap<>(); private Set argsFound = new HashSet<>(); private int currentArgument; private char errorArgumentId = '\0'; @@ -52,13 +50,13 @@ private void parseSchemaElement(String element) throws ParseException { char elementId = element.charAt(0); String elementTail = element.substring(1); validateSchemaElementId(elementId); - if (isBooleanSchemaElement(elementTail)) - parseBooleanSchemaElement(elementId); - else if (isStringSchemaElement(elementTail)) - parseStringSchemaElement(elementId); - else if (isIntegerSchemaElement(elementTail)) - parseIntegerSchemaElement(elementId); - else { + if (isBooleanSchemaElement(elementTail)) { + marshalers.put(elementId, new BooleanArgumentMarshaler()); + } else if (isStringSchemaElement(elementTail)) { + marshalers.put(elementId, new StringArgumentMarshaler()); + } else if (isIntegerSchemaElement(elementTail)) { + marshalers.put(elementId, new IntegerArgumentMarshaler()); + } else { throw new ParseException( String.format("Argument: %c has invalid format: %s.", elementId, elementTail), 0); @@ -72,18 +70,6 @@ private void validateSchemaElementId(char elementId) throws ParseException { } } - private void parseBooleanSchemaElement(char elementId) { - booleanArgs.put(elementId, false); - } - - private void parseIntegerSchemaElement(char elementId) { - intArgs.put(elementId, 0); - } - - private void parseStringSchemaElement(char elementId) { - stringArgs.put(elementId, ""); - } - private boolean isStringSchemaElement(String elementTail) { return elementTail.equals("*"); } @@ -126,63 +112,55 @@ private void parseElement(char argChar) throws ArgsException { } private boolean setArgument(char argChar) throws ArgsException { - if (isBooleanArg(argChar)) - setBooleanArg(argChar, true); - else if (isStringArg(argChar)) - setStringArg(argChar); - else if (isIntArg(argChar)) - setIntArg(argChar); - else - return false; - + ArgumentMarshaler m = marshalers.get(argChar); + try { + if (m instanceof BooleanArgumentMarshaler) + setBooleanArg(m); + else if (m instanceof StringArgumentMarshaler) + setStringArg(m); + else if (m instanceof IntegerArgumentMarshaler) + setIntArg(m); + else + return false; + } catch (ArgsException e) { + valid = false; + errorArgumentId = argChar; + throw e; + } return true; } - private boolean isIntArg(char argChar) { - return intArgs.containsKey(argChar); - } - - private void setIntArg(char argChar) throws ArgsException { + private void setIntArg(ArgumentMarshaler m) throws ArgsException { currentArgument++; String parameter = null; try { parameter = args[currentArgument]; - intArgs.put(argChar, new Integer(parameter)); + m.set(parameter); } catch (ArrayIndexOutOfBoundsException e) { - valid = false; - errorArgumentId = argChar; errorCode = ErrorCode.MISSING_INTEGER; throw new ArgsException(); - } catch (NumberFormatException e) { - valid = false; - errorArgumentId = argChar; + } catch (ArgsException e) { errorParameter = parameter; errorCode = ErrorCode.INVALID_INTEGER; - throw new ArgsException(); + throw e; } } - private void setStringArg(char argChar) { + private void setStringArg(ArgumentMarshaler m) throws ArgsException { currentArgument++; try { - stringArgs.put(argChar, args[currentArgument]); + m.set(args[currentArgument]); } catch (ArrayIndexOutOfBoundsException e) { - valid = false; - errorArgumentId = argChar; errorCode = ErrorCode.MISSING_STRING; + throw new ArgsException(); } } - private boolean isStringArg(char argChar) { - return stringArgs.containsKey(argChar); - } - - private void setBooleanArg(char argChar, boolean value) { - booleanArgs.put(argChar, value); - } - - private boolean isBooleanArg(char argChar) { - return booleanArgs.containsKey(argChar); + private void setBooleanArg(ArgumentMarshaler m) { + try { + m.set("true"); + } catch (ArgsException e) { + } } public int cardinality() { @@ -226,28 +204,33 @@ private String unexpectedArgumentMessage() { return message.toString(); } - private boolean falseIfNull(Boolean b) { - return b == null ? false : b; - } - - private int zeroIfNull(Integer i) { - return i == null ? 0 : i; - } - - private String blankIfNull(String s) { - return s == null ? "" : s; - } - public String getString(char arg) { - return blankIfNull(stringArgs.get(arg)); + ArgumentMarshaler am = marshalers.get(arg); + try { + return am == null ? "" : (String) am.get(); + } catch (ClassCastException e) { + return ""; + } } public int getInt(char arg) { - return zeroIfNull(intArgs.get(arg)); + ArgumentMarshaler am = marshalers.get(arg); + try { + return am == null ? 0 : (Integer) am.get(); + } catch (ClassCastException e) { + return 0; + } } public boolean getBoolean(char arg) { - return falseIfNull(booleanArgs.get(arg)); + ArgumentMarshaler am = marshalers.get(arg); + boolean b = false; + try { + b = am != null && (Boolean) am.get(); + } catch (ClassCastException e) { + b = false; + } + return b; } public boolean has(char arg) { @@ -260,4 +243,56 @@ public boolean isValid() { private class ArgsException extends Exception { } + + private abstract class ArgumentMarshaler { + public abstract void set(String s) throws ArgsException; + + public abstract Object get(); + } + + private class BooleanArgumentMarshaler extends ArgumentMarshaler { + private boolean booleanValue = false; + + @Override + public void set(String s) { + booleanValue = true; + } + + @Override + public Object get() { + return booleanValue; + } + } + + private class StringArgumentMarshaler extends ArgumentMarshaler { + private String stringValue = ""; + + @Override + public void set(String s) { + stringValue = s; + } + + @Override + public Object get() { + return stringValue; + } + } + + private class IntegerArgumentMarshaler extends ArgumentMarshaler { + private int intValue = 0; + + @Override + public void set(String s) throws ArgsException { + try { + intValue = Integer.parseInt(s); + } catch (NumberFormatException e) { + throw new ArgsException(); + } + } + + @Override + public Object get() { + return intValue; + } + } } From a2596ccb97000df5770297f6e01bd64c16fe8c63 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 11:41:02 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20version=202=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1. args 배열을 list로 변환 후 setxxxArg()에서 Iterator를 사용하도록 변경 * 2. setArgument()의 if-else 연쇄를 제거하기 위해 오류 로직을 분리 * 3. setBooleanArg()가 Iterator를 파라미터로 받도록 변경 * 4. ArgumentMarshaler set()을 직접 사용하여 setBooleanArg() 제거 * 5. setStringArg(), setIntArg() 제거 * 6. setArgument()의 타입을 일일히 확인하던 코드 제거 * 7. ArgumentMarshaler를 인터페이스로 변경 --- src/main/java/chapter14/args/Args.java | 92 +++++++++----------------- 1 file changed, 33 insertions(+), 59 deletions(-) diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index 0e79af4..60e6b82 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -5,15 +5,15 @@ public class Args { private String schema; - private String[] args; private boolean valid = true; private Set unexpectedArguments = new TreeSet<>(); private Map marshalers = new HashMap<>(); private Set argsFound = new HashSet<>(); - private int currentArgument; + private Iterator currentArgument; private char errorArgumentId = '\0'; private String errorParameter = "TILT"; private ErrorCode errorCode = ErrorCode.OK; + private List argsList; enum ErrorCode { OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT @@ -21,12 +21,12 @@ enum ErrorCode { public Args(String schema, String[] args) throws ParseException { this.schema = schema; - this.args = args; + argsList = Arrays.asList(args); valid = parse(); } private boolean parse() throws ParseException { - if (schema.length() == 0 && args.length == 0) + if (schema.length() == 0 && argsList.size() == 0) return true; parseSchema(); try { @@ -83,8 +83,8 @@ private boolean isIntegerSchemaElement(String elementTail) { } private boolean parseArguments() throws ArgsException { - for (currentArgument = 0; currentArgument < args.length; currentArgument++) { - String arg = args[currentArgument]; + for (currentArgument = argsList.iterator(); currentArgument.hasNext(); ) { + String arg = currentArgument.next(); parseArgument(arg); } return true; @@ -113,54 +113,16 @@ private void parseElement(char argChar) throws ArgsException { private boolean setArgument(char argChar) throws ArgsException { ArgumentMarshaler m = marshalers.get(argChar); + if (m == null) + return false; try { - if (m instanceof BooleanArgumentMarshaler) - setBooleanArg(m); - else if (m instanceof StringArgumentMarshaler) - setStringArg(m); - else if (m instanceof IntegerArgumentMarshaler) - setIntArg(m); - else - return false; + m.set(currentArgument); + return true; } catch (ArgsException e) { valid = false; errorArgumentId = argChar; throw e; } - return true; - } - - private void setIntArg(ArgumentMarshaler m) throws ArgsException { - currentArgument++; - String parameter = null; - try { - parameter = args[currentArgument]; - m.set(parameter); - } catch (ArrayIndexOutOfBoundsException e) { - errorCode = ErrorCode.MISSING_INTEGER; - throw new ArgsException(); - } catch (ArgsException e) { - errorParameter = parameter; - errorCode = ErrorCode.INVALID_INTEGER; - throw e; - } - } - - private void setStringArg(ArgumentMarshaler m) throws ArgsException { - currentArgument++; - try { - m.set(args[currentArgument]); - } catch (ArrayIndexOutOfBoundsException e) { - errorCode = ErrorCode.MISSING_STRING; - throw new ArgsException(); - } - } - - private void setBooleanArg(ArgumentMarshaler m) { - try { - m.set("true"); - } catch (ArgsException e) { - } } public int cardinality() { @@ -244,17 +206,17 @@ public boolean isValid() { private class ArgsException extends Exception { } - private abstract class ArgumentMarshaler { - public abstract void set(String s) throws ArgsException; + private interface ArgumentMarshaler { + void set(Iterator currentArgument) throws ArgsException; - public abstract Object get(); + Object get(); } - private class BooleanArgumentMarshaler extends ArgumentMarshaler { + private class BooleanArgumentMarshaler implements ArgumentMarshaler { private boolean booleanValue = false; @Override - public void set(String s) { + public void set(Iterator currentArgument) throws ArgsException { booleanValue = true; } @@ -264,12 +226,17 @@ public Object get() { } } - private class StringArgumentMarshaler extends ArgumentMarshaler { + private class StringArgumentMarshaler implements ArgumentMarshaler { private String stringValue = ""; @Override - public void set(String s) { - stringValue = s; + public void set(Iterator currentArgument) throws ArgsException { + try { + stringValue = currentArgument.next(); + } catch (NoSuchElementException e) { + errorCode = ErrorCode.MISSING_STRING; + throw new ArgsException(); + } } @Override @@ -278,14 +245,21 @@ public Object get() { } } - private class IntegerArgumentMarshaler extends ArgumentMarshaler { + private class IntegerArgumentMarshaler implements ArgumentMarshaler { private int intValue = 0; @Override - public void set(String s) throws ArgsException { + public void set(Iterator currentArgument) throws ArgsException { + String parameter = null; try { - intValue = Integer.parseInt(s); + parameter = currentArgument.next(); + intValue = Integer.parseInt(parameter); + } catch (NoSuchElementException e) { + errorCode = ErrorCode.MISSING_INTEGER; + throw new ArgsException(); } catch (NumberFormatException e) { + errorParameter = parameter; + errorCode = ErrorCode.INVALID_INTEGER; throw new ArgsException(); } } From ad15f990dff589818da64020fe8cb9856443a747 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 11:55:06 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20version=203=20(Add=20Double)=20(#?= =?UTF-8?q?10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: double 유형 테스트 추가 * refactor: isxxxSchemaElement() 인라인으로 변경하여 제거 * feat: double 유형 추가 --- src/main/java/chapter14/args/Args.java | 63 ++++++++++++++------ src/test/java/chapter14/args/ArgsTest.java | 67 ++++++++++++++++++++++ 2 files changed, 114 insertions(+), 16 deletions(-) diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index 60e6b82..e45390b 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -16,7 +16,8 @@ public class Args { private List argsList; enum ErrorCode { - OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT + OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, + UNEXPECTED_ARGUMENT, MISSING_DOUBLE, INVALID_DOUBLE } public Args(String schema, String[] args) throws ParseException { @@ -50,12 +51,14 @@ private void parseSchemaElement(String element) throws ParseException { char elementId = element.charAt(0); String elementTail = element.substring(1); validateSchemaElementId(elementId); - if (isBooleanSchemaElement(elementTail)) { + if (elementTail.length() == 0) { marshalers.put(elementId, new BooleanArgumentMarshaler()); - } else if (isStringSchemaElement(elementTail)) { + } else if (elementTail.equals("*")) { marshalers.put(elementId, new StringArgumentMarshaler()); - } else if (isIntegerSchemaElement(elementTail)) { + } else if (elementTail.equals("#")) { marshalers.put(elementId, new IntegerArgumentMarshaler()); + } else if (elementTail.equals("##")) { + marshalers.put(elementId, new DoubleArgumentMarshaler()); } else { throw new ParseException( String.format("Argument: %c has invalid format: %s.", @@ -70,18 +73,6 @@ private void validateSchemaElementId(char elementId) throws ParseException { } } - private boolean isStringSchemaElement(String elementTail) { - return elementTail.equals("*"); - } - - private boolean isBooleanSchemaElement(String elementTail) { - return elementTail.length() == 0; - } - - private boolean isIntegerSchemaElement(String elementTail) { - return elementTail.equals("#"); - } - private boolean parseArguments() throws ArgsException { for (currentArgument = argsList.iterator(); currentArgument.hasNext(); ) { String arg = currentArgument.next(); @@ -151,6 +142,12 @@ public String errorMessage() throws Exception { case MISSING_INTEGER: return String.format("Could not find integer parameter for -%c.", errorArgumentId); + case INVALID_DOUBLE: + return String.format("Argument -%c expects an double but was '%s'.", + errorArgumentId, errorParameter); + case MISSING_DOUBLE: + return String.format("Could not find double parameter for -%c.", + errorArgumentId); } return ""; @@ -195,6 +192,15 @@ public boolean getBoolean(char arg) { return b; } + public double getDouble(char arg) { + ArgumentMarshaler am = marshalers.get(arg); + try { + return am == null ? 0.0 : (Double) am.get(); + } catch (ClassCastException e) { + return 0.0; + } + } + public boolean has(char arg) { return argsFound.contains(arg); } @@ -269,4 +275,29 @@ public Object get() { return intValue; } } + + private class DoubleArgumentMarshaler implements ArgumentMarshaler { + private double doubleValue = 0; + + @Override + public void set(Iterator currentArgument) throws ArgsException { + String parameter = null; + try { + parameter = currentArgument.next(); + doubleValue = Double.parseDouble(parameter); + } catch (NoSuchElementException e) { + errorCode = ErrorCode.MISSING_DOUBLE; + throw new ArgsException(); + } catch (NumberFormatException e) { + errorParameter = parameter; + errorCode = ErrorCode.INVALID_DOUBLE; + throw new ArgsException(); + } + } + + @Override + public Object get() { + return doubleValue; + } + } } diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index ab97b0e..fcfe149 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -329,6 +329,72 @@ void invalidInteger() throws Exception { assertThat(args.errorMessage()).isEqualTo("Argument -x expects an integer but was 'Forty two'."); } + @DisplayName("double 값이 있는 경우") + @Test + void simpleDoublePresent() throws Exception { + //given + String schema = "x##"; + String[] arguments = new String[]{"-x", "42.3"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isTrue(); + assertThat(args.cardinality()).isOne(); + assertThat(args.has('x')).isTrue(); + assertThat(args.getDouble('x')).isEqualTo(42.3); + } + + @DisplayName("Double 값이 없는 경우") + @Test + void simpleDoubleNotPresent() throws Exception { + //given + Args args = new Args("x##", new String[]{}); + + //when + double actual = args.getDouble('y'); + + //then + assertThat(actual).isZero(); + } + + @DisplayName("Double Argument 값이 없는 경우") + @Test + void missingDouble() throws Exception { + //given + String schema = "x##"; + String[] arguments = new String[]{"-x"}; // missing + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getDouble('x')).isZero(); + assertThat(args.errorMessage()).isEqualTo("Could not find double parameter for -x."); + } + + @DisplayName("Double Argument 값을 파싱할 수 없는 경우") + @Test + void invalidDouble() throws Exception { + //given + String schema = "x##"; + String[] arguments = new String[]{"-x", "Forty two"}; + + //when + Args args = new Args(schema, arguments); + + //then + assertThat(args.isValid()).isFalse(); + assertThat(args.cardinality()).isZero(); + assertThat(args.has('x')).isFalse(); + assertThat(args.getDouble('x')).isZero(); + assertThat(args.errorMessage()).isEqualTo("Argument -x expects an double but was 'Forty two'."); + } + @DisplayName("잘못된 타입으로 호출한 경우") @Test void invalidType() throws Exception { @@ -343,6 +409,7 @@ void invalidType() throws Exception { assertThat(args.getBoolean('x')).isFalse(); // x is type int assertThat(args.getString('x')).isEmpty(); // x is type int assertThat(args.getInt('y')).isZero(); // y is type String + assertThat(args.getDouble('y')).isZero(); // y is type String } @DisplayName("유효한 args에서 errorMessage를 조회할 경우 Excpetion이 발생한다") From 127aaea52ea648b54af192ae577fb41b50118d66 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 16:09:02 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20version=204=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1. ErrorCode ArgsException class로 이동 * 2. ParseException 대신 ArgsException을 던지도록 변경 * 3. 예외 관련 로직 ArgsException으로 복사 * 4. parse()의 빈 catch절 제거하여 ArgsException을 던지게 변경 * 5. 예외에서 값을 꺼내도록 예외 테스트 코드 변경 * 6. UNEXPECTED_ARGUMENT도 ArgsException을 던지도록 변경 * 7. UNEXPECTED_ARGUMENT 예외 메세지 변경 * 8. 예외에서 값을 꺼내도록 예외 테스트 코드 변경 * 9. Args에서 불필요해진 예외 코드 제거 * 10. ArgsException 클래스 추출 * 11. ArgumentMarshaler 관련 클래스 추출 * 12. Args isValid 제거 * 13. INVALID_ARGUMENT_NAME, FORMAT errorCode 추가 * 14. 메서드 순서 변경 등 책이랑 맞춤 --- src/main/java/chapter14/Application.java | 7 +- src/main/java/chapter14/args/Args.java | 202 +++--------------- .../java/chapter14/args/ArgsException.java | 92 ++++++++ .../chapter14/args/ArgumentMarshaler.java | 9 + .../args/BooleanArgumentMarshaler.java | 17 ++ .../args/DoubleArgumentMarshaler.java | 29 +++ .../args/IntegerArgumentMarshaler.java | 29 +++ .../args/StringArgumentMarshaler.java | 24 +++ .../chapter14/args/ArgsExceptionTest.java | 106 +++++++++ src/test/java/chapter14/args/ArgsTest.java | 157 ++------------ .../args/DoubleArgumentMarshalerTest.java | 48 +++++ .../args/IntegerArgumentMarshalerTest.java | 48 +++++ .../args/StringArgumentMarshalerTest.java | 30 +++ 13 files changed, 476 insertions(+), 322 deletions(-) create mode 100644 src/main/java/chapter14/args/ArgsException.java create mode 100644 src/main/java/chapter14/args/ArgumentMarshaler.java create mode 100644 src/main/java/chapter14/args/BooleanArgumentMarshaler.java create mode 100644 src/main/java/chapter14/args/DoubleArgumentMarshaler.java create mode 100644 src/main/java/chapter14/args/IntegerArgumentMarshaler.java create mode 100644 src/main/java/chapter14/args/StringArgumentMarshaler.java create mode 100644 src/test/java/chapter14/args/ArgsExceptionTest.java create mode 100644 src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java create mode 100644 src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java create mode 100644 src/test/java/chapter14/args/StringArgumentMarshalerTest.java diff --git a/src/main/java/chapter14/Application.java b/src/main/java/chapter14/Application.java index ca77f84..e9acbe7 100644 --- a/src/main/java/chapter14/Application.java +++ b/src/main/java/chapter14/Application.java @@ -1,8 +1,7 @@ package chapter14; import chapter14.args.Args; - -import java.text.ParseException; +import chapter14.args.ArgsException; class Application { @@ -13,8 +12,8 @@ public static void main(String[] args) { int port = arg.getInt('p'); String directory = arg.getString('d'); executeApplication(logging, port, directory); - } catch (ParseException e) { - System.out.printf("Parse error: %s\n", e.getMessage()); + } catch (ArgsException e) { + System.out.printf("Argument error: %s\n", e.getMessage()); } } diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index e45390b..d3dd8bc 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -1,53 +1,35 @@ package chapter14.args; -import java.text.ParseException; import java.util.*; public class Args { private String schema; - private boolean valid = true; - private Set unexpectedArguments = new TreeSet<>(); private Map marshalers = new HashMap<>(); private Set argsFound = new HashSet<>(); private Iterator currentArgument; - private char errorArgumentId = '\0'; - private String errorParameter = "TILT"; - private ErrorCode errorCode = ErrorCode.OK; private List argsList; - enum ErrorCode { - OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, - UNEXPECTED_ARGUMENT, MISSING_DOUBLE, INVALID_DOUBLE - } - - public Args(String schema, String[] args) throws ParseException { + public Args(String schema, String[] args) throws ArgsException { this.schema = schema; argsList = Arrays.asList(args); - valid = parse(); + parse(); } - private boolean parse() throws ParseException { - if (schema.length() == 0 && argsList.size() == 0) - return true; + private void parse() throws ArgsException { parseSchema(); - try { - parseArguments(); - } catch (ArgsException e) { - } - return valid; + parseArguments(); } - private boolean parseSchema() throws ParseException { + private boolean parseSchema() throws ArgsException { for (String element : schema.split(",")) { if (element.length() > 0) { - String trimmedElement = element.trim(); - parseSchemaElement(trimmedElement); + parseSchemaElement(element.trim()); } } return true; } - private void parseSchemaElement(String element) throws ParseException { + private void parseSchemaElement(String element) throws ArgsException { char elementId = element.charAt(0); String elementTail = element.substring(1); validateSchemaElementId(elementId); @@ -60,25 +42,23 @@ private void parseSchemaElement(String element) throws ParseException { } else if (elementTail.equals("##")) { marshalers.put(elementId, new DoubleArgumentMarshaler()); } else { - throw new ParseException( - String.format("Argument: %c has invalid format: %s.", - elementId, elementTail), 0); + throw new ArgsException(ArgsException.ErrorCode.INVALID_ARGUMENT_FORMAT, + elementId, elementTail); } } - private void validateSchemaElementId(char elementId) throws ParseException { + private void validateSchemaElementId(char elementId) throws ArgsException { if (!Character.isLetter(elementId)) { - throw new ParseException( - "Bad character: " + elementId + " in Args format: " + schema, 0); + throw new ArgsException(ArgsException.ErrorCode.INVALID_ARGUMENT_NAME, + elementId, null); } } - private boolean parseArguments() throws ArgsException { + private void parseArguments() throws ArgsException { for (currentArgument = argsList.iterator(); currentArgument.hasNext(); ) { String arg = currentArgument.next(); parseArgument(arg); } - return true; } private void parseArgument(String arg) throws ArgsException { @@ -96,9 +76,8 @@ private void parseElement(char argChar) throws ArgsException { if (setArgument(argChar)) argsFound.add(argChar); else { - unexpectedArguments.add(argChar); - errorCode = ErrorCode.UNEXPECTED_ARGUMENT; - valid = false; + throw new ArgsException(ArgsException.ErrorCode.UNEXPECTED_ARGUMENT, + argChar, null); } } @@ -110,8 +89,7 @@ private boolean setArgument(char argChar) throws ArgsException { m.set(currentArgument); return true; } catch (ArgsException e) { - valid = false; - errorArgumentId = argChar; + e.setErrorArgumentId(argChar); throw e; } } @@ -127,40 +105,15 @@ public String usage() { return ""; } - public String errorMessage() throws Exception { - switch (errorCode) { - case OK: - throw new Exception("TILT: Should not get here."); - case UNEXPECTED_ARGUMENT: - return unexpectedArgumentMessage(); - case MISSING_STRING: - return String.format("Could not find string parameter for -%c.", - errorArgumentId); - case INVALID_INTEGER: - return String.format("Argument -%c expects an integer but was '%s'.", - errorArgumentId, errorParameter); - case MISSING_INTEGER: - return String.format("Could not find integer parameter for -%c.", - errorArgumentId); - case INVALID_DOUBLE: - return String.format("Argument -%c expects an double but was '%s'.", - errorArgumentId, errorParameter); - case MISSING_DOUBLE: - return String.format("Could not find double parameter for -%c.", - errorArgumentId); - } - return ""; - - } - - private String unexpectedArgumentMessage() { - StringBuffer message = new StringBuffer("Argument(s) -"); - for (char c : unexpectedArguments) { - message.append(c); + public boolean getBoolean(char arg) { + ArgumentMarshaler am = marshalers.get(arg); + boolean b = false; + try { + b = am != null && (Boolean) am.get(); + } catch (ClassCastException e) { + b = false; } - message.append(" unexpected."); - - return message.toString(); + return b; } public String getString(char arg) { @@ -181,17 +134,6 @@ public int getInt(char arg) { } } - public boolean getBoolean(char arg) { - ArgumentMarshaler am = marshalers.get(arg); - boolean b = false; - try { - b = am != null && (Boolean) am.get(); - } catch (ClassCastException e) { - b = false; - } - return b; - } - public double getDouble(char arg) { ArgumentMarshaler am = marshalers.get(arg); try { @@ -204,100 +146,4 @@ public double getDouble(char arg) { public boolean has(char arg) { return argsFound.contains(arg); } - - public boolean isValid() { - return valid; - } - - private class ArgsException extends Exception { - } - - private interface ArgumentMarshaler { - void set(Iterator currentArgument) throws ArgsException; - - Object get(); - } - - private class BooleanArgumentMarshaler implements ArgumentMarshaler { - private boolean booleanValue = false; - - @Override - public void set(Iterator currentArgument) throws ArgsException { - booleanValue = true; - } - - @Override - public Object get() { - return booleanValue; - } - } - - private class StringArgumentMarshaler implements ArgumentMarshaler { - private String stringValue = ""; - - @Override - public void set(Iterator currentArgument) throws ArgsException { - try { - stringValue = currentArgument.next(); - } catch (NoSuchElementException e) { - errorCode = ErrorCode.MISSING_STRING; - throw new ArgsException(); - } - } - - @Override - public Object get() { - return stringValue; - } - } - - private class IntegerArgumentMarshaler implements ArgumentMarshaler { - private int intValue = 0; - - @Override - public void set(Iterator currentArgument) throws ArgsException { - String parameter = null; - try { - parameter = currentArgument.next(); - intValue = Integer.parseInt(parameter); - } catch (NoSuchElementException e) { - errorCode = ErrorCode.MISSING_INTEGER; - throw new ArgsException(); - } catch (NumberFormatException e) { - errorParameter = parameter; - errorCode = ErrorCode.INVALID_INTEGER; - throw new ArgsException(); - } - } - - @Override - public Object get() { - return intValue; - } - } - - private class DoubleArgumentMarshaler implements ArgumentMarshaler { - private double doubleValue = 0; - - @Override - public void set(Iterator currentArgument) throws ArgsException { - String parameter = null; - try { - parameter = currentArgument.next(); - doubleValue = Double.parseDouble(parameter); - } catch (NoSuchElementException e) { - errorCode = ErrorCode.MISSING_DOUBLE; - throw new ArgsException(); - } catch (NumberFormatException e) { - errorParameter = parameter; - errorCode = ErrorCode.INVALID_DOUBLE; - throw new ArgsException(); - } - } - - @Override - public Object get() { - return doubleValue; - } - } } diff --git a/src/main/java/chapter14/args/ArgsException.java b/src/main/java/chapter14/args/ArgsException.java new file mode 100644 index 0000000..4e9addb --- /dev/null +++ b/src/main/java/chapter14/args/ArgsException.java @@ -0,0 +1,92 @@ +package chapter14.args; + +public class ArgsException extends Exception { + private char errorArgumentId = '\0'; + private String errorParameter = "TILT"; + private ErrorCode errorCode = ErrorCode.OK; + + public ArgsException() { + } + + public ArgsException(String message) { + super(message); + } + + public ArgsException(ErrorCode errorCode) { + this.errorCode = errorCode; + } + + public ArgsException(ErrorCode errorCode, String errorParameter) { + this.errorCode = errorCode; + this.errorParameter = errorParameter; + } + + public ArgsException(ErrorCode errorCode, char errorArgumentId, String errorParameter) { + this.errorCode = errorCode; + this.errorArgumentId = errorArgumentId; + this.errorParameter = errorParameter; + } + + public char getErrorArgumentId() { + return errorArgumentId; + } + + public void setErrorArgumentId(char errorArgumentId) { + this.errorArgumentId = errorArgumentId; + } + + public String getErrorParameter() { + return errorParameter; + } + + public void setErrorParameter(String errorParameter) { + this.errorParameter = errorParameter; + } + + public ErrorCode getErrorCode() { + return errorCode; + } + + public void setErrorCode(ErrorCode errorCode) { + this.errorCode = errorCode; + } + + public String errorMessage() throws Exception { + switch (errorCode) { + case OK: + throw new Exception("TILT: Should not get here."); + case UNEXPECTED_ARGUMENT: + return String.format("Argument(s) -%c unexpected.", errorArgumentId); + case MISSING_STRING: + return String.format("Could not find string parameter for -%c.", + errorArgumentId); + case INVALID_INTEGER: + return String.format("Argument -%c expects an integer but was '%s'.", + errorArgumentId, errorParameter); + case MISSING_INTEGER: + return String.format("Could not find integer parameter for -%c.", + errorArgumentId); + case INVALID_DOUBLE: + return String.format("Argument -%c expects an double but was '%s'.", + errorArgumentId, errorParameter); + case MISSING_DOUBLE: + return String.format("Could not find double parameter for -%c.", + errorArgumentId); + case INVALID_ARGUMENT_NAME: + return String.format("'%c' is not a valid argument name.", + errorArgumentId); + case INVALID_ARGUMENT_FORMAT: + return String.format("'%s' is not a valid argument format.", + errorParameter); + } + return ""; + } + + public enum ErrorCode { + OK, INVALID_ARGUMENT_FORMAT, UNEXPECTED_ARGUMENT, + INVALID_ARGUMENT_NAME, + MISSING_STRING, + MISSING_INTEGER, INVALID_INTEGER, + MISSING_DOUBLE, INVALID_DOUBLE + } +} diff --git a/src/main/java/chapter14/args/ArgumentMarshaler.java b/src/main/java/chapter14/args/ArgumentMarshaler.java new file mode 100644 index 0000000..8a641aa --- /dev/null +++ b/src/main/java/chapter14/args/ArgumentMarshaler.java @@ -0,0 +1,9 @@ +package chapter14.args; + +import java.util.Iterator; + +public interface ArgumentMarshaler { + void set(Iterator currentArgument) throws ArgsException; + + Object get(); +} diff --git a/src/main/java/chapter14/args/BooleanArgumentMarshaler.java b/src/main/java/chapter14/args/BooleanArgumentMarshaler.java new file mode 100644 index 0000000..4619a7e --- /dev/null +++ b/src/main/java/chapter14/args/BooleanArgumentMarshaler.java @@ -0,0 +1,17 @@ +package chapter14.args; + +import java.util.Iterator; + +public class BooleanArgumentMarshaler implements ArgumentMarshaler { + private boolean booleanValue = false; + + @Override + public void set(Iterator currentArgument) throws ArgsException { + booleanValue = true; + } + + @Override + public Object get() { + return booleanValue; + } +} \ No newline at end of file diff --git a/src/main/java/chapter14/args/DoubleArgumentMarshaler.java b/src/main/java/chapter14/args/DoubleArgumentMarshaler.java new file mode 100644 index 0000000..16544d3 --- /dev/null +++ b/src/main/java/chapter14/args/DoubleArgumentMarshaler.java @@ -0,0 +1,29 @@ +package chapter14.args; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static chapter14.args.ArgsException.ErrorCode.INVALID_DOUBLE; +import static chapter14.args.ArgsException.ErrorCode.MISSING_DOUBLE; + +public class DoubleArgumentMarshaler implements ArgumentMarshaler { + private double doubleValue = 0; + + @Override + public void set(Iterator currentArgument) throws ArgsException { + String parameter = null; + try { + parameter = currentArgument.next(); + doubleValue = Double.parseDouble(parameter); + } catch (NoSuchElementException e) { + throw new ArgsException(MISSING_DOUBLE); + } catch (NumberFormatException e) { + throw new ArgsException(INVALID_DOUBLE, parameter); + } + } + + @Override + public Object get() { + return doubleValue; + } +} \ No newline at end of file diff --git a/src/main/java/chapter14/args/IntegerArgumentMarshaler.java b/src/main/java/chapter14/args/IntegerArgumentMarshaler.java new file mode 100644 index 0000000..ee040a5 --- /dev/null +++ b/src/main/java/chapter14/args/IntegerArgumentMarshaler.java @@ -0,0 +1,29 @@ +package chapter14.args; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static chapter14.args.ArgsException.ErrorCode.INVALID_INTEGER; +import static chapter14.args.ArgsException.ErrorCode.MISSING_INTEGER; + +public class IntegerArgumentMarshaler implements ArgumentMarshaler { + private int intValue = 0; + + @Override + public void set(Iterator currentArgument) throws ArgsException { + String parameter = null; + try { + parameter = currentArgument.next(); + intValue = Integer.parseInt(parameter); + } catch (NoSuchElementException e) { + throw new ArgsException(MISSING_INTEGER); + } catch (NumberFormatException e) { + throw new ArgsException(INVALID_INTEGER, parameter); + } + } + + @Override + public Object get() { + return intValue; + } +} \ No newline at end of file diff --git a/src/main/java/chapter14/args/StringArgumentMarshaler.java b/src/main/java/chapter14/args/StringArgumentMarshaler.java new file mode 100644 index 0000000..2eef6d9 --- /dev/null +++ b/src/main/java/chapter14/args/StringArgumentMarshaler.java @@ -0,0 +1,24 @@ +package chapter14.args; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static chapter14.args.ArgsException.ErrorCode.MISSING_STRING; + +public class StringArgumentMarshaler implements ArgumentMarshaler { + private String stringValue = ""; + + @Override + public void set(Iterator currentArgument) throws ArgsException { + try { + stringValue = currentArgument.next(); + } catch (NoSuchElementException e) { + throw new ArgsException(MISSING_STRING); + } + } + + @Override + public Object get() { + return stringValue; + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/args/ArgsExceptionTest.java b/src/test/java/chapter14/args/ArgsExceptionTest.java new file mode 100644 index 0000000..a01faaf --- /dev/null +++ b/src/test/java/chapter14/args/ArgsExceptionTest.java @@ -0,0 +1,106 @@ +package chapter14.args; + +import org.junit.jupiter.api.Test; + +import static chapter14.args.ArgsException.ErrorCode; +import static chapter14.args.ArgsException.ErrorCode.*; +import static org.assertj.core.api.Assertions.assertThat; + +class ArgsExceptionTest { + + @Test + void unexpectedMessage() throws Exception { + //given + ErrorCode errorCode = UNEXPECTED_ARGUMENT; + + //when + ArgsException e = new ArgsException(errorCode, 'x', null); + + //then + assertThat(e.errorMessage()).isEqualTo("Argument(s) -x unexpected."); + } + + @Test + void missingStringMessage() throws Exception { + //given + ErrorCode errorCode = MISSING_STRING; + + //when + ArgsException e = new ArgsException(errorCode, 'x', null); + + //then + assertThat(e.errorMessage()).isEqualTo("Could not find string parameter for -x."); + } + + @Test + void invalidIntegerMessage() throws Exception { + //given + ErrorCode errorCode = INVALID_INTEGER; + + //when + ArgsException e = new ArgsException(errorCode, 'x', "Forty two"); + + //then + assertThat(e.errorMessage()).isEqualTo("Argument -x expects an integer but was 'Forty two'."); + } + + @Test + void missingIntegerMessage() throws Exception { + //given + ErrorCode errorCode = MISSING_INTEGER; + + //when + ArgsException e = new ArgsException(errorCode, 'x', null); + + //then + assertThat(e.errorMessage()).isEqualTo("Could not find integer parameter for -x."); + } + + @Test + void invalidDoubleMessage() throws Exception { + //given + ErrorCode errorCode = INVALID_DOUBLE; + + //when + ArgsException e = new ArgsException(errorCode, 'x', "Forty two"); + + //then + assertThat(e.errorMessage()).isEqualTo("Argument -x expects an double but was 'Forty two'."); + } + + @Test + void missingDoubleMessage() throws Exception { + //given + ErrorCode errorCode = MISSING_DOUBLE; + + //when + ArgsException e = new ArgsException(errorCode, 'x', null); + + //then + assertThat(e.errorMessage()).isEqualTo("Could not find double parameter for -x."); + } + + @Test + void invalidArgumentNameMessage() throws Exception { + //given + ErrorCode errorCode = INVALID_ARGUMENT_NAME; + + //when + ArgsException e = new ArgsException(errorCode, 'x', null); + + //then + assertThat(e.errorMessage()).isEqualTo("'x' is not a valid argument name."); + } + + @Test + void invalidArgumentFormatMessage() throws Exception { + //given + ErrorCode errorCode = INVALID_ARGUMENT_FORMAT; + + //when + ArgsException e = new ArgsException(errorCode, 'x', "f~"); + + //then + assertThat(e.errorMessage()).isEqualTo("'f~' is not a valid argument format."); + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index fcfe149..b28ab04 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -3,8 +3,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.text.ParseException; - +import static chapter14.args.ArgsException.ErrorCode.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchException; @@ -21,40 +20,25 @@ void noSchemaAndArguments() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isZero(); } @DisplayName("schema가 없고 argument가 1개 있는 경우") @Test - void noSchemaButWithOneArgument() throws Exception { + void noSchemaButWithOneArgument() { //given String schema = ""; String[] arguments = new String[]{"-x"}; //when - Args args = new Args(schema, arguments); + Exception exception = catchException(() -> new Args(schema, arguments)); //then - assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isZero(); - assertThat(args.errorMessage()).isEqualTo("Argument(s) -x unexpected."); - } - - @DisplayName("schema가 없고 argument가 여러 개 있는 경우") - @Test - void noSchemaButWithMultipleArguments() throws Exception { - //given - String schema = ""; - String[] arguments = new String[]{"-x", "-y"}; - - //when - Args args = new Args(schema, arguments); + assertThat(exception).isInstanceOf(ArgsException.class); - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isZero(); - assertThat(args.errorMessage()).isEqualTo("Argument(s) -xy unexpected."); + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(UNEXPECTED_ARGUMENT); + assertThat(e.getErrorArgumentId()).isEqualTo('x'); } @DisplayName("Schema가 있고, arugment가 없는 경우") @@ -68,7 +52,6 @@ void multipleSchemasButNoArguments() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isZero(); assertThat(args.has('x')).isFalse(); assertThat(args.has('y')).isFalse(); @@ -89,9 +72,11 @@ void nonLetterSchema() { Exception exception = catchException(() -> new Args(nonLetterSchemaElementId, arguments)); //then - assertThat(exception) - .isInstanceOf(ParseException.class) - .hasMessage("Bad character: * in Args format: *"); + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(INVALID_ARGUMENT_NAME); + assertThat(e.getErrorArgumentId()).isEqualTo('*'); } @DisplayName("schema format이 유효하지 않은 경우") @@ -105,9 +90,11 @@ void invalidArgumentFormat() { Exception exception = catchException(() -> new Args(invalidSchemeFormat, arguments)); //then - assertThat(exception) - .isInstanceOf(ParseException.class) - .hasMessage("Argument: f has invalid format: ~."); + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(INVALID_ARGUMENT_FORMAT); + assertThat(e.getErrorArgumentId()).isEqualTo('f'); } @DisplayName("Schema format에 스페이스가 있는 경우") @@ -121,7 +108,6 @@ void spacesInFormat() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); @@ -138,7 +124,6 @@ void simpleBooleanPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isOne(); assertThat(args.getBoolean('x')).isTrue(); } @@ -154,7 +139,6 @@ void simpleBooleanMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); @@ -188,7 +172,6 @@ void simpleStringPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getString('x')).isEqualTo("param"); @@ -205,7 +188,6 @@ void simpleStringMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); @@ -228,22 +210,6 @@ void simpleStringNotPresent() throws Exception { assertThat(actual).isEmpty(); } - @DisplayName("String Argument 값이 없는 경우") - @Test - void missingStringArgument() throws Exception { - //given - String schema = "x*"; - String[] arguments = new String[]{"-x"}; // missing - - //when - Args args = new Args(schema, arguments); - - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.getString('x')).isEmpty(); - assertThat(args.errorMessage()).isEqualTo("Could not find string parameter for -x."); - } - @DisplayName("int 값이 있는 경우") @Test void simpleIntPresent() throws Exception { @@ -255,7 +221,6 @@ void simpleIntPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getInt('x')).isEqualTo(42); @@ -272,7 +237,6 @@ void simpleIntMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); @@ -295,40 +259,6 @@ void simpleIntNotPresent() throws Exception { assertThat(actual).isZero(); } - @DisplayName("Integer Argument 값이 없는 경우") - @Test - void missingInteger() throws Exception { - //given - String schema = "x#"; - String[] arguments = new String[]{"-x"}; // missing - - //when - Args args = new Args(schema, arguments); - - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.getInt('x')).isZero(); - assertThat(args.errorMessage()).isEqualTo("Could not find integer parameter for -x."); - } - - @DisplayName("Integer Argument 값을 파싱할 수 없는 경우") - @Test - void invalidInteger() throws Exception { - //given - String schema = "x#"; - String[] arguments = new String[]{"-x", "Forty two"}; - - //when - Args args = new Args(schema, arguments); - - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getInt('x')).isZero(); - assertThat(args.errorMessage()).isEqualTo("Argument -x expects an integer but was 'Forty two'."); - } - @DisplayName("double 값이 있는 경우") @Test void simpleDoublePresent() throws Exception { @@ -340,7 +270,6 @@ void simpleDoublePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.isValid()).isTrue(); assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getDouble('x')).isEqualTo(42.3); @@ -359,42 +288,6 @@ void simpleDoubleNotPresent() throws Exception { assertThat(actual).isZero(); } - @DisplayName("Double Argument 값이 없는 경우") - @Test - void missingDouble() throws Exception { - //given - String schema = "x##"; - String[] arguments = new String[]{"-x"}; // missing - - //when - Args args = new Args(schema, arguments); - - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getDouble('x')).isZero(); - assertThat(args.errorMessage()).isEqualTo("Could not find double parameter for -x."); - } - - @DisplayName("Double Argument 값을 파싱할 수 없는 경우") - @Test - void invalidDouble() throws Exception { - //given - String schema = "x##"; - String[] arguments = new String[]{"-x", "Forty two"}; - - //when - Args args = new Args(schema, arguments); - - //then - assertThat(args.isValid()).isFalse(); - assertThat(args.cardinality()).isZero(); - assertThat(args.has('x')).isFalse(); - assertThat(args.getDouble('x')).isZero(); - assertThat(args.errorMessage()).isEqualTo("Argument -x expects an double but was 'Forty two'."); - } - @DisplayName("잘못된 타입으로 호출한 경우") @Test void invalidType() throws Exception { @@ -411,20 +304,4 @@ void invalidType() throws Exception { assertThat(args.getInt('y')).isZero(); // y is type String assertThat(args.getDouble('y')).isZero(); // y is type String } - - @DisplayName("유효한 args에서 errorMessage를 조회할 경우 Excpetion이 발생한다") - @Test - void errorMessageThrowExceptionWhenErrorCodeIsOK() throws Exception { - //given - Args args = new Args("x", new String[]{"-x"}); - assertThat(args.isValid()).isTrue(); - - //when - Exception exception = catchException(args::errorMessage); - - //then - assertThat(exception) - .isInstanceOf(Exception.class) - .hasMessage("TILT: Should not get here."); - } } \ No newline at end of file diff --git a/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java b/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java new file mode 100644 index 0000000..609941e --- /dev/null +++ b/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java @@ -0,0 +1,48 @@ +package chapter14.args; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; + +class DoubleArgumentMarshalerTest { + private ArgumentMarshaler am = new DoubleArgumentMarshaler(); + + @DisplayName("값을 파싱할 수 없는 경우") + @Test + void invalidDouble() { + //given + Iterator argument = List.of("Forty two").iterator(); + + //when + Exception exception = catchException(() -> am.set(argument)); + + //then + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.INVALID_DOUBLE); + assertThat(e.getErrorParameter()).isEqualTo("Forty two"); + } + + @DisplayName("Argument 값이 없는 경우") + @Test + void missingDouble() { + //given + Iterator argument = Collections.emptyIterator(); + + //when + Exception exception = catchException(() -> am.set(argument)); + + //then + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_DOUBLE); + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java b/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java new file mode 100644 index 0000000..9135c20 --- /dev/null +++ b/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java @@ -0,0 +1,48 @@ +package chapter14.args; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; + +class IntegerArgumentMarshalerTest { + private ArgumentMarshaler am = new IntegerArgumentMarshaler(); + + @DisplayName("Integer Argument 값을 파싱할 수 없는 경우") + @Test + void invalidInteger() { + //given + Iterator argument = List.of("Forty two").iterator(); + + //when + Exception exception = catchException(() -> am.set(argument)); + + //then + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.INVALID_INTEGER); + assertThat(e.getErrorParameter()).isEqualTo("Forty two"); + } + + @DisplayName("Argument 값이 없는 경우") + @Test + void missingInteger() { + //given + Iterator argument = Collections.emptyIterator(); + + //when + Exception exception = catchException(() -> am.set(argument)); + + //then + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_INTEGER); + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/args/StringArgumentMarshalerTest.java b/src/test/java/chapter14/args/StringArgumentMarshalerTest.java new file mode 100644 index 0000000..9f7772c --- /dev/null +++ b/src/test/java/chapter14/args/StringArgumentMarshalerTest.java @@ -0,0 +1,30 @@ +package chapter14.args; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.Iterator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; + +class StringArgumentMarshalerTest { + private ArgumentMarshaler am = new StringArgumentMarshaler(); + + @DisplayName("Argument 값이 없는 경우") + @Test + void missingString() { + //given + Iterator argument = Collections.emptyIterator(); + + //when + Exception exception = catchException(() -> am.set(argument)); + + //then + assertThat(exception).isInstanceOf(ArgsException.class); + + ArgsException e = (ArgsException) exception; + assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_STRING); + } +} \ No newline at end of file From aac8128ae975346346addcc9fc3035a894843336 Mon Sep 17 00:00:00 2001 From: viiviii Date: Thu, 12 May 2022 18:27:57 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=E2=9C=A8=2014.=20=EC=A0=90=EC=A7=84?= =?UTF-8?q?=EC=A0=81=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20-=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20version=205=20(Final)=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1. 사용하지 않는 usage() 제거 * 2. schema 필드 제거 * 3. argList 필드 제거 및 메서드명 변경 * 4. parsexxx() 리팩토링 * 5. cardinality() 제거 * 6. getxxx() 내부 로직을 타입별 ArgumentMarshaler로 이동 * 7. ArgumentMarshaler get() 제거 * 8. 책과 동일하게 메서드 순서 및 괄호 등 format 맞춤 * 9. ErrorCode.OK errorMessage 변경 * 10. 사용 코드 목록 14-1과 동일하게 변경 --- src/main/java/chapter14/Application.java | 2 +- src/main/java/chapter14/args/Args.java | 140 ++++++------------ .../java/chapter14/args/ArgsException.java | 4 +- .../chapter14/args/ArgumentMarshaler.java | 2 - .../args/BooleanArgumentMarshaler.java | 9 +- .../args/DoubleArgumentMarshaler.java | 9 +- .../args/IntegerArgumentMarshaler.java | 9 +- .../args/StringArgumentMarshaler.java | 9 +- src/test/java/chapter14/args/ArgsTest.java | 11 +- .../args/BooleanArgumentMarshalerTest.java | 52 +++++++ .../args/DoubleArgumentMarshalerTest.java | 43 +++++- .../args/IntegerArgumentMarshalerTest.java | 43 +++++- .../args/StringArgumentMarshalerTest.java | 45 +++++- 13 files changed, 257 insertions(+), 121 deletions(-) create mode 100644 src/test/java/chapter14/args/BooleanArgumentMarshalerTest.java diff --git a/src/main/java/chapter14/Application.java b/src/main/java/chapter14/Application.java index e9acbe7..904f8d9 100644 --- a/src/main/java/chapter14/Application.java +++ b/src/main/java/chapter14/Application.java @@ -13,7 +13,7 @@ public static void main(String[] args) { String directory = arg.getString('d'); executeApplication(logging, port, directory); } catch (ArgsException e) { - System.out.printf("Argument error: %s\n", e.getMessage()); + System.out.printf("Argument error: %s\n", e.errorMessage()); } } diff --git a/src/main/java/chapter14/args/Args.java b/src/main/java/chapter14/args/Args.java index d3dd8bc..07e4ac8 100644 --- a/src/main/java/chapter14/args/Args.java +++ b/src/main/java/chapter14/args/Args.java @@ -2,148 +2,106 @@ import java.util.*; +import static chapter14.args.ArgsException.ErrorCode.*; + public class Args { - private String schema; - private Map marshalers = new HashMap<>(); - private Set argsFound = new HashSet<>(); - private Iterator currentArgument; - private List argsList; + private Map marshalers; + private Set argsFound; + private ListIterator currentArgument; public Args(String schema, String[] args) throws ArgsException { - this.schema = schema; - argsList = Arrays.asList(args); - parse(); - } + marshalers = new HashMap<>(); + argsFound = new HashSet<>(); - private void parse() throws ArgsException { - parseSchema(); - parseArguments(); + parseSchema(schema); + parseArgumentStrings(Arrays.asList(args)); } - private boolean parseSchema() throws ArgsException { + private void parseSchema(String schema) throws ArgsException { for (String element : schema.split(",")) { if (element.length() > 0) { parseSchemaElement(element.trim()); } } - return true; } private void parseSchemaElement(String element) throws ArgsException { char elementId = element.charAt(0); String elementTail = element.substring(1); validateSchemaElementId(elementId); - if (elementTail.length() == 0) { + if (elementTail.length() == 0) marshalers.put(elementId, new BooleanArgumentMarshaler()); - } else if (elementTail.equals("*")) { + else if (elementTail.equals("*")) marshalers.put(elementId, new StringArgumentMarshaler()); - } else if (elementTail.equals("#")) { + else if (elementTail.equals("#")) marshalers.put(elementId, new IntegerArgumentMarshaler()); - } else if (elementTail.equals("##")) { + else if (elementTail.equals("##")) marshalers.put(elementId, new DoubleArgumentMarshaler()); - } else { - throw new ArgsException(ArgsException.ErrorCode.INVALID_ARGUMENT_FORMAT, - elementId, elementTail); - } + else + throw new ArgsException(INVALID_ARGUMENT_FORMAT, elementId, elementTail); + } private void validateSchemaElementId(char elementId) throws ArgsException { if (!Character.isLetter(elementId)) { - throw new ArgsException(ArgsException.ErrorCode.INVALID_ARGUMENT_NAME, - elementId, null); - } - } - - private void parseArguments() throws ArgsException { - for (currentArgument = argsList.iterator(); currentArgument.hasNext(); ) { - String arg = currentArgument.next(); - parseArgument(arg); + throw new ArgsException(INVALID_ARGUMENT_NAME, elementId, null); } } - private void parseArgument(String arg) throws ArgsException { - if (arg.startsWith("-")) - parseElements(arg); - } - - private void parseElements(String arg) throws ArgsException { - for (int i = 1; i < arg.length(); i++) { - parseElement(arg.charAt(i)); + private void parseArgumentStrings(List argsList) throws ArgsException { + for (currentArgument = argsList.listIterator(); currentArgument.hasNext(); ) { + String argString = currentArgument.next(); + if (argString.startsWith("-")) { + parseArgumentCharacters(argString.substring(1)); + } else { + currentArgument.previous(); + break; + } } } - private void parseElement(char argChar) throws ArgsException { - if (setArgument(argChar)) - argsFound.add(argChar); - else { - throw new ArgsException(ArgsException.ErrorCode.UNEXPECTED_ARGUMENT, - argChar, null); + private void parseArgumentCharacters(String argChars) throws ArgsException { + for (int i = 0; i < argChars.length(); i++) { + parseArgumentCharacter(argChars.charAt(i)); } } - private boolean setArgument(char argChar) throws ArgsException { + private void parseArgumentCharacter(char argChar) throws ArgsException { ArgumentMarshaler m = marshalers.get(argChar); - if (m == null) - return false; - try { - m.set(currentArgument); - return true; - } catch (ArgsException e) { - e.setErrorArgumentId(argChar); - throw e; + if (m == null) { + throw new ArgsException(UNEXPECTED_ARGUMENT, argChar, null); + } else { + argsFound.add(argChar); + try { + m.set(currentArgument); + } catch (ArgsException e) { + e.setErrorArgumentId(argChar); + throw e; + } } } - public int cardinality() { - return argsFound.size(); + public boolean has(char arg) { + return argsFound.contains(arg); } - public String usage() { - if (schema.length() > 0) - return "-[" + schema + "]"; - else - return ""; + public int nextArgument() { + return currentArgument.nextIndex(); } public boolean getBoolean(char arg) { - ArgumentMarshaler am = marshalers.get(arg); - boolean b = false; - try { - b = am != null && (Boolean) am.get(); - } catch (ClassCastException e) { - b = false; - } - return b; + return BooleanArgumentMarshaler.getValue(marshalers.get(arg)); } public String getString(char arg) { - ArgumentMarshaler am = marshalers.get(arg); - try { - return am == null ? "" : (String) am.get(); - } catch (ClassCastException e) { - return ""; - } + return StringArgumentMarshaler.getValue(marshalers.get(arg)); } public int getInt(char arg) { - ArgumentMarshaler am = marshalers.get(arg); - try { - return am == null ? 0 : (Integer) am.get(); - } catch (ClassCastException e) { - return 0; - } + return IntegerArgumentMarshaler.getValue(marshalers.get(arg)); } public double getDouble(char arg) { - ArgumentMarshaler am = marshalers.get(arg); - try { - return am == null ? 0.0 : (Double) am.get(); - } catch (ClassCastException e) { - return 0.0; - } - } - - public boolean has(char arg) { - return argsFound.contains(arg); + return DoubleArgumentMarshaler.getValue(marshalers.get(arg)); } } diff --git a/src/main/java/chapter14/args/ArgsException.java b/src/main/java/chapter14/args/ArgsException.java index 4e9addb..5f6b985 100644 --- a/src/main/java/chapter14/args/ArgsException.java +++ b/src/main/java/chapter14/args/ArgsException.java @@ -51,10 +51,10 @@ public void setErrorCode(ErrorCode errorCode) { this.errorCode = errorCode; } - public String errorMessage() throws Exception { + public String errorMessage() { switch (errorCode) { case OK: - throw new Exception("TILT: Should not get here."); + return "TILT: Should not get here."; case UNEXPECTED_ARGUMENT: return String.format("Argument(s) -%c unexpected.", errorArgumentId); case MISSING_STRING: diff --git a/src/main/java/chapter14/args/ArgumentMarshaler.java b/src/main/java/chapter14/args/ArgumentMarshaler.java index 8a641aa..ebf4a48 100644 --- a/src/main/java/chapter14/args/ArgumentMarshaler.java +++ b/src/main/java/chapter14/args/ArgumentMarshaler.java @@ -4,6 +4,4 @@ public interface ArgumentMarshaler { void set(Iterator currentArgument) throws ArgsException; - - Object get(); } diff --git a/src/main/java/chapter14/args/BooleanArgumentMarshaler.java b/src/main/java/chapter14/args/BooleanArgumentMarshaler.java index 4619a7e..8ec3e0e 100644 --- a/src/main/java/chapter14/args/BooleanArgumentMarshaler.java +++ b/src/main/java/chapter14/args/BooleanArgumentMarshaler.java @@ -10,8 +10,11 @@ public void set(Iterator currentArgument) throws ArgsException { booleanValue = true; } - @Override - public Object get() { - return booleanValue; + public static boolean getValue(ArgumentMarshaler am) { + if (am != null && am instanceof BooleanArgumentMarshaler) { + return ((BooleanArgumentMarshaler) am).booleanValue; + } else { + return false; + } } } \ No newline at end of file diff --git a/src/main/java/chapter14/args/DoubleArgumentMarshaler.java b/src/main/java/chapter14/args/DoubleArgumentMarshaler.java index 16544d3..e737b01 100644 --- a/src/main/java/chapter14/args/DoubleArgumentMarshaler.java +++ b/src/main/java/chapter14/args/DoubleArgumentMarshaler.java @@ -22,8 +22,11 @@ public void set(Iterator currentArgument) throws ArgsException { } } - @Override - public Object get() { - return doubleValue; + public static double getValue(ArgumentMarshaler am) { + if (am != null && am instanceof DoubleArgumentMarshaler) { + return ((DoubleArgumentMarshaler) am).doubleValue; + } else { + return 0.0; + } } } \ No newline at end of file diff --git a/src/main/java/chapter14/args/IntegerArgumentMarshaler.java b/src/main/java/chapter14/args/IntegerArgumentMarshaler.java index ee040a5..5162230 100644 --- a/src/main/java/chapter14/args/IntegerArgumentMarshaler.java +++ b/src/main/java/chapter14/args/IntegerArgumentMarshaler.java @@ -22,8 +22,11 @@ public void set(Iterator currentArgument) throws ArgsException { } } - @Override - public Object get() { - return intValue; + public static int getValue(ArgumentMarshaler am) { + if (am != null && am instanceof IntegerArgumentMarshaler) { + return ((IntegerArgumentMarshaler) am).intValue; + } else { + return 0; + } } } \ No newline at end of file diff --git a/src/main/java/chapter14/args/StringArgumentMarshaler.java b/src/main/java/chapter14/args/StringArgumentMarshaler.java index 2eef6d9..b0698e4 100644 --- a/src/main/java/chapter14/args/StringArgumentMarshaler.java +++ b/src/main/java/chapter14/args/StringArgumentMarshaler.java @@ -17,8 +17,11 @@ public void set(Iterator currentArgument) throws ArgsException { } } - @Override - public Object get() { - return stringValue; + public static String getValue(ArgumentMarshaler am) { + if (am != null && am instanceof StringArgumentMarshaler) { + return ((StringArgumentMarshaler) am).stringValue; + } else { + return ""; + } } } \ No newline at end of file diff --git a/src/test/java/chapter14/args/ArgsTest.java b/src/test/java/chapter14/args/ArgsTest.java index b28ab04..0b331a2 100644 --- a/src/test/java/chapter14/args/ArgsTest.java +++ b/src/test/java/chapter14/args/ArgsTest.java @@ -20,7 +20,7 @@ void noSchemaAndArguments() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isZero(); + assertThat(args.nextArgument()).isZero(); } @DisplayName("schema가 없고 argument가 1개 있는 경우") @@ -52,7 +52,6 @@ void multipleSchemasButNoArguments() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isZero(); assertThat(args.has('x')).isFalse(); assertThat(args.has('y')).isFalse(); assertThat(args.has('z')).isFalse(); @@ -108,7 +107,6 @@ void spacesInFormat() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); } @@ -124,7 +122,6 @@ void simpleBooleanPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isOne(); assertThat(args.getBoolean('x')).isTrue(); } @@ -139,7 +136,6 @@ void simpleBooleanMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); assertThat(args.has('z')).isFalse(); @@ -172,7 +168,6 @@ void simpleStringPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getString('x')).isEqualTo("param"); } @@ -188,7 +183,6 @@ void simpleStringMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); assertThat(args.has('z')).isFalse(); @@ -221,7 +215,6 @@ void simpleIntPresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getInt('x')).isEqualTo(42); } @@ -237,7 +230,6 @@ void simpleIntMultiplePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isEqualTo(2); assertThat(args.has('x')).isTrue(); assertThat(args.has('y')).isTrue(); assertThat(args.has('z')).isFalse(); @@ -270,7 +262,6 @@ void simpleDoublePresent() throws Exception { Args args = new Args(schema, arguments); //then - assertThat(args.cardinality()).isOne(); assertThat(args.has('x')).isTrue(); assertThat(args.getDouble('x')).isEqualTo(42.3); } diff --git a/src/test/java/chapter14/args/BooleanArgumentMarshalerTest.java b/src/test/java/chapter14/args/BooleanArgumentMarshalerTest.java new file mode 100644 index 0000000..2b7f28d --- /dev/null +++ b/src/test/java/chapter14/args/BooleanArgumentMarshalerTest.java @@ -0,0 +1,52 @@ +package chapter14.args; + +import org.junit.jupiter.api.Test; + +import java.util.Iterator; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + + +class BooleanArgumentMarshalerTest { + + @Test + void getValueNotPresent() { + //given + ArgumentMarshaler am = new BooleanArgumentMarshaler(); + + //when, then + assertThat(BooleanArgumentMarshaler.getValue(am)).isFalse(); + } + + @Test + void getValuePresent() throws ArgsException { + //given + Iterator list = List.of("test").iterator(); + + //when + ArgumentMarshaler am = new BooleanArgumentMarshaler(); + am.set(list); + + //then + assertThat(BooleanArgumentMarshaler.getValue(am)).isTrue(); + } + + @Test + void getValueNotEqualsType() throws ArgsException { + //given + Iterator list = List.of("param").iterator(); + + //when + ArgumentMarshaler otherType = new StringArgumentMarshaler(); + otherType.set(list); + + //then + assertThat(BooleanArgumentMarshaler.getValue(otherType)).isFalse(); + } + + @Test + void getValueNull() { + assertThat(BooleanArgumentMarshaler.getValue(null)).isFalse(); + } +} \ No newline at end of file diff --git a/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java b/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java index 609941e..354c8c2 100644 --- a/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java +++ b/src/test/java/chapter14/args/DoubleArgumentMarshalerTest.java @@ -11,7 +11,6 @@ import static org.assertj.core.api.Assertions.catchException; class DoubleArgumentMarshalerTest { - private ArgumentMarshaler am = new DoubleArgumentMarshaler(); @DisplayName("값을 파싱할 수 없는 경우") @Test @@ -20,6 +19,7 @@ void invalidDouble() { Iterator argument = List.of("Forty two").iterator(); //when + ArgumentMarshaler am = new DoubleArgumentMarshaler(); Exception exception = catchException(() -> am.set(argument)); //then @@ -37,6 +37,7 @@ void missingDouble() { Iterator argument = Collections.emptyIterator(); //when + ArgumentMarshaler am = new DoubleArgumentMarshaler(); Exception exception = catchException(() -> am.set(argument)); //then @@ -45,4 +46,44 @@ void missingDouble() { ArgsException e = (ArgsException) exception; assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_DOUBLE); } + + @Test + void getValueNotPresent() { + //given + ArgumentMarshaler am = new DoubleArgumentMarshaler(); + + //when, then + assertThat(DoubleArgumentMarshaler.getValue(am)).isZero(); + } + + @Test + void getValuePresent() throws ArgsException { + //given + Iterator list = List.of("42.3").iterator(); + + //when + ArgumentMarshaler am = new DoubleArgumentMarshaler(); + am.set(list); + + //then + assertThat(DoubleArgumentMarshaler.getValue(am)).isEqualTo(42.3); + } + + @Test + void getValueNotEqualsType() throws ArgsException { + //given + Iterator list = List.of("param").iterator(); + + //when + ArgumentMarshaler otherType = new StringArgumentMarshaler(); + otherType.set(list); + + //then + assertThat(DoubleArgumentMarshaler.getValue(otherType)).isZero(); + } + + @Test + void getValueNull() { + assertThat(DoubleArgumentMarshaler.getValue(null)).isZero(); + } } \ No newline at end of file diff --git a/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java b/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java index 9135c20..9c94d1e 100644 --- a/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java +++ b/src/test/java/chapter14/args/IntegerArgumentMarshalerTest.java @@ -11,7 +11,6 @@ import static org.assertj.core.api.Assertions.catchException; class IntegerArgumentMarshalerTest { - private ArgumentMarshaler am = new IntegerArgumentMarshaler(); @DisplayName("Integer Argument 값을 파싱할 수 없는 경우") @Test @@ -20,6 +19,7 @@ void invalidInteger() { Iterator argument = List.of("Forty two").iterator(); //when + ArgumentMarshaler am = new IntegerArgumentMarshaler(); Exception exception = catchException(() -> am.set(argument)); //then @@ -37,6 +37,7 @@ void missingInteger() { Iterator argument = Collections.emptyIterator(); //when + ArgumentMarshaler am = new IntegerArgumentMarshaler(); Exception exception = catchException(() -> am.set(argument)); //then @@ -45,4 +46,44 @@ void missingInteger() { ArgsException e = (ArgsException) exception; assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_INTEGER); } + + @Test + void getValueNotPresent() { + //given + ArgumentMarshaler am = new IntegerArgumentMarshaler(); + + //when, then + assertThat(IntegerArgumentMarshaler.getValue(am)).isZero(); + } + + @Test + void getValuePresent() throws ArgsException { + //given + Iterator list = List.of("42").iterator(); + + //when + ArgumentMarshaler am = new IntegerArgumentMarshaler(); + am.set(list); + + //then + assertThat(IntegerArgumentMarshaler.getValue(am)).isEqualTo(42); + } + + @Test + void getValueNotEqualsType() throws ArgsException { + //given + Iterator list = List.of("param").iterator(); + + //when + ArgumentMarshaler otherType = new StringArgumentMarshaler(); + otherType.set(list); + + //then + assertThat(IntegerArgumentMarshaler.getValue(otherType)).isZero(); + } + + @Test + void getValueNull() { + assertThat(IntegerArgumentMarshaler.getValue(null)).isZero(); + } } \ No newline at end of file diff --git a/src/test/java/chapter14/args/StringArgumentMarshalerTest.java b/src/test/java/chapter14/args/StringArgumentMarshalerTest.java index 9f7772c..fed79ca 100644 --- a/src/test/java/chapter14/args/StringArgumentMarshalerTest.java +++ b/src/test/java/chapter14/args/StringArgumentMarshalerTest.java @@ -5,12 +5,12 @@ import java.util.Collections; import java.util.Iterator; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchException; class StringArgumentMarshalerTest { - private ArgumentMarshaler am = new StringArgumentMarshaler(); @DisplayName("Argument 값이 없는 경우") @Test @@ -19,6 +19,7 @@ void missingString() { Iterator argument = Collections.emptyIterator(); //when + ArgumentMarshaler am = new StringArgumentMarshaler(); Exception exception = catchException(() -> am.set(argument)); //then @@ -27,4 +28,46 @@ void missingString() { ArgsException e = (ArgsException) exception; assertThat(e.getErrorCode()).isEqualTo(ArgsException.ErrorCode.MISSING_STRING); } + + + @Test + void getValueNotPresent() { + //given + ArgumentMarshaler am = new StringArgumentMarshaler(); + + //when, then + assertThat(StringArgumentMarshaler.getValue(am)).isEmpty(); + } + + @Test + void getValuePresent() throws ArgsException { + //given + Iterator list = List.of("param").iterator(); + + //when + ArgumentMarshaler am = new StringArgumentMarshaler(); + am.set(list); + + //then + assertThat(StringArgumentMarshaler.getValue(am)).isEqualTo("param"); + } + + @Test + void getValueNotEqualsType() throws ArgsException { + //given + Iterator list = List.of("42").iterator(); + + //when + ArgumentMarshaler otherType = new IntegerArgumentMarshaler(); + otherType.set(list); + + //then + assertThat(StringArgumentMarshaler.getValue(otherType)).isEmpty(); + } + + + @Test + void getValueNull() { + assertThat(StringArgumentMarshaler.getValue(null)).isEmpty(); + } } \ No newline at end of file