Fixes to Skylark function call
Allow a call to a struct's field when it's a function.
Check whether a java method exists before issuing KwArg error.
--
MOS_MIGRATED_REVID=101937143
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 b11866d..c9e9a65 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
@@ -51,7 +51,7 @@
protected ModalTestCase newTest() {
return new SkylarkTest();
}
-
+
@SkylarkModule(name = "Mock", doc = "")
static class Mock {
@SkylarkCallable(doc = "")
@@ -94,6 +94,10 @@
public String string() {
return "a";
}
+ @Override
+ public String toString() {
+ return "<mock>";
+ }
}
@SkylarkModule(name = "MockInterface", doc = "")
@@ -324,60 +328,60 @@
public void testForLoopBreak() throws Exception {
simpleFlowTest("break", 1);
}
-
+
@Test
public void testForLoopContinue() throws Exception {
simpleFlowTest("continue", 10);
}
-
+
@SuppressWarnings("unchecked")
private void simpleFlowTest(String statement, int expected) throws Exception {
eval("def foo():",
" s = 0",
- " hit = 0",
- " for i in range(0, 10):",
- " s = s + 1",
- " " + statement + "",
- " hit = 1",
- " return [s, hit]",
+ " hit = 0",
+ " for i in range(0, 10):",
+ " s = s + 1",
+ " " + statement + "",
+ " hit = 1",
+ " return [s, hit]",
"x = foo()");
assertThat((Iterable<Object>) lookup("x")).containsExactly(expected, 0).inOrder();
}
-
- @Test
+
+ @Test
public void testForLoopBreakFromDeeperBlock() throws Exception {
flowFromDeeperBlock("break", 1);
flowFromNestedBlocks("break", 29);
}
-
- @Test
+
+ @Test
public void testForLoopContinueFromDeeperBlock() throws Exception {
flowFromDeeperBlock("continue", 5);
flowFromNestedBlocks("continue", 39);
}
-
+
private void flowFromDeeperBlock(String statement, int expected) throws Exception {
eval("def foo():",
- " s = 0",
- " for i in range(0, 10):",
- " if i % 2 != 0:",
+ " s = 0",
+ " for i in range(0, 10):",
+ " if i % 2 != 0:",
" " + statement + "",
- " s = s + 1",
- " return s",
+ " s = s + 1",
+ " return s",
"x = foo()");
assertThat(lookup("x")).isEqualTo(expected);
}
-
+
private void flowFromNestedBlocks(String statement, int expected) throws Exception {
eval("def foo2():",
- " s = 0",
- " for i in range(1, 41):",
- " if i % 2 == 0:",
+ " s = 0",
+ " for i in range(1, 41):",
+ " if i % 2 == 0:",
" if i % 3 == 0:",
- " if i % 5 == 0:",
+ " if i % 5 == 0:",
" " + statement + "",
- " s = s + 1",
- " return s",
+ " s = s + 1",
+ " return s",
"y = foo2()");
assertThat(lookup("y")).isEqualTo(expected);
}
@@ -401,11 +405,11 @@
" second = 0",
" for i in range(0, 5):",
" for j in range(0, 5):",
- " if j == 2:",
+ " if j == 2:",
" " + statement + "",
" first = first + 1",
" for k in range(0, 5):",
- " if k == 2:",
+ " if k == 2:",
" " + statement + "",
" second = second + 1",
" if i == 2:",
@@ -416,7 +420,7 @@
assertThat((Iterable<Object>) lookup("x"))
.containsExactly(outerExpected, firstExpected, secondExpected).inOrder();
}
-
+
@Test
public void testForLoopBreakError() throws Exception {
flowStatementInsideFunction("break");
@@ -430,18 +434,18 @@
}
private void flowStatementInsideFunction(String statement) throws Exception {
- checkEvalErrorContains(statement + " statement must be inside a for loop",
+ checkEvalErrorContains(statement + " statement must be inside a for loop",
"def foo():",
- " " + statement + "",
+ " " + statement + "",
"x = foo()");
}
-
+
private void flowStatementAfterLoop(String statement) throws Exception {
- checkEvalErrorContains(statement + " statement must be inside a for loop",
+ checkEvalErrorContains(statement + " statement must be inside a for loop",
"def foo2():",
" for i in range(0, 3):",
" pass",
- " " + statement + "",
+ " " + statement + "",
"y = foo2()");
}
@@ -496,7 +500,9 @@
@Test
public void testJavaCallsNoMethod() throws Exception {
- new SkylarkTest().testIfExactError("No matching method found for bad() in int", "s = 3.bad()");
+ new SkylarkTest()
+ .update("mock", new Mock())
+ .testIfExactError("No matching method found for bad() in Mock", "mock.bad()");
}
@Test
@@ -517,17 +523,18 @@
@Test
public void testJavaCallWithKwargs() throws Exception {
- new SkylarkTest().testIfExactError(
- "Keyword arguments are not allowed when calling a java method"
- + "\nwhile calling method 'compare_to' on object 3 of type int",
- "comp = 3.compare_to(x = 4)");
+ new SkylarkTest()
+ .update("mock", new Mock())
+ .testIfExactError("Keyword arguments are not allowed when calling a java method"
+ + "\nwhile calling method 'string' on object of type Mock",
+ "mock.string(key=True)");
}
@Test
public void testNoJavaCallsWithoutSkylark() throws Exception {
new SkylarkTest().testIfExactError(
"No matching method found for to_string() in int", "s = 3.to_string()");
- }
+ }
@Test
public void testNoJavaCallsIfClassNotAnnotated() throws Exception {
@@ -705,9 +712,22 @@
}
@Test
- public void testStructAccessingFieldsWithArgs() throws Exception {
+ public void testStructAccessingUnknownFieldWithArgs() throws Exception {
new SkylarkTest().testIfExactError(
- "No matching method found for a(int) in struct", "x = struct(a = 1, b = 2)", "x1 = x.a(1)");
+ "struct has no method 'c'", "x = struct(a = 1, b = 2)", "y = x.c()");
+ }
+
+ @Test
+ public void testStructAccessingNonFunctionFieldWithArgs() throws Exception {
+ new SkylarkTest().testIfExactError(
+ "struct field 'a' is not a function", "x = struct(a = 1, b = 2)", "x1 = x.a(1)");
+ }
+
+ @Test
+ public void testStructAccessingFunctionFieldWithArgs() throws Exception {
+ new SkylarkTest()
+ .setUp("def f(x): return x+5", "x = struct(a = f, b = 2)", "x1 = x.a(1)")
+ .testLookup("x1", 6);
}
@Test
@@ -802,7 +822,7 @@
@Test
public void testUserFunctionKeywordArgs() throws Exception {
- new SkylarkTest().setUp("def foo(a, b, c):",
+ new SkylarkTest().setUp("def foo(a, b, c):",
" return a + b + c", "s = foo(1, c=2, b=3)")
.testLookup("s", 6);
}