package com.lexicalscope.jewel.cli;
import static com.lexicalscope.fluentreflection.FluentReflection.*;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import com.lexicalscope.jewel.cli.specification.ParsedOptionSpecification;
public class TestOptionSpecificationImpl {
@Rule public ExpectedException exception = ExpectedException.none();
public interface HasShortName {
@Option(shortName = "n") String getName1();
@Option String getName2();
}
public interface ShortName {
@Option(shortName = "") String getName0();
@Option(shortName = "n") String getName1();
@Option(shortName = "excessive") String getName2();
}
public interface LongName {
@Option() String getName0();
@Option(longName = "totallyDifferent") String getName1();
@Option(longName = "name2") String getName2();
}
public interface MultipleLongNames {
@Option(longName = { "name", "alternativename" }) String getName();
}
public interface InvalidLongName {
@Option(longName = "") String getName0();
}
public interface SingleCharacterBoolean {
@Option boolean f();
}
public interface Value {
@Option String getName();
@Option boolean getDebug();
}
public interface Name {
@Option String getName();
@Option String name();
@Option boolean isDebug();
@Option boolean debug();
}
public interface Type {
@Option String getString();
@Option Integer getInteger();
@Option int getInt();
@Option List<String> getStringList();
@SuppressWarnings("rawtypes") @Option List getList();
}
public interface MultiValued {
@Option List<String> getStringList();
@SuppressWarnings("rawtypes") @Option List getList();
}
public interface HasOptionalOption {
@Option String getName1();
@Option String getName2();
boolean isName2();
}
public interface ToString {
@Option(longName = "aLongName") String getLongName();
@Option(longName = { "aLongName", "alternativeLongName" }) String getMultipleLongNames();
@Option(shortName = "s") String getShortName();
@Option String getOptional();
boolean isOptional();
@Option List<String> getOptionalMulti();
boolean isOptionalMulti();
@Option(description = "this is a description") List<String> getDescription();
@Option(description = "this is a description", shortName = "a") List<String> getAll();
boolean isAll();
}
public interface Summary {
@Option(shortName = "s") String getShortName();
@Option(longName = "aLongName") String getLongName();
@Option(description = "this is a description") String getWithDescription();
@Option(longName = "aLongName", shortName = "s") String getLongNameShortName();
@Option(pattern = "[a-z]") char getPattern();
@Option String getOptional();
boolean isOptional();
@Option List<String> getList();
@Option List<String> getOptionalList();
boolean isOptionalList();
@Option(longName = "aLongName", shortName = "s") List<String> getOptionalListShortNameLongName();
boolean isOptionalListShortNameLongName();
}
@Test public void testSumary() throws NoSuchMethodException {
checkSummary("getShortName", "--shortName -s value");
checkSummary("getLongName", "--aLongName value");
checkSummary("getWithDescription", "--withDescription value : this is a description");
checkSummary("getLongNameShortName", "--aLongName -s value");
checkSummary("getOptional", "[--optional value]");
checkSummary("getList", "--list value...");
checkSummary("getOptionalList", "[--optionalList value...]");
checkSummary("getOptionalListShortNameLongName", "[--aLongName -s value...]");
checkSummary("getPattern", "--pattern /[a-z]/");
// TODO[tim]: test summary
// TODO[tim]: test option specifications (plural) summary.
}
private void checkSummary(final String method, final String expectedSummary) throws NoSuchMethodException {
assertEquals(expectedSummary, new ParsedOptionSummary(createOption(Summary.class, method)).toString());
}
@Test public void testToString() throws NoSuchMethodException {
assertEquals("--aLongName value", createOption(ToString.class, "getLongName").toString());
assertEquals("--aLongName --alternativeLongName value", createOption(ToString.class, "getMultipleLongNames")
.toString());
assertEquals("--shortName -s value", createOption(ToString.class, "getShortName").toString());
assertEquals("[--optional value]", createOption(ToString.class, "getOptional").toString());
assertEquals("[--optionalMulti value...]", createOption(ToString.class, "getOptionalMulti").toString());
assertEquals("--description value... : this is a description", createOption(ToString.class, "getDescription")
.toString());
assertEquals("[--all -a value...] : this is a description", createOption(ToString.class, "getAll").toString());
}
@Test public void testIsMultiValued() throws NoSuchMethodException {
assertTrue(createOption(MultiValued.class, "getStringList").isMultiValued());
assertTrue(createOption(MultiValued.class, "getList").isMultiValued());
}
@Test public void testGetType() throws NoSuchMethodException {
assertEquals(String.class, createOption(Type.class, "getString").getType());
assertEquals(Integer.class, createOption(Type.class, "getInteger").getType());
assertEquals(int.class, createOption(Type.class, "getInt").getType());
assertEquals(String.class, createOption(Type.class, "getStringList").getType());
assertEquals(String.class, createOption(Type.class, "getList").getType());
}
@Test public void testGetName() throws SecurityException, NoSuchMethodException {
assertThat(createOption(Name.class, "getName").getLongName(), contains("name"));
assertThat(createOption(Name.class, "name").getLongName(), contains("name"));
assertThat(createOption(Name.class, "isDebug").getLongName(), contains("debug"));
assertThat(createOption(Name.class, "debug").getLongName(), contains("debug"));
}
@Test public void testGetShortName() throws SecurityException, NoSuchMethodException {
assertEquals(0, createOption(ShortName.class, "getName0").getShortNames().size());
assertEquals("n", createOption(ShortName.class, "getName1").getShortNames().get(0));
assertEquals("e", createOption(ShortName.class, "getName2").getShortNames().get(0));
}
@Test public void testGetLongName() throws SecurityException, NoSuchMethodException {
assertThat(createOption(LongName.class, "getName0").getLongName(), contains("name0"));
assertThat(createOption(LongName.class, "getName1").getLongName(), contains("totallyDifferent"));
assertThat(createOption(LongName.class, "getName2").getLongName(), contains("name2"));
}
@Test public void testMultipleLongNames() throws SecurityException, NoSuchMethodException {
assertThat(createOption(MultipleLongNames.class, "getName").getLongName(), contains("name", "alternativename"));
}
@Test public void testEmptyLongNameIsNotAllowed() throws SecurityException, NoSuchMethodException {
exception.expect(InvalidOptionSpecificationException.class);
exception.expectMessage("option public java.lang.String getName0() long name cannot be blank");
createOption(InvalidLongName.class, "getName0");
}
@Test public void testHasValue() throws SecurityException, NoSuchMethodException {
assertTrue(createOption(Value.class, "getName").hasValue());
assertFalse(createOption(Value.class, "getDebug").hasValue());
}
@Test public void testHasShortName() throws SecurityException, NoSuchMethodException {
assertTrue(createOption(HasShortName.class, "getName1").hasShortName());
assertFalse(createOption(HasShortName.class, "getName2").hasShortName());
}
@Test public void testIsOptional() throws SecurityException, NoSuchMethodException {
assertFalse(createOption(HasOptionalOption.class, "getName1").isOptional());
assertTrue(createOption(HasOptionalOption.class, "getName2").isOptional());
}
@Test public void testSingleCharacterBoolean() throws SecurityException, NoSuchMethodException {
assertTrue(createOption(SingleCharacterBoolean.class, "f").isBoolean());
}
private ParsedOptionSpecification createOption(final Class<?> klass, final String methodName)
throws NoSuchMethodException {
final Method method = klass.getMethod(methodName, (Class[]) null);
return new ConvertGetterMethodToParsedOptionSpecification(type(klass)).convert(method(method));
}
}