Skip to content

Commit

Permalink
✨ 14. 점진적인 개선 - Add String (#3)
Browse files Browse the repository at this point in the history
* feat: String 인수 유형 추가 버전 / 목록 14-10

* test: String 인수 유형 추가 버전 테스트 추가

* fix: schema 오타 수정
  • Loading branch information
viiviii authored May 6, 2022
1 parent dc2e002 commit 2bf8e17
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 67 deletions.
17 changes: 12 additions & 5 deletions src/main/java/chapter14/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
155 changes: 118 additions & 37 deletions src/main/java/chapter14/args/Args.java
Original file line number Diff line number Diff line change
@@ -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<Character> unexpectedArguments = new TreeSet<>();
private Map<Character, Boolean> booleanArgs = new HashMap<>();
private int numberOfArguments = 0;
private Map<Character, String> stringArgs = new HashMap<>();
private Set<Character> 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;
Expand All @@ -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);
}
Expand All @@ -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 "";
}
}
Expand All @@ -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;
}
}
40 changes: 32 additions & 8 deletions src/test/java/chapter14/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 2bf8e17

Please sign in to comment.