/* 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.limiters; import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; import static se.softhouse.jargo.Arguments.integerArgument; import static se.softhouse.jargo.Arguments.stringArgument; import static se.softhouse.jargo.Arguments.withParser; import static se.softhouse.jargo.limiters.FooLimiter.foos; import static se.softhouse.jargo.utils.Assertions2.assertThat; import static se.softhouse.jargo.utils.ExpectedTexts.expected; import org.junit.Test; import se.softhouse.common.testlib.Explanation; import se.softhouse.jargo.Argument; import se.softhouse.jargo.ArgumentBuilder; import se.softhouse.jargo.ArgumentException; import se.softhouse.jargo.Usage; import se.softhouse.jargo.stringparsers.custom.Port; import se.softhouse.jargo.stringparsers.custom.PortParser; import com.google.common.base.Predicate; import com.google.common.collect.Range; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Test for {@link ArgumentBuilder#limitTo(Predicate)} */ public class LimiterTest { @Test public void testRangeLimiter() throws ArgumentException { Argument<Integer> limitedNumber = integerArgument().limitTo(Range.closed(0, 4)).build(); try { limitedNumber.parse("5"); fail("5 shouldn't be valid since it's higher than 4"); } catch(ArgumentException expected) { assertThat(expected.getMessageAndUsage()).isEqualTo(expected("limiterOutOfRange")); } assertThat(limitedNumber.parse("4")).isEqualTo(4); assertThat(integerArgument().limitTo(Range.closed(1, 3)).defaultValue(1).parse("2")).isEqualTo(2); } @Test public void testThatSeveralLimiterAreCombinedIntoAnAndLimiter() { try { integerArgument("-n").limitTo(Range.closed(1, 2)).limitTo(Range.closed(0, 4)).parse("-n", "3"); fail("3 should not be allowed, limiter override lost previously set limiter"); } catch(ArgumentException expected) { assertThat(expected).hasMessage("'3' is not And([1‥2],[0‥4])"); } } @Test public void testRepeatedWithLimiter() { try { stringArgument("-i", "--index").limitTo(foos()).repeated().parse("-i", "foo", "--index", "bar"); fail("bar shouldn't be allowed"); } catch(ArgumentException expected) { // This message is from ListPredicate that throws IllegalArgumentException so // this verifies that the message of the wrapped exception is used. assertThat(expected).hasMessage("'bar' is not foo"); } } @Test public void testArityOfWithLimiter() { try { stringArgument("-f", "--foos").required().limitTo(foos()).arity(2).parse("-f", "foo", "bar"); } catch(ArgumentException expected) { Usage usage = expected.getMessageAndUsage(); assertThat(usage).isEqualTo(expected("arityWithLimitedValues")); } } @Test(expected = ArgumentException.class) public void testSplittingAndLimiting() throws ArgumentException { stringArgument("-n").separator("=").limitTo(foos()).splitWith(",").parse("-n=foo,bar"); } @Test(expected = IllegalStateException.class) @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED", justification = Explanation.FAIL_FAST) public void testThatDefaultValuesAreLimited() { stringArgument("-n").limitTo(foos()).defaultValue("bar").build(); } @Test public void testThatLimiterIsNotCalledTooOften() throws ArgumentException { ProfilingLimiter<Integer> profiler = new ProfilingLimiter<Integer>(); integerArgument("-n").limitTo(profiler).repeated().parse("-n", "1", "-n", "-2"); assertThat(profiler.limitationsMade).isEqualTo(2); } @Test public void testThatRangeLimiterDoesNotCallToStringOnComparedObjectsInVain() throws ArgumentException { Port min = new Port(1); Argument<Port> portArgument = withParser(new PortParser()).limitTo(Range.closed(min, Port.MAX)).build(); try { portArgument.parse("-1"); fail("-1 shouldn't be valid since it's not within the range of valid port numbers"); } catch(ArgumentException expected) { assertThat(min.toStringCallCount).isZero(); } // Also make sure the range accepts valid ports assertThat(portArgument.parse("2")).isEqualTo(new Port(2)); } @Test public void testThatLimiterForSuperClassWorks() { try { integerArgument("-n").limitTo(new LowNumbers()).parse("-n", "5"); fail("5 should not be allowed"); } catch(ArgumentException expected) { assertThat(expected).hasMessage("'5' is not Any number between 0 and 4 (inclusive)"); } } @Test public void testThatCauseIsSetForLimitedValue() throws Exception { final IllegalArgumentException originalException = new IllegalArgumentException(); try { integerArgument().limitTo(new Predicate<Integer>(){ @Override public boolean apply(Integer input) { throw originalException; } }).parse("1"); fail("Limiter should have propagated originalException"); } catch(ArgumentException expected) { assertThat(expected.getCause()).isSameAs(originalException); } } }