diff --git a/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java b/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java index bf2566bd7..d882e055b 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java @@ -69,10 +69,6 @@ public PositionalArgumentMetadata(int position, String title, throw new IllegalArgumentException("Position must be >= 0"); if (title == null) throw new NullPointerException("title cannot be null"); - if (path == null) - throw new NullPointerException("path cannot be null"); - if (!path.iterator().hasNext()) - throw new IllegalArgumentException("path cannot be empty"); this.position = position; this.title = title; @@ -82,7 +78,12 @@ public PositionalArgumentMetadata(int position, String title, this.restrictions = restrictions != null ? AirlineUtils.unmodifiableListCopy(restrictions) : Collections. emptyList(); this.provider = typeConverterProvider != null ? typeConverterProvider : new DefaultTypeConverterProvider(); - this.accessors = SetUtils.unmodifiableSet(Collections.singleton(new Accessor(path))); + + if (path != null) { + if (!path.iterator().hasNext()) + throw new IllegalArgumentException("path cannot be empty"); + this.accessors = SetUtils.unmodifiableSet(Collections.singleton(new Accessor(path))); + } } public PositionalArgumentMetadata(Iterable arguments) { @@ -232,7 +233,8 @@ public String toString() { * Child * @return Merged metadata */ - public static PositionalArgumentMetadata override(PositionalArgumentMetadata parent, PositionalArgumentMetadata child) { + public static PositionalArgumentMetadata override(PositionalArgumentMetadata parent, + PositionalArgumentMetadata child) { // Cannot change position if (parent.position != child.position) throw new IllegalArgumentException( @@ -267,15 +269,17 @@ public static PositionalArgumentMetadata override(PositionalArgumentMetadata par // Parent must not state it is sealed UNLESS it is a duplicate which can // happen when using @Inject to inject options via delegates if (parent.sealed && !isDuplicate) - throw new IllegalArgumentException( - String.format("Cannot override positional argument %d (%s) as parent argument declares it to be sealed", parent.position, parent.title)); + throw new IllegalArgumentException(String.format( + "Cannot override positional argument %d (%s) as parent argument declares it to be sealed", + parent.position, parent.title)); // Child must explicitly state that it overrides otherwise we cannot // override UNLESS it is the case that this is a duplicate which // can happen when using @Inject to inject options via delegates if (!child.overrides && !isDuplicate) - throw new IllegalArgumentException( - String.format("Cannot override positional argument %d (%s) unless child argument sets overrides to true", parent.position, parent.title)); + throw new IllegalArgumentException(String.format( + "Cannot override positional argument %d (%s) unless child argument sets overrides to true", + parent.position, parent.title)); PositionalArgumentMetadata merged; //@formatter:off diff --git a/airline-core/src/test/java/com/github/rvesse/airline/TestPositionalArgs.java b/airline-core/src/test/java/com/github/rvesse/airline/TestPositionalArgs.java deleted file mode 100644 index fc669bee4..000000000 --- a/airline-core/src/test/java/com/github/rvesse/airline/TestPositionalArgs.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.github.rvesse.airline; - -import com.github.rvesse.airline.args.ArgsPositional; -import com.github.rvesse.airline.args.ArgsPositionalGap; -import com.github.rvesse.airline.model.PositionalArgumentMetadata; -import static com.github.rvesse.airline.TestingUtil.singleCommandParser; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; - -import org.testng.Assert; -import org.testng.annotations.Test; - -@SuppressWarnings("unused") -public class TestPositionalArgs { - - @Test - public void positional_args_01() { - SingleCommand parser = singleCommandParser(ArgsPositional.class); - assertFalse(parser.getCommandMetadata().getPositionalArguments().isEmpty()); - assertEquals(parser.getCommandMetadata().getPositionalArguments().size(), 2); - - PositionalArgumentMetadata posArg = parser.getCommandMetadata().getPositionalArguments().get(0); - assertEquals(posArg.getZeroBasedPosition(), 0); - assertEquals(posArg.getOneBasedPosition(), 1); - assertEquals(posArg.getJavaType(), String.class); - assertEquals(posArg.getTitle(), "File"); - - posArg = parser.getCommandMetadata().getPositionalArguments().get(1); - assertEquals(posArg.getZeroBasedPosition(), 1); - assertEquals(posArg.getOneBasedPosition(), 2); - assertEquals(posArg.getJavaType(), Integer.class); - assertEquals(posArg.getTitle(), "Mode"); - - ArgsPositional cmd = parser.parse("example.txt", "600", "extra"); - assertEquals(cmd.file, "example.txt"); - assertEquals(cmd.mode, new Integer(600)); - assertEquals(cmd.parameters.size(), 1); - assertEquals(cmd.parameters.get(0), "extra"); - - } - - @Test(expectedExceptions = IllegalStateException.class) - public void positional_args_gap_01() { - singleCommandParser(ArgsPositionalGap.class); - } -} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositional.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositional.java similarity index 96% rename from airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositional.java rename to airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositional.java index d16694f0b..99e349a6f 100644 --- a/airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositional.java +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositional.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.github.rvesse.airline.args; +package com.github.rvesse.airline.args.positional; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalConflict.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalConflict.java new file mode 100644 index 000000000..1ced2b925 --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalConflict.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Arguments; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; +import com.github.rvesse.airline.annotations.restrictions.Required; + +import java.util.ArrayList; +import java.util.List; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalConflict +{ + @PositionalArgument(position = PositionalArgument.FIRST, title = "File") + @Required + public String file; + + @PositionalArgument(position = PositionalArgument.FIRST, title = "Mode") + public Integer mode; + + @Arguments + public List parameters = new ArrayList<>(); +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalDuplicate.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalDuplicate.java new file mode 100644 index 000000000..f827d7ad2 --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalDuplicate.java @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Arguments; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; +import com.github.rvesse.airline.annotations.restrictions.Required; + +import java.util.ArrayList; +import java.util.List; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalDuplicate +{ + @PositionalArgument(position = PositionalArgument.FIRST, title = "File") + @Required + public String file; + + @PositionalArgument(position = PositionalArgument.FIRST, title = "File") + @Required + public String otherFile; + + @PositionalArgument(position = PositionalArgument.SECOND, title = "Mode") + public Integer mode; + + @Arguments + public List parameters = new ArrayList<>(); +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositionalGap.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalGap.java similarity index 96% rename from airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositionalGap.java rename to airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalGap.java index 50ee50563..055f2629f 100644 --- a/airline-core/src/test/java/com/github/rvesse/airline/args/ArgsPositionalGap.java +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalGap.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.github.rvesse.airline.args; +package com.github.rvesse.airline.args.positional; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverride.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverride.java new file mode 100644 index 000000000..b2af319f2 --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverride.java @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; +import com.github.rvesse.airline.annotations.restrictions.Unrestricted; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalOverride extends ArgsPositional { + + // Override the title and the restriction + @PositionalArgument(position = PositionalArgument.FIRST, title = "YourFile", override = true, sealed = true) + @Unrestricted + public String file; +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverrideChild.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverrideChild.java new file mode 100644 index 000000000..a92f7020d --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalOverrideChild.java @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalOverrideChild extends ArgsPositionalOverride { + + // Override the title and the restriction + @PositionalArgument(position = PositionalArgument.FIRST, title = "AwesomeFile", override = true) + public String file; +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional.java new file mode 100644 index 000000000..d7f27c8e2 --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Arguments; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; +import com.github.rvesse.airline.annotations.restrictions.Required; + +import java.util.ArrayList; +import java.util.List; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalRequiredAfterOptional +{ + @PositionalArgument(position = PositionalArgument.FIRST, title = "File") + public String file; + + @PositionalArgument(position = PositionalArgument.SECOND, title = "Mode") + @Required + public Integer mode; + + @Arguments + public List parameters = new ArrayList<>(); +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional2.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional2.java new file mode 100644 index 000000000..3bf1f6ddb --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/ArgsPositionalRequiredAfterOptional2.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.annotations.Arguments; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.PositionalArgument; +import com.github.rvesse.airline.annotations.restrictions.Required; + +import java.util.ArrayList; +import java.util.List; + +@Command(name = "ArgsPositional", description = "ArgsPositional description") +public class ArgsPositionalRequiredAfterOptional2 +{ + @PositionalArgument(position = PositionalArgument.FIRST, title = "File") + public String file; + + @PositionalArgument(position = PositionalArgument.SECOND, title = "Mode") + public Integer mode; + + @Arguments + @Required + public List parameters = new ArrayList<>(); +} diff --git a/airline-core/src/test/java/com/github/rvesse/airline/args/positional/TestPositionalArgs.java b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/TestPositionalArgs.java new file mode 100644 index 000000000..ddf269599 --- /dev/null +++ b/airline-core/src/test/java/com/github/rvesse/airline/args/positional/TestPositionalArgs.java @@ -0,0 +1,140 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * 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 com.github.rvesse.airline.args.positional; + +import com.github.rvesse.airline.SingleCommand; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; +import static com.github.rvesse.airline.TestingUtil.singleCommandParser; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@SuppressWarnings("unused") +public class TestPositionalArgs { + + @Test + public void positional_args_01() { + SingleCommand parser = singleCommandParser(ArgsPositional.class); + assertFalse(parser.getCommandMetadata().getPositionalArguments().isEmpty()); + assertEquals(parser.getCommandMetadata().getPositionalArguments().size(), 2); + + PositionalArgumentMetadata posArg = parser.getCommandMetadata().getPositionalArguments().get(0); + assertEquals(posArg.getZeroBasedPosition(), 0); + assertEquals(posArg.getOneBasedPosition(), 1); + assertEquals(posArg.getJavaType(), String.class); + assertTrue(posArg.isRequired()); + assertEquals(posArg.getTitle(), "File"); + + posArg = parser.getCommandMetadata().getPositionalArguments().get(1); + assertEquals(posArg.getZeroBasedPosition(), 1); + assertEquals(posArg.getOneBasedPosition(), 2); + assertEquals(posArg.getJavaType(), Integer.class); + assertEquals(posArg.getTitle(), "Mode"); + + ArgsPositional cmd = parser.parse("example.txt", "600", "extra"); + assertEquals(cmd.file, "example.txt"); + assertEquals(cmd.mode, new Integer(600)); + assertEquals(cmd.parameters.size(), 1); + assertEquals(cmd.parameters.get(0), "extra"); + + } + + @Test + public void positional_args_02() { + SingleCommand parser = singleCommandParser(ArgsPositional.class); + ArgsPositional cmd = parser.parse("example.txt", "600", "extra", "other", "another"); + + assertEquals(cmd.file, "example.txt"); + assertEquals(cmd.mode, new Integer(600)); + assertEquals(cmd.parameters.size(), 3); + assertEquals(cmd.parameters.get(0), "extra"); + assertEquals(cmd.parameters.get(1), "other"); + assertEquals(cmd.parameters.get(2), "another"); + + } + + @Test + public void positional_args_03() { + SingleCommand parser = singleCommandParser(ArgsPositionalDuplicate.class); + assertFalse(parser.getCommandMetadata().getPositionalArguments().isEmpty()); + assertEquals(parser.getCommandMetadata().getPositionalArguments().size(), 2); + + ArgsPositionalDuplicate cmd = parser.parse("example.txt", "600", "extra"); + assertEquals(cmd.file, "example.txt"); + assertEquals(cmd.otherFile, "example.txt"); + assertEquals(cmd.file, cmd.otherFile); + assertEquals(cmd.mode, new Integer(600)); + assertEquals(cmd.parameters.size(), 1); + assertEquals(cmd.parameters.get(0), "extra"); + + } + + @Test + public void positional_args_04() { + SingleCommand parser = singleCommandParser(ArgsPositionalOverride.class); + assertFalse(parser.getCommandMetadata().getPositionalArguments().isEmpty()); + assertEquals(parser.getCommandMetadata().getPositionalArguments().size(), 2); + + PositionalArgumentMetadata posArg = parser.getCommandMetadata().getPositionalArguments().get(0); + assertEquals(posArg.getZeroBasedPosition(), 0); + assertEquals(posArg.getOneBasedPosition(), 1); + assertEquals(posArg.getJavaType(), String.class); + assertEquals(posArg.getTitle(), "YourFile"); + assertFalse(posArg.isRequired()); + + posArg = parser.getCommandMetadata().getPositionalArguments().get(1); + assertEquals(posArg.getZeroBasedPosition(), 1); + assertEquals(posArg.getOneBasedPosition(), 2); + assertEquals(posArg.getJavaType(), Integer.class); + assertEquals(posArg.getTitle(), "Mode"); + + ArgsPositional cmd = parser.parse("example.txt", "600", "extra"); + assertEquals(cmd.file, "example.txt"); + assertEquals(cmd.mode, new Integer(600)); + assertEquals(cmd.parameters.size(), 1); + assertEquals(cmd.parameters.get(0), "extra"); + + } + + @Test(expectedExceptions = IllegalStateException.class) + public void positional_args_gap_01() { + singleCommandParser(ArgsPositionalGap.class); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void positional_args_conflict_01() { + singleCommandParser(ArgsPositionalConflict.class); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void positional_args_conflcit_02() { + singleCommandParser(ArgsPositionalOverrideChild.class); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void positional_args_required_01() { + singleCommandParser(ArgsPositionalRequiredAfterOptional.class); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void positional_args_required_02() { + singleCommandParser(ArgsPositionalRequiredAfterOptional2.class); + } +}