aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
diff options
context:
space:
mode:
authorGravatar Michael Staib <mstaib@google.com>2017-03-22 14:37:03 +0000
committerGravatar Yue Gan <yueg@google.com>2017-03-22 15:12:09 +0000
commit79bd2c2bdca3d97063d1a08e6be2ea8f5724fe13 (patch)
treef8baddb1be38ce2cff272eb2ce3ce973115283dd /src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
parent1e18045ed9d6ab9c945cec69286a7d8bd288a507 (diff)
Enable SkylarkCallable methods to be used on ClassObjects.
Previously, ClassObjects' SkylarkCallable struct fields worked as expected (with values of the struct taking precedence), but calling methods annotated with SkylarkCallable did not work at all; methods were treated as if they were not present in the struct. This adds some tests for the various ways of looking up fields and methods, and rearranges the logic in FuncallExpression to allow for callable methods on SkylarkClassObject's descendants. -- PiperOrigin-RevId: 150876181 MOS_MIGRATED_REVID=150876181
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java119
1 files changed, 119 insertions, 0 deletions
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 a72f5e5a91..32932b6a73 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
@@ -26,6 +26,8 @@ import com.google.devtools.build.lib.analysis.FileConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.NativeClassObjectConstructor;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -1288,4 +1290,121 @@ public class SkylarkEvaluationTest extends EvaluationTest {
new SkylarkTest().setUp("def foo(a, b, c): return a+b if c else a-b\n").testStatement(
"foo(23, 5, 0)", 18);
}
+
+ @SkylarkModule(name = "SkylarkClassObjectWithSkylarkCallables", doc = "")
+ static final class SkylarkClassObjectWithSkylarkCallables extends SkylarkClassObject {
+ private static final NativeClassObjectConstructor CONSTRUCTOR =
+ new NativeClassObjectConstructor("struct_with_skylark_callables") {};
+
+ SkylarkClassObjectWithSkylarkCallables() {
+ super(
+ CONSTRUCTOR,
+ ImmutableMap.of(
+ "values_only_field",
+ "fromValues",
+ "values_only_method",
+ new BuiltinFunction("values_only_method", FunctionSignature.of()) {
+ public String invoke() {
+ return "fromValues";
+ }
+ },
+ "collision_field",
+ "fromValues",
+ "collision_method",
+ new BuiltinFunction("collision_method", FunctionSignature.of()) {
+ public String invoke() {
+ return "fromValues";
+ }
+ }));
+ }
+
+ @SkylarkCallable(name = "callable_only_field", doc = "", structField = true)
+ public String getCallableOnlyField() {
+ return "fromSkylarkCallable";
+ }
+
+ @SkylarkCallable(name = "callable_only_method", doc = "", structField = false)
+ public String getCallableOnlyMethod() {
+ return "fromSkylarkCallable";
+ }
+
+ @SkylarkCallable(name = "collision_field", doc = "", structField = true)
+ public String getCollisionField() {
+ return "fromSkylarkCallable";
+ }
+
+ @SkylarkCallable(name = "collision_method", doc = "", structField = false)
+ public String getCollisionMethod() {
+ return "fromSkylarkCallable";
+ }
+ }
+
+ @Test
+ public void testStructFieldDefinedOnlyInValues() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.values_only_field")
+ .testLookup("v", "fromValues");
+ }
+
+ @Test
+ public void testStructMethodDefinedOnlyInValues() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.values_only_method()")
+ .testLookup("v", "fromValues");
+ }
+
+ @Test
+ public void testStructFieldDefinedOnlyInSkylarkCallable() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.callable_only_field")
+ .testLookup("v", "fromSkylarkCallable");
+ }
+
+ @Test
+ public void testStructMethodDefinedOnlyInSkylarkCallable() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.callable_only_method()")
+ .testLookup("v", "fromSkylarkCallable");
+ }
+
+ @Test
+ public void testStructFieldDefinedInValuesAndSkylarkCallable() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.collision_field")
+ .testLookup("v", "fromValues");
+ }
+
+ @Test
+ public void testStructMethodDefinedInValuesAndSkylarkCallable() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .setUp("v = val.collision_method()")
+ .testLookup("v", "fromValues");
+ }
+
+ @Test
+ public void testStructFieldNotDefined() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .testIfExactError(
+ // TODO(bazel-team): This should probably list callable_only_field/method as well.
+ "'struct_with_skylark_callables' object has no attribute 'nonexistent_field'\n"
+ + "Available attributes: collision_field, collision_method, values_only_field, "
+ + "values_only_method",
+ "v = val.nonexistent_field");
+ }
+
+ @Test
+ public void testStructMethodNotDefined() throws Exception {
+ new SkylarkTest()
+ .update("val", new SkylarkClassObjectWithSkylarkCallables())
+ .testIfExactError(
+ // TODO(bazel-team): This should probably match the error above better.
+ "struct has no method 'nonexistent_method'", "v = val.nonexistent_method()");
+ }
}