/** Leniently parses the specified String as an {@code Range} value and return the result. A range string can * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}. * @param range the value range string to parse * @return a new {@code Range} value */ public static Range valueOf(String range) { range = range.trim(); boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith(".."); int min = -1, max = -1; boolean variable = false; int dots = -1; if ((dots = range.indexOf("..")) >= 0) { min = parseInt(range.substring(0, dots), 0); max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE); variable = max == Integer.MAX_VALUE; } else { max = parseInt(range, Integer.MAX_VALUE); variable = max == Integer.MAX_VALUE; min = variable ? 0 : max; } Range result = new Range(min, max, variable, unspecified, range); return result; } private static int parseInt(String str, int defaultValue) {
@Test public void testDefaultArity_Field() throws Exception { class ImplicitBoolField { @Option(names = "-x") boolean x; @Option(names = "-y") int y; @Option(names = "-z") List<String> z; @Parameters boolean a; @Parameters int b; @Parameters List<String> c; } assertEquals(Range.valueOf("0"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("x"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("y"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("z"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("a"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("b"))); assertEquals(Range.valueOf("0..1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("c"))); }
@Test public void testArityForOption_arrayFieldImplicitArity1() throws Exception { class ImplicitList { @Option(names = "-a") int[] intArray; } Range arity = Range.optionArity(ImplicitList.class.getDeclaredField("intArray")); assertEquals(Range.valueOf("1"), arity); assertEquals("1", arity.toString()); }
for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) { Range indexRange = positionalParam.index(); if (!indexRange.contains(position) || positionalParam.typedValueAtPosition.get(position) != null) { continue;
/** Leniently parses the specified String as an {@code Range} value and return the result. A range string can * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}. * @param range the value range string to parse * @return a new {@code Range} value */ public static Range valueOf(String range) { range = range.trim(); boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith(".."); int min = -1, max = -1; boolean variable = false; int dots = -1; if ((dots = range.indexOf("..")) >= 0) { min = parseInt(range.substring(0, dots), 0); max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE); variable = max == Integer.MAX_VALUE; } else { max = parseInt(range, Integer.MAX_VALUE); variable = max == Integer.MAX_VALUE; min = variable ? 0 : max; } Range result = new Range(min, max, variable, unspecified, range); return result; } private static int parseInt(String str, int defaultValue) {
@Test public void testDefaultArity_Field() throws Exception { class ImplicitBoolField { @Option(names = "-x") boolean x; @Option(names = "-y") int y; @Option(names = "-z") List<String> z; @Parameters boolean a; @Parameters int b; @Parameters List<String> c; } assertEquals(Range.valueOf("0"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("x"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("y"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("z"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("a"))); assertEquals(Range.valueOf("1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("b"))); assertEquals(Range.valueOf("0..1"), Range.defaultArity(ImplicitBoolField.class.getDeclaredField("c"))); }
@Test public void testConstructorDisallowsNegativeRange() { try { new Range(-1, 0, true, true, ""); fail("Expected exception"); } catch (InitializationException ex) { assertEquals("Invalid negative range (min=-1, max=0)", ex.getMessage()); } try { new Range(-3, -1, true, true, ""); fail("Expected exception"); } catch (InitializationException ex) { assertEquals("Invalid negative range (min=-3, max=-1)", ex.getMessage()); } }
@Test public void testConstructorDisallowsInvalidRange() { try { new Range(1, 0, true, true, ""); fail("Expected exception"); } catch (InitializationException ex) { assertEquals("Invalid range (min=1, max=0)", ex.getMessage()); } try { new Range(3, 1, true, true, ""); fail("Expected exception"); } catch (InitializationException ex) { assertEquals("Invalid range (min=3, max=1)", ex.getMessage()); } }
@Test(expected = InitializationException.class) public void testRangeConstructorDisallowsNegativeMax() { new Range(0, -2, false, false, ""); }
@Test(expected = InitializationException.class) public void testRangeConstructorDisallowsNegativeMin() { new Range(-1, 2, false, false, ""); }
@Test public void testParameterIndex_WhenDefined() throws Exception { class ImplicitBoolField { @Parameters(index = "2..3") boolean boolSingleValue; } Range arity = Range.parameterIndex(ImplicitBoolField.class.getDeclaredField("boolSingleValue")); assertEquals(3, arity.max); assertEquals(2, arity.min); assertEquals(false, arity.isVariable); assertEquals("2..3", arity.toString()); }
/** Returns a new Range object with the {@code min} value replaced by the specified value. * The {@code max} of the returned Range is guaranteed not to be less than the new {@code min} value. * @param newMin the {@code min} value of the returned Range object * @return a new Range object with the specified {@code min} value */ public Range min(int newMin) { return new Range(newMin, Math.max(newMin, max), isVariable, isUnspecified, originalValue); }
/** Returns a new {@code Range} based on the {@link Option#arity()} annotation on the specified field, * or the field type's default arity if no arity was specified. * @param field the field whose Option annotation to inspect * @return a new {@code Range} based on the Option arity annotation on the specified field */ public static Range optionArity(Field field) { return optionArity(new TypedMember(field)); } private static Range optionArity(TypedMember member) {
/** Returns a new {@code Range} based on the {@link Parameters#index()} annotation on the specified field. * @param field the field whose Parameters annotation to inspect * @return a new {@code Range} based on the Parameters index annotation on the specified field */ public static Range parameterIndex(Field field) { return parameterIndex(new TypedMember(field)); } private static Range parameterIndex(TypedMember member) {
@Test public void testArityForOption_intFieldImplicitArity1() throws Exception { Range arity = Range.optionArity(SupportedTypes2.class.getDeclaredField("intField")); assertEquals(Range.valueOf("1"), arity); assertEquals("1", arity.toString()); } @Test
@Test public void testArityForParameters_booleanFieldImplicitArity1() throws Exception { class ImplicitBoolField { @Parameters boolean boolSingleValue; } Range arity = Range.parameterArity(ImplicitBoolField.class.getDeclaredField("boolSingleValue")); assertEquals(Range.valueOf("1"), arity); assertEquals("1", arity.toString()); } @Test
static Range adjustForType(Range result, TypedMember member) { return result.isUnspecified ? defaultArity(member) : result; } /** Returns the default arity {@code Range}: for {@link Option options} this is 0 for booleans and 1 for
/** Returns a new Range object with the {@code isUnspecified} value replaced by the specified value. * @param unspecified the {@code unspecified} value of the returned Range object * @return a new Range object with the specified {@code unspecified} value */ public Range unspecified(boolean unspecified) { return new Range(min, max, isVariable, unspecified, originalValue); }