Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/main/java/chapter14/Application.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
121 changes: 121 additions & 0 deletions src/main/java/chapter14/args/Args.java
Original file line number Diff line number Diff line change
@@ -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<Character> unexpectedArguments = new TreeSet<>();
private Map<Character, Boolean> 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);
}
}
37 changes: 37 additions & 0 deletions src/test/java/chapter14/ApplicationTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
39 changes: 39 additions & 0 deletions src/test/java/chapter14/MainMethodTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
123 changes: 123 additions & 0 deletions src/test/java/chapter14/args/ArgsTest.java
Original file line number Diff line number Diff line change
@@ -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();
}
}