diff options
author | 2018-04-09 15:43:22 -0700 | |
---|---|---|
committer | 2018-04-09 15:44:52 -0700 | |
commit | 979195edc4ad8ea7b6923f99c827a4c1ec102815 (patch) | |
tree | 09732695db9c9d5c1b64297de41b7d0ea639e17c /src/test/java/com/google/devtools/build/lib | |
parent | 5c20c949188641db1376dd4b7ed958658ccb3670 (diff) |
Introduce extraPositonals and extraArguments to SkylarkCallable, to have parity with @SkylarkSignature.
This is necessary for several builtin functions that still use @SkylarkSignature, such as string format. These will be migrated in a future CL.
RELNOTES: None.
PiperOrigin-RevId: 192200282
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib')
7 files changed, 419 insertions, 2 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java index 69a2725e7d..016fe30704 100644 --- a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java @@ -74,7 +74,29 @@ public final class SkylarkCallableProcessorTest { .failsToCompile() .withErrorContaining( "@SkylarkCallable-annotated methods with structField=true may not also specify " - + "useAst, useEnvironment, or useLocation"); + + "useAst, useEnvironment, useLocation, extraPositionals, or extraKeywords"); + } + + @Test + public void testStructFieldWithExtraArgs() throws Exception { + assertAbout(javaSource()) + .that(getFile("StructFieldWithExtraArgs.java")) + .processedWith(new SkylarkCallableProcessor()) + .failsToCompile() + .withErrorContaining( + "@SkylarkCallable-annotated methods with structField=true may not also specify " + + "useAst, useEnvironment, useLocation, extraPositionals, or extraKeywords"); + } + + @Test + public void testStructFieldWithExtraKeywords() throws Exception { + assertAbout(javaSource()) + .that(getFile("StructFieldWithExtraKeywords.java")) + .processedWith(new SkylarkCallableProcessor()) + .failsToCompile() + .withErrorContaining( + "@SkylarkCallable-annotated methods with structField=true may not also specify " + + "useAst, useEnvironment, useLocation, extraPositionals, or extraKeywords"); } @Test @@ -220,4 +242,27 @@ public final class SkylarkCallableProcessorTest { .withErrorContaining( "Positional-only parameter 'two' is specified after one or more named parameters"); } + + @Test + public void testExtraKeywordsOutOfOrder() throws Exception { + assertAbout(javaSource()) + .that(getFile("ExtraKeywordsOutOfOrder.java")) + .processedWith(new SkylarkCallableProcessor()) + .failsToCompile() + .withErrorContaining( + "Expected parameter index 1 to be the " + + "com.google.devtools.build.lib.syntax.SkylarkDict<?,?> type, matching " + + "extraKeywords, but was java.lang.String"); + } + + @Test + public void testExtraPositionalsMissing() throws Exception { + assertAbout(javaSource()) + .that(getFile("ExtraPositionalsMissing.java")) + .processedWith(new SkylarkCallableProcessor()) + .failsToCompile() + .withErrorContaining( + "@SkylarkCallable annotated method has 3 parameters, but annotation declared " + + "1 user-supplied parameters and 3 extra interpreter parameters."); + } } diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraKeywordsOutOfOrder.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraKeywordsOutOfOrder.java new file mode 100644 index 0000000000..31498c0eef --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraKeywordsOutOfOrder.java @@ -0,0 +1,41 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.lib.skylarkinterface.processor.testsources; + +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.syntax.Environment; +import com.google.devtools.build.lib.syntax.SkylarkDict; + +/** + * Test case for a SkylarkCallable method which specifies extraKeywords, but specifies the argument + * out of order. + */ +public class ExtraKeywordsOutOfOrder { + + @SkylarkCallable( + name = "extra_kwargs_out_of_order", + documented = false, + parameters = {@Param(name = "one")}, + extraKeywords = @Param(name = "kwargs"), + useLocation = true, + useEnvironment = true + ) + public String threeArgMethod( + SkylarkDict<?, ?> kwargs, String one, Location location, Environment environment) { + return "bar"; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraPositionalsMissing.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraPositionalsMissing.java new file mode 100644 index 0000000000..4fbb044e2b --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ExtraPositionalsMissing.java @@ -0,0 +1,38 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.lib.skylarkinterface.processor.testsources; + +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.syntax.Environment; + +/** + * Test case for a SkylarkCallable method which specifies extraPositionals, but omits that argument. + */ +public class ExtraPositionalsMissing { + + @SkylarkCallable( + name = "extra_positionals_missing", + documented = false, + parameters = {@Param(name = "one")}, + extraPositionals = @Param(name = "args"), + useLocation = true, + useEnvironment = true + ) + public String threeArgMethod(String one, Location location, Environment environment) { + return "bar"; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java index 53baa0145c..1b0e136fea 100644 --- a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java @@ -20,6 +20,8 @@ import com.google.devtools.build.lib.skylarkinterface.ParamType; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.FuncallExpression; +import com.google.devtools.build.lib.syntax.SkylarkDict; +import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkSemantics; /** @@ -152,4 +154,48 @@ public class GoldenCase { Location location) { return "baz"; } + + @SkylarkCallable( + name = "two_arg_method_with_params_and_info_and_kwargs", + documented = false, + parameters = { + @Param(name = "one", type = String.class, named = true), + @Param(name = "two", type = Integer.class, named = true), + }, + extraKeywords = @Param(name = "kwargs"), + useAst = true, + useLocation = true, + useEnvironment = true, + useSkylarkSemantics = true + ) + public String twoArgMethodWithParamsAndInfoAndKwargs( + String one, + Integer two, + SkylarkDict<?, ?> kwargs, + Location location, + FuncallExpression ast, + Environment environment, + SkylarkSemantics skylarkSemantics) { + return "blep"; + } + + @SkylarkCallable( + name = "two_arg_method_with_env_and_args_and_kwargs", + documented = false, + parameters = { + @Param(name = "one", type = String.class, named = true), + @Param(name = "two", type = Integer.class, named = true), + }, + extraPositionals = @Param(name = "args"), + extraKeywords = @Param(name = "kwargs"), + useEnvironment = true + ) + public String twoArgMethodWithParamsAndInfoAndKwargs( + String one, + Integer two, + SkylarkList<?> args, + SkylarkDict<?, ?> kwargs, + Environment environment) { + return "yar"; + } } diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraArgs.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraArgs.java new file mode 100644 index 0000000000..8c8c5081ce --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraArgs.java @@ -0,0 +1,33 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.lib.skylarkinterface.processor.testsources; + +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.syntax.SkylarkList; + +/** Test case which verifies a struct field method cannot specify extraArgs. */ +public class StructFieldWithExtraArgs { + + @SkylarkCallable( + name = "struct_field_method_with_extra_args", + documented = false, + structField = true, + extraPositionals = @Param(name = "args") + ) + public String structFieldMethodWithExtraArgs(SkylarkList<?> args) { + return "Cat."; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraKeywords.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraKeywords.java new file mode 100644 index 0000000000..9055172465 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/StructFieldWithExtraKeywords.java @@ -0,0 +1,33 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.lib.skylarkinterface.processor.testsources; + +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.syntax.SkylarkDict; + +/** Test case which verifies a struct field method cannot specify extraArgs. */ +public class StructFieldWithExtraKeywords { + + @SkylarkCallable( + name = "struct_field_method_with_extra_kwargs", + documented = false, + structField = true, + extraKeywords = @Param(name = "kwargs") + ) + public String structFieldMethodWithExtraKeywords(SkylarkDict<?, ?> args) { + return "Dog."; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java index 3804a72d53..7b86d6cad4 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.syntax; import static com.google.common.truth.Truth.assertThat; +import static java.util.stream.Collectors.joining; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; @@ -163,7 +164,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { return ImmutableMap.of("a", ImmutableList.of("b", "c")); } - + @SkylarkCallable( name = "with_params", documented = false, @@ -365,6 +366,82 @@ public class SkylarkEvaluationTest extends EvaluationTest { return NativeProvider.STRUCT.create(builder.build(), "no native callable '%s'"); } + @SkylarkCallable( + name = "with_args_and_env", + documented = false, + parameters = { + @Param(name = "pos1", type = Integer.class), + @Param(name = "pos2", defaultValue = "False", type = Boolean.class), + @Param(name = "named", type = Boolean.class, positional = false, named = true), + }, + extraPositionals = @Param(name = "args"), + useEnvironment = true + ) + public String withArgsAndEnv( + Integer pos1, boolean pos2, boolean named, SkylarkList<?> args, Environment env) { + String argsString = + "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")"; + return "with_args_and_env(" + + pos1 + + ", " + + pos2 + + ", " + + named + + ", " + + argsString + + ", " + + env.isGlobal() + + ")"; + } + + @SkylarkCallable( + name = "with_kwargs", + documented = false, + parameters = { + @Param(name = "pos", defaultValue = "False", type = Boolean.class), + @Param(name = "named", type = Boolean.class, positional = false, named = true), + }, + extraKeywords = @Param(name = "kwargs") + ) + public String withKwargs(boolean pos, boolean named, SkylarkDict<?, ?> kwargs) + throws EvalException { + String kwargsString = + "kwargs(" + + kwargs + .getContents(String.class, Object.class, "kwargs") + .entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(joining(", ")) + + ")"; + return "with_kwargs(" + pos + ", " + named + ", " + kwargsString + ")"; + } + + @SkylarkCallable( + name = "with_args_and_kwargs", + documented = false, + parameters = { + @Param(name = "foo", named = true, positional = true, type = String.class), + }, + extraPositionals = @Param(name = "args"), + extraKeywords = @Param(name = "kwargs") + ) + public String withArgsAndKwargs(String foo, SkylarkList<?> args, SkylarkDict<?, ?> kwargs) + throws EvalException { + String argsString = + "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")"; + String kwargsString = + "kwargs(" + + kwargs + .getContents(String.class, Object.class, "kwargs") + .entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(joining(", ")) + + ")"; + return "with_args_and_kwargs(" + foo + ", " + argsString + ", " + kwargsString + ")"; + } + @Override public String toString() { return "<mock>"; @@ -1108,6 +1185,107 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @Test + public void testJavaFunctionWithExtraArgsAndEnv() throws Exception { + new SkylarkTest() + .update("mock", new Mock()) + .setUp("b = mock.with_args_and_env(1, True, 'extraArg1', 'extraArg2', named=True)") + .testLookup("b", "with_args_and_env(1, true, true, args(extraArg1, extraArg2), true)"); + + // Use an args list. + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "myargs = ['extraArg2']", + "b = mock.with_args_and_env(1, True, 'extraArg1', named=True, *myargs)") + .testLookup("b", "with_args_and_env(1, true, true, args(extraArg1, extraArg2), true)"); + } + + @Test + public void testJavaFunctionWithExtraKwargs() throws Exception { + new SkylarkTest() + .update("mock", new Mock()) + .setUp("b = mock.with_kwargs(True, extraKey1=True, named=True, extraKey2='x')") + .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))"); + + // Use a kwargs dict. + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "mykwargs = {'extraKey2':'x', 'named':True}", + "b = mock.with_kwargs(True, extraKey1=True, **mykwargs)") + .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))"); + } + + @Test + public void testJavaFunctionWithArgsAndKwargs() throws Exception { + // Foo is used positionally + new SkylarkTest() + .update("mock", new Mock()) + .setUp("b = mock.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')") + .testLookup( + "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))"); + + // Use an args list and a kwargs dict + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "mykwargs = {'extraKey1':True}", + "myargs = ['baz']", + "b = mock.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)") + .testLookup( + "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))"); + + // Foo is used by name + new SkylarkTest() + .update("mock", new Mock()) + .setUp("b = mock.with_args_and_kwargs(foo='foo', extraKey1=True)") + .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))"); + + // Empty args and kwargs. + new SkylarkTest() + .update("mock", new Mock()) + .setUp("b = mock.with_args_and_kwargs('foo')") + .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())"); + } + + @Test + public void testProxyMethodsObjectWithArgsAndKwargs() throws Exception { + // Foo is used positionally + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "m = mock.proxy_methods_object()", + "b = m.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')") + .testLookup( + "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))"); + + // Use an args list and a kwargs dict + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "mykwargs = {'extraKey1':True}", + "myargs = ['baz']", + "m = mock.proxy_methods_object()", + "b = m.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)") + .testLookup( + "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))"); + + // Foo is used by name + new SkylarkTest() + .update("mock", new Mock()) + .setUp( + "m = mock.proxy_methods_object()", + "b = m.with_args_and_kwargs(foo='foo', extraKey1=True)") + .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))"); + + // Empty args and kwargs. + new SkylarkTest() + .update("mock", new Mock()) + .setUp("m = mock.proxy_methods_object()", "b = m.with_args_and_kwargs('foo')") + .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())"); + } + + @Test public void testStructAccessOfMethod() throws Exception { new SkylarkTest() .update("mock", new Mock()) @@ -1591,7 +1769,10 @@ public class SkylarkEvaluationTest extends EvaluationTest { "struct_field_callable", "value_of", "voidfunc", + "with_args_and_env", + "with_args_and_kwargs", "with_extra", + "with_kwargs", "with_params", "with_params_and_extra"); } |