/* Copyright 2013 Jonatan Jönsson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.softhouse.jargo;
import static java.util.Arrays.asList;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
import static se.softhouse.jargo.Arguments.integerArgument;
import static se.softhouse.jargo.Arguments.stringArgument;
import static se.softhouse.jargo.utils.Assertions2.assertThat;
import static se.softhouse.jargo.utils.ExpectedTexts.expected;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import se.softhouse.common.testlib.Explanation;
import se.softhouse.jargo.CommandLineParserInstance.ArgumentIterator;
import se.softhouse.jargo.internal.Texts.ProgrammaticErrors;
import se.softhouse.jargo.internal.Texts.UserErrors;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Tests for {@link ArgumentBuilder#arity(int)} and {@link ArgumentBuilder#variableArity()}
*/
public class ArityArgumentTest
{
@Test
public void testTwoParametersForNamedArgument() throws ArgumentException
{
String[] args = {"--numbers", "5", "6", "Rest", "Of", "Arguments"};
Argument<List<Integer>> numbers = integerArgument("--numbers").arity(2).build();
Argument<List<String>> unhandledArguments = stringArgument().variableArity().build();
ParsedArguments parsed = CommandLineParser.withArguments(numbers, unhandledArguments).parse(args);
assertThat(parsed.get(numbers)).isEqualTo(Arrays.asList(5, 6));
assertThat(parsed.get(unhandledArguments)).isEqualTo(Arrays.asList("Rest", "Of", "Arguments"));
}
@Test
public void testVariableArityForNamedArgument() throws ArgumentException
{
assertThat(integerArgument("--numbers").variableArity().parse("--numbers", "5", "6")).isEqualTo(asList(5, 6));
}
@Test(expected = UnsupportedOperationException.class)
public void testThatParsedValuesIsWrappedInAnUnmodifiableList() throws ArgumentException
{
integerArgument("--numbers").variableArity().parse("--numbers", "2", "3").add(1);
}
// This is what's being tested
@SuppressWarnings("deprecation")
@Test(expected = IllegalStateException.class)
public void testThatArityAndSplitWithIncompabilityIsEnforced()
{
integerArgument().arity(2).splitWith(",");
}
@Test
public void testThatArityOfOneIsForbidden()
{
try
{
integerArgument().arity(1);
fail("Arity should require at least 2 parameters");
}
catch(IllegalArgumentException expected)
{
assertThat(expected).hasMessage(String.format(ProgrammaticErrors.TO_SMALL_ARITY, 1));
}
}
@Test
public void testThatErrorMessageForMissingParameterLooksGoodForFixedArityArguments()
{
try
{
integerArgument("--numbers").arity(2).parse("--numbers", "5");
fail("Missing integer not detected");
}
catch(ArgumentException expected)
{
assertThat(expected).hasMessage(String.format(UserErrors.MISSING_NTH_PARAMETER, "second", "<integer>", "--numbers"));
}
}
@Test
public void testThatUsageTextForArityLooksGood()
{
Argument<List<String>> foo = stringArgument("--foo").arity(3).description("MetaDescShouldBeDisplayedThreeTimes").build();
Argument<List<Integer>> bar = integerArgument("--bar").arity(2).description("MetaDescShouldBeDisplayedTwoTimes").build();
Argument<List<Integer>> zoo = integerArgument("--zoo").variableArity().description("MetaDescShouldIndicateVariableAmount").build();
Argument<List<Integer>> boo = integerArgument().variableArity().description("MetaDescShouldIndicateVariableAmount").build();
Usage usage = CommandLineParser.withArguments(foo, bar, zoo, boo).usage();
assertThat(usage).isEqualTo(expected("metaDescriptionsForArityArgument"));
}
@Test
public void testUsageTextForEmptyList()
{
Usage usage = stringArgument().arity(2).defaultValue(Collections.<String>emptyList()).usage();
assertThat(usage).contains("Default: Empty list");
}
@Test
public void testThatNrOfRemainingArgumentsGivesTheCorrectCapacity()
{
ArgumentIterator args = ArgumentIterator.forArguments(Arrays.asList("foo"), Collections.<String, Argument<?>>emptyMap());
assertThat(args.nrOfRemainingArguments()).isEqualTo(1);
args.next(); // Consume one argument
assertThat(args.nrOfRemainingArguments()).isEqualTo(0);
}
@Test
@SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED", justification = Explanation.FAIL_FAST)
public void testThatTwoUnnamedVariableArityArgumentsIsIllegal()
{
// This is illegal because the parser couldn't possibly know when the integerArgument ends
// and the stringArgument begins
Argument<List<Integer>> numbers = integerArgument().variableArity().build();
Argument<List<String>> strings = stringArgument().variableArity().build();
try
{
CommandLineParser.withArguments(numbers, strings);
fail("several variable arity parsers should be forbidden");
}
catch(IllegalArgumentException expected)
{
assertThat(expected).hasMessage(String.format(ProgrammaticErrors.SEVERAL_VARIABLE_ARITY_PARSERS, "[<integer>, <string>]"));
}
}
}