Simplify Skylark tests
Use the new EvaluationContext infrastructure to simplify Skylark tests
(said infrastructure is originally based on code from these tests).
Merge AbstractEvaluationTestCase and AbstractParserTestCase into
a non-abstract class EvaluationTestCase that uses EvaluationContext.
Cleanup the EventCollectionApparatus it uses.
Refactor all Skylark tests to use this new infrastructure.
Fix EvaluationTest and MethodLibraryTest to actually and correctly
run tests in both modes.
Fix small bugs in the main code base discovered by actually running the
code in both modes, and make error messages identical when possible.
--
MOS_MIGRATED_REVID=90828053
diff --git a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
index 1513735..87b9f02 100644
--- a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
+++ b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
@@ -13,14 +13,12 @@
// limitations under the License.
package com.google.devtools.build.lib.events.util;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventCollector;
-import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.PrintingEventHandler;
import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.syntax.EvaluationContext;
import com.google.devtools.build.lib.testutil.JunitTestUtils;
import com.google.devtools.build.lib.util.io.OutErr;
@@ -28,43 +26,31 @@
import java.util.Set;
/**
- * An apparatus for reporting / collecting events.
+ * An apparatus for reporting / collecting events.
*/
public class EventCollectionApparatus {
- /**
- * The fail fast handler, which fails the test fail whenever we encounter
- * an error event.
- */
- private static final EventHandler FAIL_FAST_HANDLER = new EventHandler() {
- @Override
- public void handle(Event event) {
- assertWithMessage(event.toString()).that(EventKind.ERRORS_AND_WARNINGS)
- .doesNotContain(event.getKind());
- }
- };
private Set<EventKind> customMask;
-
- /*
- * Determine which events the {@link #collector()} created by this apparatus
+
+ /**
+ * Determine which events the {@link #collector()} created by this apparatus
* will collect. Default: {@link EventKind#ERRORS_AND_WARNINGS}.
- *
- */
+ */
public EventCollectionApparatus(Set<EventKind> mask) {
this.customMask = mask;
-
+
eventCollector = new EventCollector(customMask);
reporter = new Reporter(eventCollector);
printingEventHandler = new PrintingEventHandler(EventKind.ERRORS_AND_WARNINGS_AND_OUTPUT);
reporter.addHandler(printingEventHandler);
-
+
this.setFailFast(true);
}
-
+
public EventCollectionApparatus() {
this(EventKind.ERRORS_AND_WARNINGS);
}
-
+
/* ---- Settings for the apparatus (configuration for creating state) ---- */
/* ---------- State that the apparatus initializes / operates on --------- */
@@ -72,6 +58,7 @@
private Reporter reporter;
private PrintingEventHandler printingEventHandler;
+
/**
* Determine whether the {#link reporter()} created by this apparatus will
* fail fast, that is, throw an exception whenever we encounter an event of
@@ -80,23 +67,21 @@
*/
public void setFailFast(boolean failFast) {
if (failFast) {
- reporter.addHandler(FAIL_FAST_HANDLER);
+ reporter.addHandler(EvaluationContext.FAIL_FAST_HANDLER);
} else {
- reporter.removeHandler(FAIL_FAST_HANDLER);
+ reporter.removeHandler(EvaluationContext.FAIL_FAST_HANDLER);
}
}
-
+
/**
- * Initializes the apparatus (if it's not been initialized yet) and returns
- * the reporter created with the settings specified by this apparatus.
+ * @return the event reporter for this apparatus
*/
public Reporter reporter() {
return reporter;
}
/**
- * Initializes the apparatus (if it's not been initialized yet) and returns
- * the collector created with the settings specified by this apparatus.
+ * @return the event collector for this apparatus.
*/
public EventCollector collector() {
return eventCollector;
@@ -145,5 +130,4 @@
return JunitTestUtils.assertContainsEventWithWordsInQuotes(
eventCollector, words);
}
-
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/AbstractEvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/AbstractEvaluationTestCase.java
deleted file mode 100644
index e08e4c9..0000000
--- a/src/test/java/com/google/devtools/build/lib/syntax/AbstractEvaluationTestCase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2006-2015 Google Inc. 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.syntax;
-
-import java.util.List;
-
-/**
- * Base class for test cases that use eval services.
- */
-public abstract class AbstractEvaluationTestCase extends AbstractParserTestCase {
-
- public Object eval(String input) throws Exception {
- return eval(parseExpr(input));
- }
-
- public Object eval(String input, Environment env) throws Exception {
- return eval(parseExpr(input), env);
- }
-
- public static Object eval(Expression e) throws Exception {
- return eval(e, new Environment());
- }
-
- public static Object eval(Expression e, Environment env) throws Exception {
- return e.eval(env);
- }
-
- public void exec(String input, Environment env) throws Exception {
- exec(parseStmt(input), env);
- }
-
- public void exec(Statement s, Environment env) throws Exception {
- s.exec(env);
- }
-
- public static void exec(List<Statement> li, Environment env) throws Exception {
- for (Statement stmt : li) {
- stmt.exec(env);
- }
- }
-}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/AbstractParserTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/AbstractParserTestCase.java
deleted file mode 100644
index 55c2d4c..0000000
--- a/src/test/java/com/google/devtools/build/lib/syntax/AbstractParserTestCase.java
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2006-2015 Google Inc. 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.syntax;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.events.util.EventCollectionApparatus;
-import com.google.devtools.build.lib.packages.CachingPackageLocator;
-import com.google.devtools.build.lib.rules.SkylarkModules;
-import com.google.devtools.build.lib.vfs.Path;
-import com.google.devtools.build.lib.vfs.util.FsApparatus;
-
-import java.util.List;
-
-/**
- * Base class for test cases that use parsing services.
- */
-public abstract class AbstractParserTestCase {
- public static final class EmptyPackageLocator implements CachingPackageLocator {
- @Override
- public Path getBuildFileForPackage(String packageName) {
- return null;
- }
- }
-
- protected EventCollectionApparatus syntaxEvents = new EventCollectionApparatus();
- private FsApparatus scratch = FsApparatus.newInMemory();
- private CachingPackageLocator locator = new EmptyPackageLocator();
-
- private static Lexer createLexer(String input,
- EventCollectionApparatus syntaxEvents, FsApparatus scratch) {
- Path someFile = scratch.path("/some/file.txt");
- ParserInputSource inputSource = ParserInputSource.create(input, someFile);
- return new Lexer(inputSource, syntaxEvents.reporter());
- }
-
- protected Lexer createLexer(String input) {
- return createLexer(input, syntaxEvents, scratch);
- }
-
- protected List<Statement> parseFile(String input) {
- return Parser.parseFile(createLexer(input), syntaxEvents.reporter(), locator, false)
- .statements;
- }
-
- protected List<Statement> parseFile(String input, boolean parsePython) {
- return Parser.parseFile(createLexer(input), syntaxEvents.reporter(), locator, parsePython)
- .statements;
- }
-
- protected List<Statement> parseFileForSkylark(String input) {
- return Parser.parseFileForSkylark(createLexer(input), syntaxEvents.reporter(), locator,
- SkylarkModules.getValidationEnvironment()).statements;
- }
-
- protected List<Statement> parseFileForSkylark(
- String input, ImmutableMap<String, SkylarkType> extraObject) {
- return Parser.parseFileForSkylark(createLexer(input), syntaxEvents.reporter(), locator,
- SkylarkModules.getValidationEnvironment(extraObject)).statements;
- }
-
- protected Parser.ParseResult parseFileWithComments(String input) {
- return Parser.parseFile(createLexer(input), syntaxEvents.reporter(), locator, false);
- }
-
- protected Statement parseStmt(String input) {
- return Parser.parseStatement(createLexer(input), syntaxEvents.reporter());
- }
-
- protected Expression parseExpr(String input) {
- return Parser.parseExpression(createLexer(input), syntaxEvents.reporter());
- }
-
- public static List<Statement> parseFileForSkylark(
- EventCollectionApparatus syntaxEvents, FsApparatus scratch, String input) {
- return Parser.parseFileForSkylark(createLexer(input, syntaxEvents, scratch),
- syntaxEvents.reporter(), null,
- SkylarkModules.getValidationEnvironment()).statements;
- }
-
- public static List<Statement> parseFileForSkylark(
- EventCollectionApparatus syntaxEvents, FsApparatus scratch, String input,
- ImmutableMap<String, SkylarkType> extraObject) {
- return Parser.parseFileForSkylark(createLexer(input, syntaxEvents, scratch),
- syntaxEvents.reporter(), null,
- SkylarkModules.getValidationEnvironment(extraObject)).statements;
- }
-}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/BaseFunctionTest.java b/src/test/java/com/google/devtools/build/lib/syntax/BaseFunctionTest.java
index 9deb624..acd9fb0 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/BaseFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/BaseFunctionTest.java
@@ -31,13 +31,7 @@
* between the outer call(posargs, kwargs, ast, env) and the inner call(args, ast, env).
*/
@RunWith(JUnit4.class)
-public class BaseFunctionTest extends AbstractEvaluationTestCase {
-
- private Environment singletonEnv(String id, Object value) {
- Environment env = new Environment();
- env.update(id, value);
- return env;
- }
+public class BaseFunctionTest extends EvaluationTestCase {
/**
* Handy implementation of {@link BaseFunction} that returns all its args as a list.
@@ -56,15 +50,16 @@
private void checkBaseFunction(BaseFunction func, String callExpression, String expectedOutput)
throws Exception {
- Environment env = singletonEnv(func.getName(), func);
+ setUp();
+ update(func.getName(), func);
if (expectedOutput.charAt(0) == '[') { // a tuple => expected to pass
assertEquals("Wrong output for " + callExpression,
- expectedOutput, eval(callExpression, env).toString());
+ expectedOutput, eval(callExpression).toString());
} else { // expected to fail with an exception
try {
- eval(callExpression, env);
+ eval(callExpression);
fail();
} catch (EvalException e) {
assertEquals("Wrong exception for " + callExpression,
@@ -138,26 +133,24 @@
@Test
@SuppressWarnings("unchecked")
public void testKwParam() throws Exception {
- Environment env = new SkylarkEnvironment(syntaxEvents.collector());
- exec(parseFileForSkylark(
- "def foo(a, b, c=3, d=4, *args, e, f, g=7, h=8, **kwargs):\n"
+ eval("def foo(a, b, c=3, d=4, *args, e, f, g=7, h=8, **kwargs):\n"
+ " return (a, b, c, d, e, f, g, h, args, kwargs)\n"
+ "v1 = foo(1, 2, e=5, f=6)\n"
+ "v2 = foo(1, *['x', 'y', 'z', 't'], h=9, e=5, f=6, i=0)\n"
+ "def bar(**kwargs):\n"
+ " return kwargs\n"
+ "b1 = bar(name='foo', type='jpg', version=42)\n"
- + "b2 = bar()\n"), env);
+ + "b2 = bar()\n");
- assertThat(EvalUtils.prettyPrintValue(env.lookup("v1")))
+ assertThat(EvalUtils.prettyPrintValue(lookup("v1")))
.isEqualTo("(1, 2, 3, 4, 5, 6, 7, 8, (), {})");
- assertThat(EvalUtils.prettyPrintValue(env.lookup("v2")))
+ assertThat(EvalUtils.prettyPrintValue(lookup("v2")))
.isEqualTo("(1, \"x\", \"y\", \"z\", 5, 6, 7, 9, (\"t\",), {\"i\": 0})");
// NB: the conversion to a TreeMap below ensures the keys are sorted.
assertThat(EvalUtils.prettyPrintValue(
- new TreeMap<String, Object>((Map<String, Object>) env.lookup("b1"))))
+ new TreeMap<String, Object>((Map<String, Object>) lookup("b1"))))
.isEqualTo("{\"name\": \"foo\", \"type\": \"jpg\", \"version\": 42}");
- assertThat(EvalUtils.prettyPrintValue(env.lookup("b2"))).isEqualTo("{}");
+ assertThat(EvalUtils.prettyPrintValue(lookup("b2"))).isEqualTo("{}");
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java
index 36a50c1..a324b13 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java
@@ -28,121 +28,107 @@
* Tests of Environment.
*/
@RunWith(JUnit4.class)
-public class EnvironmentTest extends AbstractEvaluationTestCase {
+public class EnvironmentTest extends EvaluationTestCase {
+
+ @Override
+ public EvaluationContext newEvaluationContext() {
+ return EvaluationContext.newBuildContext(getEventHandler());
+ }
// Test the API directly
@Test
public void testLookupAndUpdate() throws Exception {
- Environment env = new Environment();
-
try {
- env.lookup("foo");
+ lookup("foo");
fail();
} catch (Environment.NoSuchVariableException e) {
assertThat(e).hasMessage("no such variable: foo");
}
-
- env.update("foo", "bar");
-
- assertEquals("bar", env.lookup("foo"));
+ update("foo", "bar");
+ assertEquals("bar", lookup("foo"));
}
@Test
public void testLookupWithDefault() throws Exception {
- Environment env = new Environment();
- assertEquals(21, env.lookup("VERSION", 21));
- env.update("VERSION", 42);
- assertEquals(42, env.lookup("VERSION", 21));
+ assertEquals(21, getEnvironment().lookup("VERSION", 21));
+ update("VERSION", 42);
+ assertEquals(42, getEnvironment().lookup("VERSION", 21));
}
@Test
public void testDoubleUpdateSucceeds() throws Exception {
- Environment env = new Environment();
- env.update("VERSION", 42);
- assertEquals(42, env.lookup("VERSION"));
- env.update("VERSION", 43);
- assertEquals(43, env.lookup("VERSION"));
+ update("VERSION", 42);
+ assertEquals(42, lookup("VERSION"));
+ update("VERSION", 43);
+ assertEquals(43, lookup("VERSION"));
}
// Test assign through interpreter, lookup through API:
@Test
public void testAssign() throws Exception {
- Environment env = new Environment();
-
try {
- env.lookup("foo");
+ lookup("foo");
fail();
} catch (Environment.NoSuchVariableException e) {
assertThat(e).hasMessage("no such variable: foo");
}
-
- exec(parseStmt("foo = 'bar'"), env);
-
- assertEquals("bar", env.lookup("foo"));
+ eval("foo = 'bar'");
+ assertEquals("bar", lookup("foo"));
}
// Test update through API, reference through interpreter:
@Test
public void testReference() throws Exception {
- Environment env = new Environment();
-
try {
- eval(parseExpr("foo"), env);
+ eval("foo");
fail();
} catch (EvalException e) {
assertThat(e).hasMessage("name 'foo' is not defined");
}
-
- env.update("foo", "bar");
-
- assertEquals("bar", eval(parseExpr("foo"), env));
+ update("foo", "bar");
+ assertEquals("bar", eval("foo"));
}
// Test assign and reference through interpreter:
@Test
public void testAssignAndReference() throws Exception {
- Environment env = new Environment();
-
try {
- eval(parseExpr("foo"), env);
+ eval("foo");
fail();
} catch (EvalException e) {
assertThat(e).hasMessage("name 'foo' is not defined");
}
-
- exec(parseStmt("foo = 'bar'"), env);
-
- assertEquals("bar", eval(parseExpr("foo"), env));
+ eval("foo = 'bar'");
+ assertEquals("bar", eval("foo"));
}
@Test
public void testGetVariableNames() throws Exception {
- Environment env = new Environment();
- env.update("foo", "bar");
- env.update("wiz", 3);
+ update("foo", "bar");
+ update("wiz", 3);
- Environment nestedEnv = new Environment(env);
+ Environment nestedEnv = new Environment(getEnvironment());
nestedEnv.update("foo", "bat");
nestedEnv.update("quux", 42);
- assertEquals(Sets.newHashSet("True", "False", "None", "foo", "wiz"), env.getVariableNames());
+ assertEquals(Sets.newHashSet("True", "False", "None", "foo", "wiz"),
+ getEnvironment().getVariableNames());
assertEquals(Sets.newHashSet("True", "False", "None", "foo", "wiz", "quux"),
nestedEnv.getVariableNames());
}
@Test
public void testToString() throws Exception {
- Environment env = new Environment();
- env.update("subject", new StringLiteral("Hello, 'world'.", '\''));
- env.update("from", new StringLiteral("Java", '"'));
+ update("subject", new StringLiteral("Hello, 'world'.", '\''));
+ update("from", new StringLiteral("Java", '"'));
assertEquals("Environment{False -> false, None -> None, True -> true, from -> \"Java\", "
- + "subject -> 'Hello, \\'world\\'.', }", env.toString());
+ + "subject -> 'Hello, \\'world\\'.', }", getEnvironment().toString());
}
@Test
public void testBindToNullThrowsException() throws Exception {
try {
- new Environment().update("some_name", null);
+ update("some_name", null);
fail();
} catch (NullPointerException e) {
assertThat(e).hasMessage("update(value == null)");
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
index cb52cc4..9192eaa 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
@@ -17,23 +17,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -43,52 +36,31 @@
* Test of evaluation behavior. (Implicitly uses lexer + parser.)
*/
@RunWith(JUnit4.class)
-public class EvaluationTest extends AbstractEvaluationTestCase {
-
- protected Environment env;
-
- @Before
- public void setUp() throws Exception {
-
- PackageFactory factory = new PackageFactory(TestRuleClassProvider.getRuleClassProvider());
- env = factory.getEnvironment();
- }
-
- public Environment singletonEnv(String id, Object value) {
- Environment env = new Environment();
- env.update(id, value);
- return env;
- }
+public class EvaluationTest extends EvaluationTestCase {
@Override
- public Object eval(String input) throws Exception {
- return eval(parseExpr(input), env);
+ public EvaluationContext newEvaluationContext() {
+ return EvaluationContext.newBuildContext(getEventHandler(),
+ new PackageFactory(TestRuleClassProvider.getRuleClassProvider()).getEnvironment());
}
@Test
public void testExprs() throws Exception {
- assertEquals("fooxbar",
- eval("'%sx' % 'foo' + 'bar'"));
- assertEquals("fooxbar",
- eval("('%sx' % 'foo') + 'bar'"));
- assertEquals("foobarx",
- eval("'%sx' % ('foo' + 'bar')"));
- assertEquals(579,
- eval("123 + 456"));
- assertEquals(333,
- eval("456 - 123"));
- assertEquals(2,
- eval("8 % 3"));
+ assertEquals("fooxbar", eval("'%sx' % 'foo' + 'bar'"));
+ assertEquals("fooxbar", eval("('%sx' % 'foo') + 'bar'"));
+ assertEquals("foobarx", eval("'%sx' % ('foo' + 'bar')"));
+ assertEquals(579, eval("123 + 456"));
+ assertEquals(333, eval("456 - 123"));
+ assertEquals(2, eval("8 % 3"));
- checkEvalError("3 % 'foo'", "unsupported operand type(s) for %: 'int' and 'string'");
+ checkEvalErrorContains("unsupported operand type(s) for %: 'int' and 'string'", "3 % 'foo'");
}
+ @SuppressWarnings("unchecked")
@Test
public void testListExprs() throws Exception {
- assertEquals(Arrays.asList(1, 2, 3),
- eval("[1, 2, 3]"));
- assertEquals(Arrays.asList(1, 2, 3),
- eval("(1, 2, 3)"));
+ assertThat((Iterable<Object>) eval("[1, 2, 3]")).containsExactly(1, 2, 3).inOrder();
+ assertThat((Iterable<Object>) eval("(1, 2, 3)")).containsExactly(1, 2, 3).inOrder();
}
@Test
@@ -99,11 +71,9 @@
@Test
public void testAndOr() throws Exception {
assertEquals(8, eval("8 or 9"));
- assertEquals(8, eval("8 or foo")); // check that 'foo' is not evaluated
assertEquals(9, eval("0 or 9"));
assertEquals(9, eval("8 and 9"));
assertEquals(0, eval("0 and 9"));
- assertEquals(0, eval("0 and foo")); // check that 'foo' is not evaluated
assertEquals(2, eval("1 and 2 or 3"));
assertEquals(3, eval("0 and 2 or 3"));
@@ -115,9 +85,21 @@
assertEquals(1, eval("1 or 0 and 3"));
assertEquals(1, eval("1 or 0 and 3"));
- assertEquals(9, eval("\"\" or 9"));
- assertEquals("abc", eval("\"abc\" or 9"));
assertEquals(Environment.NONE, eval("None and 1"));
+
+ if (isSkylark()) {
+ checkEvalError("ERROR 1:6: name 'foo' is not defined", "8 or foo");
+ checkEvalError("ERROR 1:7: name 'foo' is not defined", "0 and foo");
+ checkEvalError("ERROR 1:7: bad or operator: int is incompatible with string at 1:1",
+ "\"\" or 9");
+ checkEvalError("ERROR 1:10: bad or operator: int is incompatible with string at 1:1",
+ "\"abc\" or 9");
+ } else {
+ assertEquals(8, eval("8 or foo")); // check that 'foo' is not evaluated
+ assertEquals(0, eval("0 and foo")); // check that 'foo' is not evaluated
+ assertEquals(9, eval("\"\" or 9"));
+ assertEquals("abc", eval("\"abc\" or 9"));
+ }
}
@Test
@@ -128,6 +110,15 @@
@Test
public void testNotWithLogicOperators() throws Exception {
+ assertEquals(true, eval("not (0 and 0)"));
+ assertEquals(false, eval("not (1 or 0)"));
+
+ if (isSkylark()) {
+ checkEvalError(
+ "ERROR 1:7: bad and operator: bool is incompatible with int at 1:1", "0 and not 0");
+ return;
+ }
+
assertEquals(0, eval("0 and not 0"));
assertEquals(0, eval("not 0 and 0"));
@@ -136,9 +127,6 @@
assertEquals(0, eval("not 1 or 0"));
assertEquals(1, eval("not 1 or 1"));
-
- assertEquals(true, eval("not (0 and 0)"));
- assertEquals(false, eval("not (1 or 0)"));
}
@Test
@@ -159,9 +147,15 @@
assertEquals(false, eval("1 == 2"));
assertEquals(true, eval("'hello' == 'hel' + 'lo'"));
assertEquals(false, eval("'hello' == 'bye'"));
- assertEquals(true, eval("[1, 2] == [1, 2]"));
- assertEquals(false, eval("[1, 2] == [2, 1]"));
assertEquals(true, eval("None == None"));
+
+ if (isSkylark()) {
+ checkEvalError("ERROR 1:1: list of ints is not comparable", "[1, 2] == [1, 2]");
+ checkEvalError("ERROR 1:1: list of ints is not comparable", "[1, 2] == [2, 1]");
+ } else {
+ assertEquals(true, eval("[1, 2] == [1, 2]"));
+ assertEquals(false, eval("[1, 2] == [2, 1]"));
+ }
}
@Test
@@ -170,8 +164,13 @@
assertEquals(true, eval("1 != 2"));
assertEquals(false, eval("'hello' != 'hel' + 'lo'"));
assertEquals(true, eval("'hello' != 'bye'"));
- assertEquals(false, eval("[1, 2] != [1, 2]"));
- assertEquals(true, eval("[1, 2] != [2, 1]"));
+ if (isSkylark()) {
+ checkEvalError("ERROR 1:1: list of ints is not comparable", "[1, 2] != [1, 2]");
+ checkEvalError("ERROR 1:1: list of ints is not comparable", "[1, 2] != [2, 1]");
+ } else {
+ assertEquals(false, eval("[1, 2] != [1, 2]"));
+ assertEquals(true, eval("[1, 2] != [2, 1]"));
+ }
}
@Test
@@ -179,8 +178,15 @@
assertEquals(true, eval("1 + 3 == 2 + 2"));
assertEquals(true, eval("not 1 == 2"));
assertEquals(false, eval("not 1 != 2"));
- assertEquals(true, eval("2 and 3 == 3 or 1"));
- assertEquals(2, eval("2 or 3 == 3 and 1"));
+ if (isSkylark()) {
+ checkEvalError("ERROR 1:7: bad and operator: bool is incompatible with int at 1:1",
+ "2 and 3 == 3 or 1");
+ checkEvalError("ERROR 1:17: bad and operator: int is incompatible with bool at 1:6",
+ "2 or 3 == 3 and 1");
+ } else {
+ assertEquals(true, eval("2 and 3 == 3 or 1"));
+ assertEquals(2, eval("2 or 3 == 3 and 1"));
+ }
}
@Test
@@ -205,21 +211,20 @@
assertEquals(2, eval("1 if False else 2"));
assertEquals(3, eval("1 + 2 if 3 + 4 else 5 + 6"));
- syntaxEvents.setFailFast(false);
- parseExpr("1 if 2");
- syntaxEvents.assertContainsEvent(
+ setFailFast(false);
+ parseExpression("1 if 2");
+ assertContainsEvent(
"missing else clause in conditional expression or semicolon before if");
- syntaxEvents.collector().clear();
}
@Test
public void testCompareStringInt() throws Exception {
- checkEvalError("'a' >= 1", "Cannot compare string with int");
+ checkEvalError("Cannot compare string with int", "'a' >= 1");
}
@Test
public void testNotComparable() throws Exception {
- checkEvalError("[1, 2] < [1, 3]", "[1, 2] is not comparable");
+ checkEvalError("[1, 2] is not comparable", "[1, 2] < [1, 3]");
}
@Test
@@ -236,54 +241,38 @@
}
};
- Environment env = singletonEnv(sum.getName(), sum);
+ update(sum.getName(), sum);
+ assertEquals(21, eval("sum(1, 2, 3, 4, 5, 6)"));
+ assertEquals(sum, eval("sum"));
+ assertEquals(0, eval("sum(a=1, b=2)"));
+ }
- String callExpr = "sum(1, 2, 3, 4, 5, 6)";
- assertEquals(21, eval(callExpr, env));
-
- assertEquals(sum, eval("sum", env));
-
- assertEquals(0, eval("sum(a=1, b=2)", env));
-
- // rebind 'sum' in a new environment:
- env = new Environment();
- exec(parseStmt("sum = 123456"), env);
-
- assertEquals(123456, env.lookup("sum"));
-
- // now we can't call it any more:
- checkEvalError(callExpr, env, "'int' object is not callable");
-
- assertEquals(123456, eval("sum", env));
+ @Test
+ public void testNotCallInt() throws Exception {
+ eval("sum = 123456");
+ assertEquals(123456, lookup("sum"));
+ checkEvalError("'int' object is not callable", "sum(1, 2, 3, 4, 5, 6)");
+ assertEquals(123456, eval("sum"));
}
@Test
public void testKeywordArgs() throws Exception {
- // This function returns the list of keyword-argument keys or values,
- // depending on whether its first (integer) parameter is zero.
- Function keyval = new AbstractFunction("keyval") {
+ // This function returns the map of keyword-argument keys or values,
+ Function kwargs = new AbstractFunction("kwargs") {
@Override
public Object call(List<Object> args,
final Map<String, Object> kwargs,
FuncallExpression ast,
Environment env) {
- List<String> keys = Ordering.natural().sortedCopy(new ArrayList<String>(kwargs.keySet()));
- if ((Integer) args.get(0) == 0) {
- return keys;
- } else {
- return Lists.transform(keys, Functions.forMap(kwargs, null));
- }
+ return kwargs;
}
};
- Environment env = singletonEnv(keyval.getName(), keyval);
+ update(kwargs.getName(), kwargs);
- assertEquals(eval("['bar', 'foo', 'wiz']"),
- eval("keyval(0, foo=1, bar='bar', wiz=[1,2,3])", env));
-
- assertEquals(eval("['bar', 1, [1,2,3]]"),
- eval("keyval(1, foo=1, bar='bar', wiz=[1,2,3])", env));
+ assertEquals(eval("[('bar', 'bar'), ('foo', 1), ('wiz', [1, 2, 3])]"),
+ eval("kwargs(foo=1, bar='bar', wiz=[1,2,3]).items()"));
}
@Test
@@ -300,10 +289,12 @@
assertEquals("foobar", eval("'foo' + 'bar'"));
}
+ @SuppressWarnings("unchecked")
@Test
public void testConcatLists() throws Exception {
// list
Object x = eval("[1,2] + [3,4]");
+ assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
assertEquals(Arrays.asList(1, 2, 3, 4), x);
assertFalse(EvalUtils.isImmutable(x));
@@ -312,91 +303,90 @@
assertEquals(Arrays.asList(1, 2, 3, 4), x);
assertTrue(EvalUtils.isImmutable(x));
- checkEvalError("(1,2) + [3,4]", // list + tuple
- "can only concatenate List (not \"Tuple\") to List");
+ checkEvalError("can only concatenate List (not \"Tuple\") to List",
+ "(1,2) + [3,4]"); // list + tuple
}
@SuppressWarnings("unchecked")
@Test
public void testListComprehensions() throws Exception {
- Iterable<Object> eval = (Iterable<Object>) eval(
- "['foo/%s.java' % x for x in []]");
- assertThat(eval).isEmpty();
+ assertThat((Iterable<Object>) eval("['foo/%s.java' % x for x in []]")).isEmpty();
- eval = (Iterable<Object>) eval(
- "['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]");
- assertThat(eval).containsExactly("foo/bar.java", "foo/wiz.java", "foo/quux.java").inOrder();
+ assertThat((Iterable<Object>) eval("['foo/%s.java' % y for y in ['bar', 'wiz', 'quux']]"))
+ .containsExactly("foo/bar.java", "foo/wiz.java", "foo/quux.java").inOrder();
- eval = (Iterable<Object>) eval(
- "['%s/%s.java' % (x, y) "
- + "for x in ['foo', 'bar'] "
- + "for y in ['baz', 'wiz', 'quux']]");
- assertThat(eval).containsExactly("foo/baz.java", "foo/wiz.java", "foo/quux.java",
- "bar/baz.java", "bar/wiz.java", "bar/quux.java").inOrder();
+ assertThat((Iterable<Object>) eval(
+ "['%s/%s.java' % (z, t) "
+ + "for z in ['foo', 'bar'] "
+ + "for t in ['baz', 'wiz', 'quux']]"))
+ .containsExactly("foo/baz.java", "foo/wiz.java", "foo/quux.java",
+ "bar/baz.java", "bar/wiz.java", "bar/quux.java").inOrder();
- eval = (Iterable<Object>) eval(
- "['%s/%s.java' % (x, x) "
- + "for x in ['foo', 'bar'] "
- + "for x in ['baz', 'wiz', 'quux']]");
- assertThat(eval).containsExactly("baz/baz.java", "wiz/wiz.java", "quux/quux.java",
- "baz/baz.java", "wiz/wiz.java", "quux/quux.java").inOrder();
+ assertThat((Iterable<Object>) eval(
+ "['%s/%s.java' % (b, b) "
+ + "for a in ['foo', 'bar'] "
+ + "for b in ['baz', 'wiz', 'quux']]"))
+ .containsExactly("baz/baz.java", "wiz/wiz.java", "quux/quux.java",
+ "baz/baz.java", "wiz/wiz.java", "quux/quux.java").inOrder();
- eval = (Iterable<Object>) eval(
- "['%s/%s.%s' % (x, y, z) "
- + "for x in ['foo', 'bar'] "
- + "for y in ['baz', 'wiz', 'quux'] "
- + "for z in ['java', 'cc']]");
- assertThat(eval).containsExactly("foo/baz.java", "foo/baz.cc", "foo/wiz.java", "foo/wiz.cc",
- "foo/quux.java", "foo/quux.cc", "bar/baz.java", "bar/baz.cc", "bar/wiz.java", "bar/wiz.cc",
- "bar/quux.java", "bar/quux.cc").inOrder();
+ assertThat((Iterable<Object>) eval(
+ "['%s/%s.%s' % (c, d, e) "
+ + "for c in ['foo', 'bar'] "
+ + "for d in ['baz', 'wiz', 'quux'] "
+ + "for e in ['java', 'cc']]"))
+ .containsExactly("foo/baz.java", "foo/baz.cc", "foo/wiz.java", "foo/wiz.cc",
+ "foo/quux.java", "foo/quux.cc", "bar/baz.java", "bar/baz.cc",
+ "bar/wiz.java", "bar/wiz.cc", "bar/quux.java", "bar/quux.cc").inOrder();
}
@Test
public void testListComprehensionsMultipleVariables() throws Exception {
assertThat(eval("[x + y for x, y in [(1, 2), (3, 4)]]").toString())
.isEqualTo("[3, 7]");
- assertThat(eval("[x + y for (x, y) in [[1, 2], [3, 4]]]").toString())
+ assertThat(eval("[z + t for (z, t) in [[1, 2], [3, 4]]]").toString())
.isEqualTo("[3, 7]");
}
@Test
public void testListComprehensionsMultipleVariablesFail() throws Exception {
- checkEvalError("[x + y for x, y, z in [(1, 2), (3, 4)]]",
- "lvalue has length 3, but rvalue has has length 2");
+ checkEvalError("lvalue has length 3, but rvalue has has length 2",
+ "[x + y for x, y, z in [(1, 2), (3, 4)]]");
- checkEvalError("[x + y for x, y in (1, 2)]",
- "type 'int' is not a collection");
+ checkEvalError("type 'int' is not a collection",
+ "[x + y for x, y in (1, 2)]");
}
@Test
public void testTupleDestructuring() throws Exception {
- exec(parseFile("a, b = 1, 2"), env);
- assertThat(env.lookup("a")).isEqualTo(1);
- assertThat(env.lookup("b")).isEqualTo(2);
+ eval("a, b = 1, 2");
+ assertThat(lookup("a")).isEqualTo(1);
+ assertThat(lookup("b")).isEqualTo(2);
- exec(parseFile("c, d = {'key1':2, 'key2':3}"), env);
- assertThat(env.lookup("c")).isEqualTo("key1");
- assertThat(env.lookup("d")).isEqualTo("key2");
+ eval("c, d = {'key1':2, 'key2':3}");
+ assertThat(lookup("c")).isEqualTo("key1");
+ assertThat(lookup("d")).isEqualTo("key2");
}
@Test
public void testRecursiveTupleDestructuring() throws Exception {
- List<Statement> input = parseFile("((a, b), (c, d)) = [(1, 2), (3, 4)]");
- exec(input, env);
- assertThat(env.lookup("a")).isEqualTo(1);
- assertThat(env.lookup("b")).isEqualTo(2);
- assertThat(env.lookup("c")).isEqualTo(3);
- assertThat(env.lookup("d")).isEqualTo(4);
+ eval("((a, b), (c, d)) = [(1, 2), (3, 4)]");
+ assertThat(lookup("a")).isEqualTo(1);
+ assertThat(lookup("b")).isEqualTo(2);
+ assertThat(lookup("c")).isEqualTo(3);
+ assertThat(lookup("d")).isEqualTo(4);
}
- // TODO(bazel-team): should this test work in Skylark?
@SuppressWarnings("unchecked")
@Test
public void testListComprehensionModifiesGlobalEnv() throws Exception {
- Environment env = singletonEnv("x", 42);
- assertThat((Iterable<Object>) eval(parseExpr("[x + 1 for x in [1,2,3]]"), env))
- .containsExactly(2, 3, 4).inOrder();
- assertEquals(3, env.lookup("x")); // (x is global)
+ update("x", 42);
+ if (isSkylark()) {
+ checkEvalError("ERROR 1:1: Variable x is read only", "[x + 1 for x in [1,2,3]]");
+ } else {
+ assertThat((Iterable<Object>) eval("[x + 1 for x in [1,2,3]]"))
+ .containsExactly(2, 3, 4).inOrder();
+ assertEquals(3, lookup("x")); // (x is global)
+ }
}
@Test
@@ -421,53 +411,52 @@
@Test
public void testDictComprehensions_ToString() throws Exception {
- assertEquals("{x: x for x in [1, 2]}", parseExpr("{x : x for x in [1, 2]}").toString());
+ assertEquals("{x: x for x in [1, 2]}",
+ evaluationContext.parseExpression("{x : x for x in [1, 2]}").toString());
assertEquals("{x + 'a': x for x in [1, 2]}",
- parseExpr("{x + 'a' : x for x in [1, 2]}").toString());
+ evaluationContext.parseExpression("{x + 'a' : x for x in [1, 2]}").toString());
}
@Test
public void testListConcatenation() throws Exception {
- assertEquals(Arrays.asList(1, 2, 3, 4), eval("[1, 2] + [3, 4]", env));
- assertEquals(ImmutableList.of(1, 2, 3, 4), eval("(1, 2) + (3, 4)", env));
- checkEvalError("[1, 2] + (3, 4)", "can only concatenate Tuple (not \"List\") to Tuple");
- checkEvalError("(1, 2) + [3, 4]", "can only concatenate List (not \"Tuple\") to List");
+ assertEquals(Arrays.asList(1, 2, 3, 4), eval("[1, 2] + [3, 4]"));
+ assertEquals(ImmutableList.of(1, 2, 3, 4), eval("(1, 2) + (3, 4)"));
+ checkEvalError("can only concatenate Tuple (not \"List\") to Tuple",
+ "[1, 2] + (3, 4)");
+ checkEvalError("can only concatenate List (not \"Tuple\") to List",
+ "(1, 2) + [3, 4]");
}
@Test
public void testListComprehensionFailsOnNonSequence() throws Exception {
- checkEvalError("[x + 1 for x in 123]", "type 'int' is not an iterable");
+ checkEvalErrorContains("type 'int' is not iterable", "[x + 1 for x in 123]");
}
@SuppressWarnings("unchecked")
@Test
public void testListComprehensionOnString() throws Exception {
- assertThat((Iterable<Object>) eval("[x for x in 'abc']")).containsExactly("a", "b", "c")
- .inOrder();
+ assertThat((Iterable<Object>) eval("[x for x in 'abc']"))
+ .containsExactly("a", "b", "c").inOrder();
}
@Test
public void testInvalidAssignment() throws Exception {
- Environment env = singletonEnv("x", 1);
- checkEvalError(parseStmt("x + 1 = 2"), env,
- "can only assign to variables and tuples, not to 'x + 1'");
+ update("x", 1);
+ checkEvalErrorContains("can only assign to variables and tuples, not to 'x + 1'",
+ "x + 1 = 2");
}
+ @SuppressWarnings("unchecked")
@Test
public void testListComprehensionOnDictionary() throws Exception {
- List<Statement> input = parseFile("val = ['var_' + n for n in {'a':1,'b':2}]");
- exec(input, env);
- Iterable<?> result = (Iterable<?>) env.lookup("val");
- assertThat(result).hasSize(2);
- assertEquals("var_a", Iterables.get(result, 0));
- assertEquals("var_b", Iterables.get(result, 1));
+ assertThat((Iterable<Object>) eval("val = ['var_' + n for n in {'a':1,'b':2}] ; val"))
+ .containsExactly("var_a", "var_b").inOrder();
}
@Test
public void testListComprehensionOnDictionaryCompositeExpression() throws Exception {
- exec(parseFile("d = {1:'a',2:'b'}\n"
- + "l = [d[x] for x in d]"), env);
- assertEquals("[\"a\", \"b\"]", EvalUtils.prettyPrintValue(env.lookup("l")));
+ eval("d = {1:'a',2:'b'}\n" + "l = [d[x] for x in d]");
+ assertEquals("[\"a\", \"b\"]", EvalUtils.prettyPrintValue(lookup("l")));
}
@Test
@@ -485,14 +474,16 @@
@Test
public void testInFail() throws Exception {
- checkEvalError("1 in '123'",
- "in operator only works on strings if the left operand is also a string");
- checkEvalError("'a' in 1",
- "in operator only works on lists, tuples, sets, dicts and strings");
+ checkEvalError("in operator only works on strings if the left operand is also a string",
+ "1 in '123'");
+ checkEvalError("in operator only works on lists, tuples, sets, dicts and strings", "'a' in 1");
}
@Test
public void testInCompositeForPrecedence() throws Exception {
+ if (isSkylark()) {
+ return;
+ }
assertEquals(0, eval("not 'a' in ['a'] or 0"));
}
@@ -507,59 +498,32 @@
@Test
public void testPercOnObject() throws Exception {
- env.update("obj", createObjWithStr());
- assertEquals("str marker", eval("'%s' % obj", env));
+ update("obj", createObjWithStr());
+ assertEquals("str marker", eval("'%s' % obj"));
}
@Test
public void testPercOnObjectList() throws Exception {
- env.update("obj", createObjWithStr());
- assertEquals("str marker str marker", eval("'%s %s' % (obj, obj)", env));
+ update("obj", createObjWithStr());
+ assertEquals("str marker str marker", eval("'%s %s' % (obj, obj)"));
}
@Test
public void testPercOnObjectInvalidFormat() throws Exception {
- env.update("obj", createObjWithStr());
- checkEvalError("'%d' % obj", env, "invalid arguments for format string");
+ update("obj", createObjWithStr());
+ checkEvalError("invalid arguments for format string", "'%d' % obj");
}
@SuppressWarnings("unchecked")
@Test
public void testDictKeys() throws Exception {
- exec("v = {'a': 1}.keys() + ['b', 'c']", env);
- assertThat((Iterable<Object>) env.lookup("v")).containsExactly("a", "b", "c").inOrder();
+ assertThat((Iterable<Object>) eval("v = {'a': 1}.keys() + ['b', 'c'] ; v"))
+ .containsExactly("a", "b", "c").inOrder();
}
@Test
public void testDictKeysTooManyArgs() throws Exception {
- checkEvalError("{'a': 1}.keys('abc')", env, "Invalid number of arguments (expected 0)");
- checkEvalError("{'a': 1}.keys(arg='abc')", env, "Invalid number of arguments (expected 0)");
- }
-
- protected void checkEvalError(String input, String msg) throws Exception {
- checkEvalError(input, env, msg);
- }
-
- protected void checkEvalError(String input, Environment env, String msg) throws Exception {
- try {
- eval(input, env);
- fail();
- } catch (EvalException e) {
- assertThat(e).hasMessage(msg);
- }
- }
-
- protected void checkEvalError(Statement input, Environment env, String msg) throws Exception {
- checkEvalError(ImmutableList.of(input), env, msg);
- }
-
- protected void checkEvalError(List<Statement> input, Environment env, String msg)
- throws Exception {
- try {
- exec(input, env);
- fail();
- } catch (EvalException e) {
- assertThat(e).hasMessage(msg);
- }
+ checkEvalError("Invalid number of arguments (expected 0)", "{'a': 1}.keys('abc')");
+ checkEvalError("Invalid number of arguments (expected 0)", "{'a': 1}.keys(arg='abc')");
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java
new file mode 100644
index 0000000..5749c40
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java
@@ -0,0 +1,136 @@
+// Copyright 2006-2015 Google Inc. 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.syntax;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventCollector;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.util.EventCollectionApparatus;
+import com.google.devtools.build.lib.rules.SkylarkModules;
+
+import org.junit.Before;
+
+import java.util.List;
+
+/**
+ * Base class for test cases that use parsing and evaluation services.
+ */
+public class EvaluationTestCase {
+
+ private EventCollectionApparatus eventCollectionApparatus;
+ protected EvaluationContext evaluationContext;
+
+ @Before
+ public void setUp() throws Exception {
+ eventCollectionApparatus = new EventCollectionApparatus(EventKind.ALL_EVENTS);
+ evaluationContext = newEvaluationContext();
+ }
+
+ protected EventHandler getEventHandler() {
+ return eventCollectionApparatus.reporter();
+ }
+
+ public Environment getEnvironment() {
+ return evaluationContext.getEnvironment();
+ }
+
+ public EvaluationContext newEvaluationContext() throws Exception {
+ return SkylarkModules.newEvaluationContext(getEventHandler());
+ }
+
+ public boolean isSkylark() {
+ return evaluationContext.isSkylark();
+ }
+
+ protected List<Statement> parseFile(String... input) {
+ return evaluationContext.parseFile(input);
+ }
+
+ Expression parseExpression(String... input) {
+ return evaluationContext.parseExpression(input);
+ }
+
+ public EvaluationTestCase update(String varname, Object value) throws Exception {
+ evaluationContext.update(varname, value);
+ return this;
+ }
+
+ public Object lookup(String varname) throws Exception {
+ return evaluationContext.lookup(varname);
+ }
+
+ public Object eval(String... input) throws Exception {
+ return evaluationContext.eval(input);
+ }
+
+ public void checkEvalError(String msg, String... input) throws Exception {
+ setFailFast(true);
+ try {
+ eval(input);
+ fail();
+ } catch (IllegalArgumentException | EvalException e) {
+ assertThat(e).hasMessage(msg);
+ }
+ }
+
+ public void checkEvalErrorContains(String msg, String... input) throws Exception {
+ try {
+ eval(input);
+ fail();
+ } catch (IllegalArgumentException | EvalException e) {
+ assertThat(e.getMessage()).contains(msg);
+ }
+ }
+
+ public void checkEvalErrorStartsWith(String msg, String... input) throws Exception {
+ try {
+ eval(input);
+ fail();
+ } catch (IllegalArgumentException | EvalException e) {
+ assertThat(e.getMessage()).startsWith(msg);
+ }
+ }
+
+ // Forward relevant methods to the EventCollectionApparatus
+ public EvaluationTestCase setFailFast(boolean failFast) {
+ eventCollectionApparatus.setFailFast(failFast);
+ return this;
+ }
+ public EvaluationTestCase assertNoEvents() {
+ eventCollectionApparatus.assertNoEvents();
+ return this;
+ }
+ public EventCollector getEventCollector() {
+ return eventCollectionApparatus.collector();
+ }
+ public Event assertContainsEvent(String expectedMessage) {
+ return eventCollectionApparatus.assertContainsEvent(expectedMessage);
+ }
+ public List<Event> assertContainsEventWithFrequency(String expectedMessage,
+ int expectedFrequency) {
+ return eventCollectionApparatus.assertContainsEventWithFrequency(
+ expectedMessage, expectedFrequency);
+ }
+ public Event assertContainsEventWithWordsInQuotes(String... words) {
+ return eventCollectionApparatus.assertContainsEventWithWordsInQuotes(words);
+ }
+ public EvaluationTestCase clearEvents() {
+ eventCollectionApparatus.collector().clear();
+ return this;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java b/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java
index a55fc01..2b8547c 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/FunctionTest.java
@@ -16,14 +16,9 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.packages.MethodLibrary;
-import com.google.devtools.build.lib.syntax.SkylarkType.SkylarkFunctionType;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -36,61 +31,42 @@
* A test class for functions and scoping.
*/
@RunWith(JUnit4.class)
-public class FunctionTest extends AbstractEvaluationTestCase {
-
- private Environment env;
-
- private static final ImmutableMap<String, SkylarkType> OUTER_FUNC_TYPES =
- ImmutableMap.<String, SkylarkType>of(
- "outer_func", SkylarkFunctionType.of("outer_func", SkylarkType.NONE));
-
- @Before
- public void setUp() throws Exception {
-
- env = new SkylarkEnvironment(syntaxEvents.collector());
- }
+public class FunctionTest extends EvaluationTestCase {
@Test
public void testFunctionDef() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(a,b,c):\n"
- + " a = 1\n"
- + " b = a\n");
-
- exec(input, env);
- UserDefinedFunction stmt = (UserDefinedFunction) env.lookup("func");
+ eval("def func(a,b,c):",
+ " a = 1",
+ " b = a\n");
+ UserDefinedFunction stmt = (UserDefinedFunction) lookup("func");
assertNotNull(stmt);
- assertEquals("func", stmt.getName());
- assertEquals(3, stmt.getFunctionSignature().getSignature().getShape().getMandatoryPositionals());
+ assertThat(stmt.getName()).isEqualTo("func");
+ assertThat(stmt.getFunctionSignature().getSignature().getShape().getMandatoryPositionals())
+ .isEqualTo(3);
assertThat(stmt.getStatements()).hasSize(2);
}
@Test
public void testFunctionDefDuplicateArguments() throws Exception {
- syntaxEvents.setFailFast(false);
- parseFileForSkylark(
- "def func(a,b,a):\n"
- + " a = 1\n");
- syntaxEvents.assertContainsEvent("duplicate parameter name in function definition");
+ setFailFast(false);
+ parseFile("def func(a,b,a):",
+ " a = 1\n");
+ assertContainsEvent("duplicate parameter name in function definition");
}
@Test
public void testFunctionDefCallOuterFunc() throws Exception {
- final List<Object> params = new ArrayList<>();
- List<Statement> input = parseFileForSkylark(
- "def func(a):\n"
- + " outer_func(a)\n"
- + "func(1)\n"
- + "func(2)",
- OUTER_FUNC_TYPES);
- createOuterFunction(env, params);
- exec(input, env);
+ List<Object> params = new ArrayList<>();
+ createOuterFunction(params);
+ eval("def func(a):",
+ " outer_func(a)",
+ "func(1)",
+ "func(2)");
assertThat(params).containsExactly(1, 2).inOrder();
}
- private void createOuterFunction(Environment env, final List<Object> params) {
+ private void createOuterFunction(final List<Object> params) throws Exception {
BaseFunction outerFunc = new BaseFunction("outer_func") {
-
@Override
public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
Environment env) throws EvalException, InterruptedException {
@@ -98,271 +74,222 @@
return Environment.NONE;
}
};
- env.update("outer_func", outerFunc);
+ update("outer_func", outerFunc);
}
@Test
public void testFunctionDefNoEffectOutsideScope() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func():\n"
- + " a = 2\n"
- + "func()\n");
- env.update("a", 1);
- exec(input, env);
- assertEquals(1, env.lookup("a"));
+ update("a", 1);
+ eval("def func():",
+ " a = 2",
+ "func()\n");
+ assertEquals(1, lookup("a"));
}
@Test
public void testFunctionDefGlobalVaribleReadInFunction() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 1\n"
- + "def func():\n"
- + " b = a\n"
- + " return b\n"
- + "c = func()\n");
- exec(input, env);
- assertEquals(1, env.lookup("c"));
+ eval("a = 1",
+ "def func():",
+ " b = a",
+ " return b",
+ "c = func()\n");
+ assertEquals(1, lookup("c"));
}
@Test
public void testFunctionDefLocalGlobalScope() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 1\n"
- + "def func():\n"
- + " a = 2\n"
- + " b = a\n"
- + " return b\n"
- + "c = func()\n");
- exec(input, env);
- assertEquals(2, env.lookup("c"));
+ eval("a = 1",
+ "def func():",
+ " a = 2",
+ " b = a",
+ " return b",
+ "c = func()\n");
+ assertEquals(2, lookup("c"));
}
@Test
public void testFunctionDefLocalVariableReferencedBeforeAssignment() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 1\n"
- + "def func():\n"
- + " b = a\n"
- + " a = 2\n"
- + " return b\n"
- + "c = func()\n");
- try {
- exec(input, env);
- fail();
- } catch (EvalException e) {
- assertThat(e.getMessage()).contains("Variable 'a' is referenced before assignment.");
- }
+ checkEvalErrorContains("Variable 'a' is referenced before assignment.",
+ "a = 1",
+ "def func():",
+ " b = a",
+ " a = 2",
+ " return b",
+ "c = func()\n");
}
@Test
public void testFunctionDefLocalVariableReferencedAfterAssignment() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 1\n"
- + "def func():\n"
- + " a = 2\n"
- + " b = a\n"
- + " a = 3\n"
- + " return b\n"
- + "c = func()\n");
- exec(input, env);
- assertEquals(2, env.lookup("c"));
+ eval("a = 1",
+ "def func():",
+ " a = 2",
+ " b = a",
+ " a = 3",
+ " return b",
+ "c = func()\n");
+ assertEquals(2, lookup("c"));
}
@SuppressWarnings("unchecked")
@Test
public void testSkylarkGlobalComprehensionIsAllowed() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = [i for i in [1, 2, 3]]\n");
- exec(input, env);
- assertThat((Iterable<Object>) env.lookup("a")).containsExactly(1, 2, 3).inOrder();
+ eval("a = [i for i in [1, 2, 3]]\n");
+ assertThat((Iterable<Object>) lookup("a")).containsExactly(1, 2, 3).inOrder();
}
@Test
public void testFunctionReturn() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func():\n"
- + " return 2\n"
- + "b = func()\n");
- exec(input, env);
- assertEquals(2, env.lookup("b"));
+ eval("def func():",
+ " return 2",
+ "b = func()\n");
+ assertEquals(2, lookup("b"));
}
@Test
public void testFunctionReturnFromALoop() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func():\n"
- + " for i in [1, 2, 3, 4, 5]:\n"
- + " return i\n"
- + "b = func()\n");
- exec(input, env);
- assertEquals(1, env.lookup("b"));
+ eval("def func():",
+ " for i in [1, 2, 3, 4, 5]:",
+ " return i",
+ "b = func()\n");
+ assertEquals(1, lookup("b"));
}
@Test
public void testFunctionExecutesProperly() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(a):\n"
- + " b = 1\n"
- + " if a:\n"
- + " b = 2\n"
- + " return b\n"
- + "c = func(0)\n"
- + "d = func(1)\n");
- exec(input, env);
- assertEquals(1, env.lookup("c"));
- assertEquals(2, env.lookup("d"));
+ eval("def func(a):",
+ " b = 1",
+ " if a:",
+ " b = 2",
+ " return b",
+ "c = func(0)",
+ "d = func(1)\n");
+ assertEquals(1, lookup("c"));
+ assertEquals(2, lookup("d"));
}
@Test
public void testFunctionCallFromFunction() throws Exception {
final List<Object> params = new ArrayList<>();
- List<Statement> input = parseFileForSkylark(
- "def func2(a):\n"
- + " outer_func(a)\n"
- + "def func1(b):\n"
- + " func2(b)\n"
- + "func1(1)\n"
- + "func1(2)\n",
- OUTER_FUNC_TYPES);
- createOuterFunction(env, params);
- exec(input, env);
+ createOuterFunction(params);
+ eval("def func2(a):",
+ " outer_func(a)",
+ "def func1(b):",
+ " func2(b)",
+ "func1(1)",
+ "func1(2)\n");
assertThat(params).containsExactly(1, 2).inOrder();
}
@Test
public void testFunctionCallFromFunctionReadGlobalVar() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 1\n"
- + "def func2():\n"
- + " return a\n"
- + "def func1():\n"
- + " return func2()\n"
- + "b = func1()\n");
- exec(input, env);
- assertEquals(1, env.lookup("b"));
+ eval("a = 1",
+ "def func2():",
+ " return a",
+ "def func1():",
+ " return func2()",
+ "b = func1()\n");
+ assertEquals(1, lookup("b"));
}
@Test
public void testSingleLineFunction() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(): return 'a'\n"
- + "s = func()\n");
- exec(input, env);
- assertEquals("a", env.lookup("s"));
+ eval("def func(): return 'a'",
+ "s = func()\n");
+ assertEquals("a", lookup("s"));
}
@Test
public void testFunctionReturnsDictionary() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- List<Statement> input = parseFileForSkylark(
- "def func(): return {'a' : 1}\n"
- + "d = func()\n"
- + "a = d['a']\n");
- exec(input, env);
- assertEquals(1, env.lookup("a"));
+ eval("def func(): return {'a' : 1}",
+ "d = func()",
+ "a = d['a']\n");
+ assertEquals(1, lookup("a"));
}
@Test
public void testFunctionReturnsList() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- List<Statement> input = parseFileForSkylark(
- "def func(): return [1, 2, 3]\n"
- + "d = func()\n"
- + "a = d[1]\n");
- exec(input, env);
- assertEquals(2, env.lookup("a"));
+ eval("def func(): return [1, 2, 3]",
+ "d = func()",
+ "a = d[1]\n");
+ assertEquals(2, lookup("a"));
}
@SuppressWarnings("unchecked")
@Test
public void testFunctionListArgumentsAreImmutable() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- List<Statement> input = parseFileForSkylark(
- "l = [1]\n"
- + "def func(l):\n"
- + " l += [2]\n"
- + "func(l)");
- exec(input, env);
- assertThat((Iterable<Object>) env.lookup("l")).containsExactly(1);
+ eval("l = [1]",
+ "def func(l):",
+ " l += [2]",
+ "func(l)");
+ assertThat((Iterable<Object>) lookup("l")).containsExactly(1);
}
@Test
public void testFunctionDictArgumentsAreImmutable() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- List<Statement> input = parseFileForSkylark(
- "d = {'a' : 1}\n"
- + "def func(d):\n"
- + " d += {'a' : 2}\n"
- + "func(d)");
- exec(input, env);
- assertEquals(ImmutableMap.of("a", 1), env.lookup("d"));
+ eval("d = {'a' : 1}",
+ "def func(d):",
+ " d += {'a' : 2}",
+ "func(d)");
+ assertEquals(ImmutableMap.of("a", 1), lookup("d"));
}
@Test
public void testFunctionNameAliasing() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(a):\n"
- + " return a + 1\n"
- + "alias = func\n"
- + "r = alias(1)");
- exec(input, env);
- assertEquals(2, env.lookup("r"));
+ eval("def func(a):",
+ " return a + 1",
+ "alias = func",
+ "r = alias(1)");
+ assertEquals(2, lookup("r"));
}
@Test
public void testCallingFunctionsWithMixedModeArgs() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(a, b, c):\n"
- + " return a + b + c\n"
- + "v = func(1, c = 2, b = 3)");
- exec(input, env);
- assertEquals(6, env.lookup("v"));
+ eval("def func(a, b, c):",
+ " return a + b + c",
+ "v = func(1, c = 2, b = 3)");
+ assertEquals(6, lookup("v"));
}
private String functionWithOptionalArgs() {
return "def func(a, b = None, c = None):\n"
- + " r = a + 'a'\n"
- + " if b:\n"
- + " r += 'b'\n"
- + " if c:\n"
- + " r += 'c'\n"
- + " return r\n";
+ + " r = a + 'a'\n"
+ + " if b:\n"
+ + " r += 'b'\n"
+ + " if c:\n"
+ + " r += 'c'\n"
+ + " return r\n";
}
@Test
public void testWhichOptionalArgsAreDefinedForFunctions() throws Exception {
- List<Statement> input = parseFileForSkylark(
- functionWithOptionalArgs()
- + "v1 = func('1', 1, 1)\n"
- + "v2 = func(b = 2, a = '2', c = 2)\n"
- + "v3 = func('3')\n"
- + "v4 = func('4', c = 1)\n");
- exec(input, env);
- assertEquals("1abc", env.lookup("v1"));
- assertEquals("2abc", env.lookup("v2"));
- assertEquals("3a", env.lookup("v3"));
- assertEquals("4ac", env.lookup("v4"));
+ eval(functionWithOptionalArgs(),
+ "v1 = func('1', 1, 1)",
+ "v2 = func(b = 2, a = '2', c = 2)",
+ "v3 = func('3')",
+ "v4 = func('4', c = 1)\n");
+ assertEquals("1abc", lookup("v1"));
+ assertEquals("2abc", lookup("v2"));
+ assertEquals("3a", lookup("v3"));
+ assertEquals("4ac", lookup("v4"));
}
@Test
public void testDefaultArguments() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func(a, b = 'b', c = 'c'):\n"
- + " return a + b + c\n"
- + "v1 = func('a', 'x', 'y')\n"
- + "v2 = func(b = 'x', a = 'a', c = 'y')\n"
- + "v3 = func('a')\n"
- + "v4 = func('a', c = 'y')\n");
- exec(input, env);
- assertEquals("axy", env.lookup("v1"));
- assertEquals("axy", env.lookup("v2"));
- assertEquals("abc", env.lookup("v3"));
- assertEquals("aby", env.lookup("v4"));
+ eval("def func(a, b = 'b', c = 'c'):",
+ " return a + b + c",
+ "v1 = func('a', 'x', 'y')",
+ "v2 = func(b = 'x', a = 'a', c = 'y')",
+ "v3 = func('a')",
+ "v4 = func('a', c = 'y')\n");
+ assertEquals("axy", lookup("v1"));
+ assertEquals("axy", lookup("v2"));
+ assertEquals("abc", lookup("v3"));
+ assertEquals("aby", lookup("v4"));
}
@Test
public void testDefaultArgumentsInsufficientArgNum() throws Exception {
- checkError("insufficient arguments received by func(a, b = \"b\", c = \"c\") "
+ checkEvalError("insufficient arguments received by func(a, b = \"b\", c = \"c\") "
+ "(got 0, expected at least 1)",
"def func(a, b = 'b', c = 'c'):",
" return a + b + c",
@@ -371,118 +298,93 @@
@Test
public void testKwargs() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo(a, b = 'b', *, c, d = 'd'):\n"
- + " return a + b + c + d\n"
- + "args = {'a': 'x', 'c': 'z'}\n"
- + "v1 = foo(**args)\n"
- + "v2 = foo('x', c = 'c', d = 'e', **{'b': 'y'})\n"
- + "v3 = foo(c = 'z', a = 'x', **{'b': 'y', 'd': 'f'})");
- exec(input, env);
- assertEquals("xbzd", env.lookup("v1"));
- assertEquals("xyce", env.lookup("v2"));
- assertEquals("xyzf", env.lookup("v3"));
- UserDefinedFunction foo = (UserDefinedFunction) env.lookup("foo");
+ eval("def foo(a, b = 'b', *, c, d = 'd'):",
+ " return a + b + c + d",
+ "args = {'a': 'x', 'c': 'z'}",
+ "v1 = foo(**args)",
+ "v2 = foo('x', c = 'c', d = 'e', **{'b': 'y'})",
+ "v3 = foo(c = 'z', a = 'x', **{'b': 'y', 'd': 'f'})");
+ assertEquals("xbzd", lookup("v1"));
+ assertEquals("xyce", lookup("v2"));
+ assertEquals("xyzf", lookup("v3"));
+ UserDefinedFunction foo = (UserDefinedFunction) lookup("foo");
assertEquals("foo(a, b = \"b\", *, c, d = \"d\")", foo.toString());
}
@Test
public void testKwargsBadKey() throws Exception {
- checkError("Keywords must be strings, not int",
- "def func(a, b):",
- " return a + b",
+ checkEvalError("Keywords must be strings, not int",
+ "def func(a, b): return a + b",
"func('a', **{3: 1})");
}
@Test
public void testKwargsIsNotDict() throws Exception {
- checkError("Argument after ** must be a dictionary, not int",
- "def func(a, b):",
- " return a + b",
+ checkEvalError("Argument after ** must be a dictionary, not int",
+ "def func(a, b): return a + b",
"func('a', **42)");
}
@Test
public void testKwargsCollision() throws Exception {
- checkError("argument 'b' passed both by position and by name in call to func(a, b)",
- "def func(a, b):",
- " return a + b",
+ checkEvalError("argument 'b' passed both by position and by name in call to func(a, b)",
+ "def func(a, b): return a + b",
"func('a', 'b', **{'b': 'foo'})");
}
@Test
public void testKwargsCollisionWithNamed() throws Exception {
- checkError("duplicate keyword 'b' in call to func",
- "def func(a, b):",
- " return a + b",
+ checkEvalError("duplicate keyword 'b' in call to func",
+ "def func(a, b): return a + b",
"func('a', b = 'b', **{'b': 'foo'})");
}
@Test
public void testDefaultArguments2() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "a = 2\n"
- + "def foo(x=a): return x\n"
- + "def bar():\n"
- + " a = 3\n"
- + " return foo()\n"
- + "v = bar()\n");
- exec(input, env);
- assertEquals(2, env.lookup("v"));
+ eval("a = 2",
+ "def foo(x=a): return x",
+ "def bar():",
+ " a = 3",
+ " return foo()",
+ "v = bar()\n");
+ assertEquals(2, lookup("v"));
}
@Test
public void testMixingPositionalOptional() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def f(name, value = '', optional = ''): return value\n"
- + "v = f('name', 'value')\n");
- exec(input, env);
- assertEquals("value", env.lookup("v"));
+ eval("def f(name, value = '', optional = ''): return value",
+ "v = f('name', 'value')\n");
+ assertEquals("value", lookup("v"));
}
@Test
public void testStarArg() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def f(name, value = '1', optional = '2'): return name + value + optional\n"
- + "v1 = f(*['name', 'value'])\n"
- + "v2 = f('0', *['name', 'value'])\n"
- + "v3 = f('0', *['b'], optional = '3')\n"
- + "v4 = f(*[],name='a')\n");
- exec(input, env);
- assertEquals("namevalue2", env.lookup("v1"));
- assertEquals("0namevalue", env.lookup("v2"));
- assertEquals("0b3", env.lookup("v3"));
- assertEquals("a12", env.lookup("v4"));
+ eval("def f(name, value = '1', optional = '2'): return name + value + optional",
+ "v1 = f(*['name', 'value'])",
+ "v2 = f('0', *['name', 'value'])",
+ "v3 = f('0', *['b'], optional = '3')",
+ "v4 = f(*[],name='a')\n");
+ assertEquals("namevalue2", lookup("v1"));
+ assertEquals("0namevalue", lookup("v2"));
+ assertEquals("0b3", lookup("v3"));
+ assertEquals("a12", lookup("v4"));
}
@Test
public void testStarParam() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def f(name, value = '1', *rest, mandatory, optional = '2'):\n"
- + " r = name + value + mandatory + optional + '|'\n"
- + " for x in rest: r += x\n"
- + " return r\n"
- + "v1 = f('a', 'b', mandatory = 'z')\n"
- + "v2 = f('a', 'b', 'c', 'd', mandatory = 'z')\n"
- + "v3 = f('a', *['b', 'c', 'd'], mandatory = 'y', optional = 'z')\n"
- + "v4 = f(*['a'], **{'value': 'b', 'mandatory': 'c'})\n"
- + "v5 = f('a', 'b', 'c', *['d', 'e'], mandatory = 'f', **{'optional': 'g'})\n");
- exec(input, env);
- assertEquals("abz2|", env.lookup("v1"));
- assertEquals("abz2|cd", env.lookup("v2"));
- assertEquals("abyz|cd", env.lookup("v3"));
- assertEquals("abc2|", env.lookup("v4"));
- assertEquals("abfg|cde", env.lookup("v5"));
- }
-
- private void checkError(String msg, String... lines)
- throws Exception {
- try {
- List<Statement> input = parseFileForSkylark(Joiner.on("\n").join(lines));
- exec(input, env);
- fail();
- } catch (EvalException e) {
- assertThat(e).hasMessage(msg);
- }
+ eval("def f(name, value = '1', *rest, mandatory, optional = '2'):",
+ " r = name + value + mandatory + optional + '|'",
+ " for x in rest: r += x",
+ " return r",
+ "v1 = f('a', 'b', mandatory = 'z')",
+ "v2 = f('a', 'b', 'c', 'd', mandatory = 'z')",
+ "v3 = f('a', *['b', 'c', 'd'], mandatory = 'y', optional = 'z')",
+ "v4 = f(*['a'], **{'value': 'b', 'mandatory': 'c'})",
+ "v5 = f('a', 'b', 'c', *['d', 'e'], mandatory = 'f', **{'optional': 'g'})\n");
+ assertEquals("abz2|", lookup("v1"));
+ assertEquals("abz2|cd", lookup("v2"));
+ assertEquals("abyz|cd", lookup("v3"));
+ assertEquals("abc2|", lookup("v4"));
+ assertEquals("abfg|cde", lookup("v5"));
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MixedModeFunctionTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MixedModeFunctionTest.java
index 6b7355b..b45e951 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/MixedModeFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/MixedModeFunctionTest.java
@@ -29,13 +29,7 @@
* Tests for {@link MixedModeFunction}.
*/
@RunWith(JUnit4.class)
-public class MixedModeFunctionTest extends AbstractEvaluationTestCase {
-
- private Environment singletonEnv(String id, Object value) {
- Environment env = new Environment();
- env.update(id, value);
- return env;
- }
+public class MixedModeFunctionTest extends EvaluationTestCase {
/**
* Handy implementation of {@link MixedModeFunction} that just tuples up its args and returns
@@ -56,14 +50,15 @@
private void checkMixedMode(Function func,
String callExpression,
String expectedOutput) throws Exception {
- Environment env = singletonEnv(func.getName(), func);
+ setUp();
+ update(func.getName(), func);
if (expectedOutput.charAt(0) == '[') { // a tuple => expected to pass
assertEquals(expectedOutput,
- eval(callExpression, env).toString());
+ eval(callExpression).toString());
} else { // expected to fail with an exception
try {
- eval(callExpression, env);
+ eval(callExpression);
fail();
} catch (EvalException e) {
assertThat(e).hasMessage(expectedOutput);
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
index 12c9abe..e568fd1 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
@@ -20,11 +20,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -35,7 +35,37 @@
* Tests of parser behaviour.
*/
@RunWith(JUnit4.class)
-public class ParserTest extends AbstractParserTestCase {
+public class ParserTest extends EvaluationTestCase {
+
+ EvaluationContext buildContext;
+ EvaluationContext buildContextWithPython;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ buildContext = EvaluationContext.newBuildContext(getEventHandler());
+ buildContextWithPython = EvaluationContext.newBuildContext(
+ getEventHandler(), new Environment(), /*parsePython*/true);
+ }
+
+ private Parser.ParseResult parseFileWithComments(String... input) {
+ return buildContext.parseFileWithComments(input);
+ }
+ @Override
+ protected List<Statement> parseFile(String... input) {
+ return buildContext.parseFile(input);
+ }
+ private List<Statement> parseFileWithPython(String... input) {
+ return buildContextWithPython.parseFile(input);
+ }
+ private List<Statement> parseFileForSkylark(String... input) {
+ return evaluationContext.parseFile(input);
+ }
+ private Statement parseStatement(String... input) {
+ return buildContext.parseStatement(input);
+ }
+
private static String getText(String text, ASTNode node) {
return text.substring(node.getLocation().getStartOffset(),
@@ -70,7 +100,7 @@
@Test
public void testPrecedence1() throws Exception {
BinaryOperatorExpression e =
- (BinaryOperatorExpression) parseExpr("'%sx' % 'foo' + 'bar'");
+ (BinaryOperatorExpression) parseExpression("'%sx' % 'foo' + 'bar'");
assertEquals(Operator.PLUS, e.getOperator());
}
@@ -78,28 +108,28 @@
@Test
public void testPrecedence2() throws Exception {
BinaryOperatorExpression e =
- (BinaryOperatorExpression) parseExpr("('%sx' % 'foo') + 'bar'");
+ (BinaryOperatorExpression) parseExpression("('%sx' % 'foo') + 'bar'");
assertEquals(Operator.PLUS, e.getOperator());
}
@Test
public void testPrecedence3() throws Exception {
BinaryOperatorExpression e =
- (BinaryOperatorExpression) parseExpr("'%sx' % ('foo' + 'bar')");
+ (BinaryOperatorExpression) parseExpression("'%sx' % ('foo' + 'bar')");
assertEquals(Operator.PERCENT, e.getOperator());
}
@Test
public void testPrecedence4() throws Exception {
BinaryOperatorExpression e =
- (BinaryOperatorExpression) parseExpr("1 + - (2 - 3)");
+ (BinaryOperatorExpression) parseExpression("1 + - (2 - 3)");
assertEquals(Operator.PLUS, e.getOperator());
}
@Test
public void testUnaryMinusExpr() throws Exception {
- FuncallExpression e = (FuncallExpression) parseExpr("-5");
- FuncallExpression e2 = (FuncallExpression) parseExpr("- 5");
+ FuncallExpression e = (FuncallExpression) parseExpression("-5");
+ FuncallExpression e2 = (FuncallExpression) parseExpression("- 5");
assertEquals("-", e.getFunction().getName());
assertEquals("-", e2.getFunction().getName());
@@ -113,7 +143,7 @@
@Test
public void testFuncallExpr() throws Exception {
- FuncallExpression e = (FuncallExpression) parseExpr("foo(1, 2, bar=wiz)");
+ FuncallExpression e = (FuncallExpression) parseExpression("foo(1, 2, bar=wiz)");
Ident ident = e.getFunction();
assertEquals("foo", ident.getName());
@@ -136,7 +166,7 @@
@Test
public void testMethCallExpr() throws Exception {
FuncallExpression e =
- (FuncallExpression) parseExpr("foo.foo(1, 2, bar=wiz)");
+ (FuncallExpression) parseExpression("foo.foo(1, 2, bar=wiz)");
Ident ident = e.getFunction();
assertEquals("foo", ident.getName());
@@ -159,7 +189,7 @@
@Test
public void testChainedMethCallExpr() throws Exception {
FuncallExpression e =
- (FuncallExpression) parseExpr("foo.replace().split(1)");
+ (FuncallExpression) parseExpression("foo.replace().split(1)");
Ident ident = e.getFunction();
assertEquals("split", ident.getName());
@@ -173,7 +203,7 @@
@Test
public void testPropRefExpr() throws Exception {
- DotExpression e = (DotExpression) parseExpr("foo.foo");
+ DotExpression e = (DotExpression) parseExpression("foo.foo");
Ident ident = e.getField();
assertEquals("foo", ident.getName());
@@ -181,7 +211,7 @@
@Test
public void testStringMethExpr() throws Exception {
- FuncallExpression e = (FuncallExpression) parseExpr("'foo'.foo()");
+ FuncallExpression e = (FuncallExpression) parseExpression("'foo'.foo()");
Ident ident = e.getFunction();
assertEquals("foo", ident.getName());
@@ -191,39 +221,39 @@
@Test
public void testStringLiteralOptimizationValue() throws Exception {
- StringLiteral l = (StringLiteral) parseExpr("'abc' + 'def'");
+ StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
assertEquals("abcdef", l.value);
}
@Test
public void testStringLiteralOptimizationToString() throws Exception {
- StringLiteral l = (StringLiteral) parseExpr("'abc' + 'def'");
+ StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
assertEquals("'abcdef'", l.toString());
}
@Test
public void testStringLiteralOptimizationLocation() throws Exception {
- StringLiteral l = (StringLiteral) parseExpr("'abc' + 'def'");
+ StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
assertEquals(0, l.getLocation().getStartOffset());
assertEquals(13, l.getLocation().getEndOffset());
}
@Test
public void testStringLiteralOptimizationDifferentQuote() throws Exception {
- assertThat(parseExpr("'abc' + \"def\"")).isInstanceOf(BinaryOperatorExpression.class);
+ assertThat(parseExpression("'abc' + \"def\"")).isInstanceOf(BinaryOperatorExpression.class);
}
@Test
public void testSubstring() throws Exception {
- FuncallExpression e = (FuncallExpression) parseExpr("'FOO.CC'[:].lower()[1:]");
+ FuncallExpression e = (FuncallExpression) parseExpression("'FOO.CC'[:].lower()[1:]");
assertEquals("$slice", e.getFunction().getName());
assertThat(e.getArguments()).hasSize(2);
- e = (FuncallExpression) parseExpr("'FOO.CC'.lower()[1:].startswith('oo')");
+ e = (FuncallExpression) parseExpression("'FOO.CC'.lower()[1:].startswith('oo')");
assertEquals("startswith", e.getFunction().getName());
assertThat(e.getArguments()).hasSize(1);
- e = (FuncallExpression) parseExpr("'FOO.CC'[1:][:2]");
+ e = (FuncallExpression) parseExpression("'FOO.CC'[1:][:2]");
assertEquals("$slice", e.getFunction().getName());
assertThat(e.getArguments()).hasSize(2);
}
@@ -241,12 +271,12 @@
@Test
public void testErrorRecovery() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
String expr = "f(1, [x for foo foo foo], 3)";
- FuncallExpression e = (FuncallExpression) parseExpr(expr);
+ FuncallExpression e = (FuncallExpression) parseExpression(expr);
- syntaxEvents.assertContainsEvent("syntax error at 'foo'");
+ assertContainsEvent("syntax error at 'foo'");
// Test that the actual parameters are: (1, $error$, 3):
@@ -273,7 +303,7 @@
@Test
public void testDoesntGetStuck() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
// Make sure the parser does not get stuck when trying
// to parse an expression containing a syntax error.
@@ -281,18 +311,18 @@
// parser keeps filling up the error log.
// We need to make sure that we will always advance
// in the token stream.
- parseExpr("f(1, ], 3)");
- parseExpr("f(1, ), 3)");
- parseExpr("[ ) for v in 3)");
+ parseExpression("f(1, ], 3)");
+ parseExpression("f(1, ), 3)");
+ parseExpression("[ ) for v in 3)");
- syntaxEvents.assertContainsEvent(""); // "" matches any;
+ assertContainsEvent(""); // "" matches any;
// i.e. there were some events
}
@Test
public void testSecondaryLocation() {
String expr = "f(1 % 2)";
- FuncallExpression call = (FuncallExpression) parseExpr(expr);
+ FuncallExpression call = (FuncallExpression) parseExpression(expr);
Argument.Passed arg = call.getArguments().get(0);
assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
}
@@ -300,39 +330,37 @@
@Test
public void testPrimaryLocation() {
String expr = "f(1 + 2)";
- FuncallExpression call = (FuncallExpression) parseExpr(expr);
+ FuncallExpression call = (FuncallExpression) parseExpression(expr);
Argument.Passed arg = call.getArguments().get(0);
assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
}
@Test
public void testAssignLocation() {
- String expr = "a = b;c = d\n";
- List<Statement> statements = parseFile(expr);
+ List<Statement> statements = parseFile("a = b;c = d\n");
Statement statement = statements.get(0);
assertEquals(5, statement.getLocation().getEndOffset());
}
@Test
public void testAssignKeyword() {
- syntaxEvents.setFailFast(false);
- parseExpr("with = 4");
- syntaxEvents.assertContainsEvent("keyword 'with' not supported");
- syntaxEvents.assertContainsEvent("syntax error at 'with': expected expression");
+ setFailFast(false);
+ parseExpression("with = 4");
+ assertContainsEvent("keyword 'with' not supported");
+ assertContainsEvent("syntax error at 'with': expected expression");
}
@Test
public void testTry() {
- syntaxEvents.setFailFast(false);
- parseExpr("try: 1 + 1");
- syntaxEvents.assertContainsEvent("'try' not supported, all exceptions are fatal");
- syntaxEvents.assertContainsEvent("syntax error at 'try': expected expression");
+ setFailFast(false);
+ parseExpression("try: 1 + 1");
+ assertContainsEvent("'try' not supported, all exceptions are fatal");
+ assertContainsEvent("syntax error at 'try': expected expression");
}
@Test
public void testTupleAssign() {
- String expr = "list[0] = 5; dict['key'] = value\n";
- List<Statement> statements = parseFile(expr);
+ List<Statement> statements = parseFile("list[0] = 5; dict['key'] = value\n");
assertThat(statements).hasSize(2);
assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
assertThat(statements.get(1)).isInstanceOf(AssignmentStatement.class);
@@ -340,8 +368,7 @@
@Test
public void testAssign() {
- String expr = "a, b = 5\n";
- List<Statement> statements = parseFile(expr);
+ List<Statement> statements = parseFile("a, b = 5\n");
assertThat(statements).hasSize(1);
assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
AssignmentStatement assign = (AssignmentStatement) statements.get(0);
@@ -350,10 +377,10 @@
@Test
public void testInvalidAssign() {
- syntaxEvents.setFailFast(false);
- parseExpr("1 + (b = c)");
- syntaxEvents.assertContainsEvent("syntax error");
- syntaxEvents.collector().clear();
+ setFailFast(false);
+ parseExpression("1 + (b = c)");
+ assertContainsEvent("syntax error");
+ clearEvents();
}
@Test
@@ -371,8 +398,7 @@
@Test
public void testFuncallLocation() {
- String expr = "a(b);c = d\n";
- List<Statement> statements = parseFile(expr);
+ List<Statement> statements = parseFile("a(b);c = d\n");
Statement statement = statements.get(0);
assertEquals(4, statement.getLocation().getEndOffset());
}
@@ -392,7 +418,7 @@
@Test
public void testListPositions() throws Exception {
String expr = "[0,f(1),2]";
- ListLiteral list = (ListLiteral) parseExpr(expr);
+ ListLiteral list = (ListLiteral) parseExpression(expr);
assertEquals("[0,f(1),2]", getText(expr, list));
assertEquals("0", getText(expr, getElem(list, 0)));
assertEquals("f(1)", getText(expr, getElem(list, 1)));
@@ -402,7 +428,7 @@
@Test
public void testDictPositions() throws Exception {
String expr = "{1:2,2:f(1),3:4}";
- DictionaryLiteral list = (DictionaryLiteral) parseExpr(expr);
+ DictionaryLiteral list = (DictionaryLiteral) parseExpression(expr);
assertEquals("{1:2,2:f(1),3:4}", getText(expr, list));
assertEquals("1:2", getText(expr, getElem(list, 0)));
assertEquals("2:f(1)", getText(expr, getElem(list, 1)));
@@ -412,7 +438,7 @@
@Test
public void testArgumentPositions() throws Exception {
String stmt = "f(0,g(1,2),2)";
- FuncallExpression f = (FuncallExpression) parseExpr(stmt);
+ FuncallExpression f = (FuncallExpression) parseExpression(stmt);
assertEquals(stmt, getText(stmt, f));
assertEquals("0", getText(stmt, getArg(f, 0)));
assertEquals("g(1,2)", getText(stmt, getArg(f, 1)));
@@ -421,7 +447,7 @@
@Test
public void testListLiterals1() throws Exception {
- ListLiteral list = (ListLiteral) parseExpr("[0,1,2]");
+ ListLiteral list = (ListLiteral) parseExpression("[0,1,2]");
assertFalse(list.isTuple());
assertThat(list.getElements()).hasSize(3);
assertFalse(list.isTuple());
@@ -432,7 +458,7 @@
@Test
public void testTupleLiterals2() throws Exception {
- ListLiteral tuple = (ListLiteral) parseExpr("(0,1,2)");
+ ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)");
assertTrue(tuple.isTuple());
assertThat(tuple.getElements()).hasSize(3);
assertTrue(tuple.isTuple());
@@ -443,7 +469,7 @@
@Test
public void testTupleWithoutParens() throws Exception {
- ListLiteral tuple = (ListLiteral) parseExpr("0, 1, 2");
+ ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2");
assertTrue(tuple.isTuple());
assertThat(tuple.getElements()).hasSize(3);
assertTrue(tuple.isTuple());
@@ -454,7 +480,7 @@
@Test
public void testTupleWithoutParensWithTrailingComma() throws Exception {
- ListLiteral tuple = (ListLiteral) parseExpr("0, 1, 2, 3,");
+ ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2, 3,");
assertTrue(tuple.isTuple());
assertThat(tuple.getElements()).hasSize(4);
assertTrue(tuple.isTuple());
@@ -465,14 +491,14 @@
@Test
public void testTupleLiterals3() throws Exception {
- ListLiteral emptyTuple = (ListLiteral) parseExpr("()");
+ ListLiteral emptyTuple = (ListLiteral) parseExpression("()");
assertTrue(emptyTuple.isTuple());
assertThat(emptyTuple.getElements()).isEmpty();
}
@Test
public void testTupleLiterals4() throws Exception {
- ListLiteral singletonTuple = (ListLiteral) parseExpr("(42,)");
+ ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)");
assertTrue(singletonTuple.isTuple());
assertThat(singletonTuple.getElements()).hasSize(1);
assertEquals(42, getIntElem(singletonTuple, 0));
@@ -480,20 +506,20 @@
@Test
public void testTupleLiterals5() throws Exception {
- IntegerLiteral intLit = (IntegerLiteral) parseExpr("(42)"); // not a tuple!
+ IntegerLiteral intLit = (IntegerLiteral) parseExpression("(42)"); // not a tuple!
assertEquals(42, (int) intLit.getValue());
}
@Test
public void testListLiterals6() throws Exception {
- ListLiteral emptyList = (ListLiteral) parseExpr("[]");
+ ListLiteral emptyList = (ListLiteral) parseExpression("[]");
assertFalse(emptyList.isTuple());
assertThat(emptyList.getElements()).isEmpty();
}
@Test
public void testListLiterals7() throws Exception {
- ListLiteral singletonList = (ListLiteral) parseExpr("[42,]");
+ ListLiteral singletonList = (ListLiteral) parseExpression("[42,]");
assertFalse(singletonList.isTuple());
assertThat(singletonList.getElements()).hasSize(1);
assertEquals(42, getIntElem(singletonList, 0));
@@ -501,7 +527,7 @@
@Test
public void testListLiterals8() throws Exception {
- ListLiteral singletonList = (ListLiteral) parseExpr("[42]"); // a singleton
+ ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton
assertFalse(singletonList.isTuple());
assertThat(singletonList.getElements()).hasSize(1);
assertEquals(42, getIntElem(singletonList, 0));
@@ -510,7 +536,7 @@
@Test
public void testDictionaryLiterals() throws Exception {
DictionaryLiteral dictionaryList =
- (DictionaryLiteral) parseExpr("{1:42}"); // a singleton dictionary
+ (DictionaryLiteral) parseExpression("{1:42}"); // a singleton dictionary
assertThat(dictionaryList.getEntries()).hasSize(1);
DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
assertEquals(1, getIntElem(tuple, true));
@@ -520,14 +546,14 @@
@Test
public void testDictionaryLiterals1() throws Exception {
DictionaryLiteral dictionaryList =
- (DictionaryLiteral) parseExpr("{}"); // an empty dictionary
+ (DictionaryLiteral) parseExpression("{}"); // an empty dictionary
assertThat(dictionaryList.getEntries()).isEmpty();
}
@Test
public void testDictionaryLiterals2() throws Exception {
DictionaryLiteral dictionaryList =
- (DictionaryLiteral) parseExpr("{1:42,}"); // a singleton dictionary
+ (DictionaryLiteral) parseExpression("{1:42,}"); // a singleton dictionary
assertThat(dictionaryList.getEntries()).hasSize(1);
DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
assertEquals(1, getIntElem(tuple, true));
@@ -536,7 +562,7 @@
@Test
public void testDictionaryLiterals3() throws Exception {
- DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpr("{1:42,2:43,3:44}");
+ DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpression("{1:42,2:43,3:44}");
assertThat(dictionaryList.getEntries()).hasSize(3);
for (int i = 0; i < 3; i++) {
DictionaryEntryLiteral tuple = getElem(dictionaryList, i);
@@ -548,57 +574,57 @@
@Test
public void testListLiterals9() throws Exception {
ListLiteral singletonList =
- (ListLiteral) parseExpr("[ abi + opt_level + \'/include\' ]");
+ (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]");
assertFalse(singletonList.isTuple());
assertThat(singletonList.getElements()).hasSize(1);
}
@Test
public void testListComprehensionSyntax() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
- parseExpr("[x for");
- syntaxEvents.assertContainsEvent("syntax error at 'newline'");
- syntaxEvents.collector().clear();
+ parseExpression("[x for");
+ assertContainsEvent("syntax error at 'newline'");
+ clearEvents();
- parseExpr("[x for x");
- syntaxEvents.assertContainsEvent("syntax error at 'newline'");
- syntaxEvents.collector().clear();
+ parseExpression("[x for x");
+ assertContainsEvent("syntax error at 'newline'");
+ clearEvents();
- parseExpr("[x for x in");
- syntaxEvents.assertContainsEvent("syntax error at 'newline'");
- syntaxEvents.collector().clear();
+ parseExpression("[x for x in");
+ assertContainsEvent("syntax error at 'newline'");
+ clearEvents();
- parseExpr("[x for x in []");
- syntaxEvents.assertContainsEvent("syntax error at 'newline'");
- syntaxEvents.collector().clear();
+ parseExpression("[x for x in []");
+ assertContainsEvent("syntax error at 'newline'");
+ clearEvents();
- parseExpr("[x for x for y in ['a']]");
- syntaxEvents.assertContainsEvent("syntax error at 'for'");
- syntaxEvents.collector().clear();
+ parseExpression("[x for x for y in ['a']]");
+ assertContainsEvent("syntax error at 'for'");
+ clearEvents();
}
@Test
public void testListComprehension() throws Exception {
ListComprehension list =
- (ListComprehension) parseExpr(
+ (ListComprehension) parseExpression(
"['foo/%s.java' % x "
+ "for x in []]");
assertThat(list.getLists()).hasSize(1);
- list = (ListComprehension) parseExpr("['foo/%s.java' % x "
+ list = (ListComprehension) parseExpression("['foo/%s.java' % x "
+ "for x in ['bar', 'wiz', 'quux']]");
assertThat(list.getLists()).hasSize(1);
- list = (ListComprehension) parseExpr("['%s/%s.java' % (x, y) "
+ list = (ListComprehension) parseExpression("['%s/%s.java' % (x, y) "
+ "for x in ['foo', 'bar'] for y in ['baz', 'wiz', 'quux']]");
assertThat(list.getLists()).hasSize(2);
}
@Test
public void testParserRecovery() throws Exception {
- syntaxEvents.setFailFast(false);
- List<Statement> statements = parseFileForSkylark(Joiner.on("\n").join(
+ setFailFast(false);
+ List<Statement> statements = parseFileForSkylark(
"def foo():",
" a = 2 not 4", // parse error
" b = [3, 4]",
@@ -608,107 +634,103 @@
"def bar():",
" a = [3, 4]",
" b = 2 + + 5", // parse error
- ""));
+ "");
- assertThat(syntaxEvents.collector()).hasSize(3);
- syntaxEvents.assertContainsEvent("syntax error at 'not': expected newline");
- syntaxEvents.assertContainsEvent("syntax error at 'ada': expected newline");
- syntaxEvents.assertContainsEvent("syntax error at '+': expected expression");
+ assertThat(getEventCollector()).hasSize(3);
+ assertContainsEvent("syntax error at 'not': expected newline");
+ assertContainsEvent("syntax error at 'ada': expected newline");
+ assertContainsEvent("syntax error at '+': expected expression");
assertThat(statements).hasSize(3);
}
@Test
public void testParserContainsErrorsIfSyntaxException() throws Exception {
- syntaxEvents.setFailFast(false);
- parseExpr("'foo' %%");
- syntaxEvents.assertContainsEvent("syntax error at '%'");
+ setFailFast(false);
+ parseExpression("'foo' %%");
+ assertContainsEvent("syntax error at '%'");
}
@Test
public void testParserDoesNotContainErrorsIfSuccess() throws Exception {
- parseExpr("'foo'");
+ parseExpression("'foo'");
}
@Test
public void testParserContainsErrors() throws Exception {
- syntaxEvents.setFailFast(false);
- parseStmt("+");
- syntaxEvents.assertContainsEvent("syntax error at '+'");
+ setFailFast(false);
+ parseStatement("+");
+ assertContainsEvent("syntax error at '+'");
}
@Test
public void testSemicolonAndNewline() throws Exception {
List<Statement> stmts = parseFile(
- "foo='bar'; foo(bar)" + '\n'
- + "" + '\n'
- + "foo='bar'; foo(bar)"
- );
+ "foo='bar'; foo(bar)",
+ "",
+ "foo='bar'; foo(bar)");
assertThat(stmts).hasSize(4);
}
@Test
public void testSemicolonAndNewline2() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
List<Statement> stmts = parseFile(
- "foo='foo' error(bar)" + '\n'
- + "" + '\n'
- );
- syntaxEvents.assertContainsEvent("syntax error at 'error'");
+ "foo='foo' error(bar)",
+ "",
+ "");
+ assertContainsEvent("syntax error at 'error'");
assertThat(stmts).hasSize(1);
}
@Test
public void testExprAsStatement() throws Exception {
List<Statement> stmts = parseFile(
- "li = []\n"
- + "li.append('a.c')\n"
- + "\"\"\" string comment \"\"\"\n"
- + "foo(bar)"
- );
+ "li = []",
+ "li.append('a.c')",
+ "\"\"\" string comment \"\"\"",
+ "foo(bar)");
assertThat(stmts).hasSize(4);
}
@Test
public void testParseBuildFileWithSingeRule() throws Exception {
List<Statement> stmts = parseFile(
- "genrule(name = 'foo'," + '\n'
- + " srcs = ['input.csv']," + '\n'
- + " outs = [ 'result.txt'," + '\n'
- + " 'result.log']," + '\n'
- + " cmd = 'touch result.txt result.log')" + '\n'
- );
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'result.txt',",
+ " 'result.log'],",
+ " cmd = 'touch result.txt result.log')",
+ "");
assertThat(stmts).hasSize(1);
}
@Test
public void testParseBuildFileWithMultipleRules() throws Exception {
List<Statement> stmts = parseFile(
- "genrule(name = 'foo'," + '\n'
- + " srcs = ['input.csv']," + '\n'
- + " outs = [ 'result.txt'," + '\n'
- + " 'result.log']," + '\n'
- + " cmd = 'touch result.txt result.log')" + '\n'
- + "" + '\n'
- + "genrule(name = 'bar'," + '\n'
- + " srcs = ['input.csv']," + '\n'
- + " outs = [ 'graph.svg']," + '\n'
- + " cmd = 'touch graph.svg')" + '\n'
- );
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'result.txt',",
+ " 'result.log'],",
+ " cmd = 'touch result.txt result.log')",
+ "",
+ "genrule(name = 'bar',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'graph.svg'],",
+ " cmd = 'touch graph.svg')");
assertThat(stmts).hasSize(2);
}
@Test
public void testParseBuildFileWithComments() throws Exception {
Parser.ParseResult result = parseFileWithComments(
- "# Test BUILD file" + '\n'
- + "# with multi-line comment" + '\n'
- + "" + '\n'
- + "genrule(name = 'foo'," + '\n'
- + " srcs = ['input.csv']," + '\n'
- + " outs = [ 'result.txt'," + '\n'
- + " 'result.log']," + '\n'
- + " cmd = 'touch result.txt result.log')" + '\n'
- );
+ "# Test BUILD file",
+ "# with multi-line comment",
+ "",
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'result.txt',",
+ " 'result.log'],",
+ " cmd = 'touch result.txt result.log')");
assertThat(result.statements).hasSize(1);
assertThat(result.comments).hasSize(2);
}
@@ -716,22 +738,21 @@
@Test
public void testParseBuildFileWithManyComments() throws Exception {
Parser.ParseResult result = parseFileWithComments(
- "# 1" + '\n'
- + "# 2" + '\n'
- + "" + '\n'
- + "# 4 " + '\n'
- + "# 5" + '\n'
- + "#" + '\n' // 6 - find empty comment for syntax highlighting
- + "# 7 " + '\n'
- + "# 8" + '\n'
- + "genrule(name = 'foo'," + '\n'
- + " srcs = ['input.csv']," + '\n'
- + " # 11" + '\n'
- + " outs = [ 'result.txt'," + '\n'
- + " 'result.log'], # 13" + '\n'
- + " cmd = 'touch result.txt result.log')" + '\n'
- + "# 15" + '\n'
- );
+ "# 1",
+ "# 2",
+ "",
+ "# 4 ",
+ "# 5",
+ "#", // 6 - find empty comment for syntax highlighting
+ "# 7 ",
+ "# 8",
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " # 11",
+ " outs = [ 'result.txt',",
+ " 'result.log'], # 13",
+ " cmd = 'touch result.txt result.log')",
+ "# 15");
assertThat(result.statements).hasSize(1); // Single genrule
StringBuilder commentLines = new StringBuilder();
for (Comment comment : result.comments) {
@@ -752,27 +773,27 @@
@Test
public void testMissingComma() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
// Regression test.
// Note: missing comma after name='foo'
parseFile("genrule(name = 'foo'\n"
+ " srcs = ['in'])");
- syntaxEvents.assertContainsEvent("syntax error at 'srcs'");
+ assertContainsEvent("syntax error at 'srcs'");
}
@Test
public void testDoubleSemicolon() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
// Regression test.
parseFile("x = 1; ; x = 2;");
- syntaxEvents.assertContainsEvent("syntax error at ';'");
+ assertContainsEvent("syntax error at ';'");
}
@Test
public void testFunctionDefinitionErrorRecovery() throws Exception {
// Parser skips over entire function definitions, and reports a meaningful
// error.
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
List<Statement> stmts = parseFile(
"x = 1;\n"
+ "def foo(x, y, **z):\n"
@@ -788,14 +809,14 @@
public void testFunctionDefinitionIgnoredEvenWithUnsupportedKeyword() throws Exception {
// Parser skips over entire function definitions without reporting error,
// when parsePython is set to true.
- List<Statement> stmts = parseFile(
- "x = 1;\n"
- + "def foo(x, y, **z):\n"
- + " try:\n"
- + " x = 2\n"
- + " with: pass\n"
- + " return 2\n"
- + "x = 3", true /* parsePython */);
+ List<Statement> stmts = parseFileWithPython(
+ "x = 1;",
+ "def foo(x, y, **z):",
+ " try:",
+ " x = 2",
+ " with: pass",
+ " return 2",
+ "x = 3");
assertThat(stmts).hasSize(2);
}
@@ -803,45 +824,43 @@
public void testFunctionDefinitionIgnored() throws Exception {
// Parser skips over entire function definitions without reporting error,
// when parsePython is set to true.
- List<Statement> stmts = parseFile(
- "x = 1;\n"
- + "def foo(x, y, **z):\n"
- + " # a comment\n"
- + " if true:"
- + " x = 2\n"
- + " foo(bar)\n"
- + " return z\n"
- + "x = 3", true /* parsePython */);
+ List<Statement> stmts = parseFileWithPython(
+ "x = 1;",
+ "def foo(x, y, **z):",
+ " # a comment",
+ " if true:",
+ " x = 2",
+ " foo(bar)",
+ " return z",
+ "x = 3");
assertThat(stmts).hasSize(2);
- stmts = parseFile(
- "x = 1;\n"
- + "def foo(x, y, **z): return x\n"
- + "x = 3", true /* parsePython */);
+ stmts = parseFileWithPython(
+ "x = 1;",
+ "def foo(x, y, **z): return x",
+ "x = 3");
assertThat(stmts).hasSize(2);
}
@Test
public void testMissingBlock() throws Exception {
- syntaxEvents.setFailFast(false);
- List<Statement> stmts = parseFile(
- "x = 1;\n"
- + "def foo(x):\n"
- + "x = 2;\n",
- true /* parsePython */);
+ setFailFast(false);
+ List<Statement> stmts = parseFileWithPython(
+ "x = 1;",
+ "def foo(x):",
+ "x = 2;\n");
assertThat(stmts).hasSize(2);
- syntaxEvents.assertContainsEvent("expected an indented block");
+ assertContainsEvent("expected an indented block");
}
@Test
public void testInvalidDef() throws Exception {
- syntaxEvents.setFailFast(false);
- parseFile(
- "x = 1;\n"
- + "def foo(x)\n"
- + "x = 2;\n",
- true /* parsePython */);
- syntaxEvents.assertContainsEvent("syntax error at 'EOF'");
+ setFailFast(false);
+ parseFileWithPython(
+ "x = 1;",
+ "def foo(x)",
+ "x = 2;\n");
+ assertContainsEvent("syntax error at 'EOF'");
}
@Test
@@ -855,14 +874,13 @@
@Test
public void testSkipIfBlock() throws Exception {
// Skip over 'if' blocks, when parsePython is set
- List<Statement> stmts = parseFile(
- "x = 1;\n"
- + "if x == 1:\n"
- + " foo(x)\n"
- + "else:\n"
- + " bar(x)\n"
- + "x = 3;\n",
- true /* parsePython */);
+ List<Statement> stmts = parseFileWithPython(
+ "x = 1;",
+ "if x == 1:",
+ " foo(x)",
+ "else:",
+ " bar(x)",
+ "x = 3;\n");
assertThat(stmts).hasSize(2);
}
@@ -875,8 +893,8 @@
@Test
public void testForPass() throws Exception {
List<Statement> statements = parseFileForSkylark(
- "def foo():\n"
- + " pass\n");
+ "def foo():",
+ " pass\n");
assertThat(statements).hasSize(1);
FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
@@ -886,15 +904,14 @@
@Test
public void testSkipIfBlockFail() throws Exception {
// Do not parse 'if' blocks, when parsePython is not set
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
List<Statement> stmts = parseFile(
- "x = 1;\n"
- + "if x == 1:\n"
- + " x = 2\n"
- + "x = 3;\n",
- false /* no parsePython */);
+ "x = 1;",
+ "if x == 1:",
+ " x = 2",
+ "x = 3;\n");
assertThat(stmts).hasSize(2);
- syntaxEvents.assertContainsEvent("This Python-style construct is not supported");
+ assertContainsEvent("This Python-style construct is not supported");
}
@Test
@@ -911,37 +928,37 @@
@Test
public void testForLoopBadSyntax() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("[1 for (a, b, c in var]\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testForLoopBadSyntax2() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("[1 for in var]\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testFunCallBadSyntax() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("f(1,\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testFunCallBadSyntax2() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("f(1, 5, ,)\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testLoadNoSymbol() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("load('/foo/bar/file')\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
@@ -973,68 +990,68 @@
@Test
public void testLoadSyntaxError() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("load(non_quoted, 'a')\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testLoadSyntaxError2() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("load('non_quoted', a)\n");
- syntaxEvents.assertContainsEvent("syntax error");
+ assertContainsEvent("syntax error");
}
@Test
public void testLoadNotAtTopLevel() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("if 1: load(8)\n");
- syntaxEvents.assertContainsEvent("function 'load' does not exist");
+ assertContainsEvent("function 'load' does not exist");
}
@Test
public void testParseErrorNotComparison() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("2 < not 3");
- syntaxEvents.assertContainsEvent("syntax error at 'not'");
+ assertContainsEvent("syntax error at 'not'");
}
@Test
public void testNotWithArithmeticOperatorsBadSyntax() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("0 + not 0");
- syntaxEvents.assertContainsEvent("syntax error at 'not'");
+ assertContainsEvent("syntax error at 'not'");
}
@Test
public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n");
- syntaxEvents.assertContainsEvent(
+ assertContainsEvent(
"a mandatory positional parameter must not follow an optional parameter");
}
@Test
public void testKwargBeforePositionalArg() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark(
- "def func(a, b): return a + b\n"
- + "func(**{'b': 1}, 'a')");
- syntaxEvents.assertContainsEvent("unexpected tokens after kwarg");
+ "def func(a, b): return a + b",
+ "func(**{'b': 1}, 'a')");
+ assertContainsEvent("unexpected tokens after kwarg");
}
@Test
public void testDuplicateKwarg() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark(
- "def func(a, b): return a + b\n"
- + "func(**{'b': 1}, **{'a': 2})");
- syntaxEvents.assertContainsEvent("unexpected tokens after kwarg");
+ "def func(a, b): return a + b",
+ "func(**{'b': 1}, **{'a': 2})");
+ assertContainsEvent("unexpected tokens after kwarg");
}
@Test
public void testUnnamedStar() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
List<Statement> statements = parseFileForSkylark(
"def func(a, b1=2, b2=3, *, c1, d=4, c2): return a + b1 + b2 + c1 + c2 + d\n");
assertThat(statements).hasSize(1);
@@ -1053,34 +1070,35 @@
@Test
public void testTopLevelForFails() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("for i in []: 0\n");
- syntaxEvents.assertContainsEvent(
+ assertContainsEvent(
"for loops are not allowed on top-level. Put it into a function");
}
@Test
public void testNestedFunctionFails() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark(
- "def func(a):\n"
- + " def bar(): return 0\n"
- + " return bar()\n");
- syntaxEvents.assertContainsEvent(
+ "def func(a):",
+ " def bar(): return 0",
+ " return bar()",
+ "");
+ assertContainsEvent(
"nested functions are not allowed. Move the function to top-level");
}
@Test
public void testIncludeFailureSkylark() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFileForSkylark("include('//foo:bar')");
- syntaxEvents.assertContainsEvent("function 'include' does not exist");
+ assertContainsEvent("function 'include' does not exist");
}
@Test
public void testIncludeFailure() throws Exception {
- syntaxEvents.setFailFast(false);
+ setFailFast(false);
parseFile("include('nonexistent')\n");
- syntaxEvents.assertContainsEvent("Invalid label 'nonexistent'");
+ assertContainsEvent("Invalid label 'nonexistent'");
}
}
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 b55f428..e50a4b0 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
@@ -29,9 +29,6 @@
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.events.EventKind;
-import com.google.devtools.build.lib.events.util.EventCollectionApparatus;
-import com.google.devtools.build.lib.packages.MethodLibrary;
import com.google.devtools.build.lib.rules.SkylarkModules;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
@@ -39,14 +36,18 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.List;
-
/**
* Evaluation tests with Skylark Environment.
*/
@RunWith(JUnit4.class)
public class SkylarkEvaluationTest extends EvaluationTest {
+ // Restoring defaults overridden by EvaluationTest
+ @Override
+ public EvaluationContext newEvaluationContext() {
+ return SkylarkModules.newEvaluationContext(getEventHandler());
+ }
+
@SkylarkModule(name = "Mock", doc = "")
static class Mock {
@SkylarkCallable(doc = "")
@@ -143,95 +144,72 @@
public void method(String i) {}
}
- private static final ImmutableMap<String, SkylarkType> MOCK_TYPES = ImmutableMap
- .<String, SkylarkType>of("mock", SkylarkType.UNKNOWN, "Mock", SkylarkType.UNKNOWN);
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- syntaxEvents = new EventCollectionApparatus(EventKind.ALL_EVENTS);
- env = new SkylarkEnvironment(syntaxEvents.collector());
- MethodLibrary.setupMethodEnvironment(env);
- }
-
- @Override
- public Environment singletonEnv(String id, Object value) {
- SkylarkEnvironment env = new SkylarkEnvironment(syntaxEvents.collector());
- env.update(id, value);
- return env;
- }
-
@Test
public void testSimpleIf() throws Exception {
- exec(parseFileForSkylark(
- "def foo():\n"
- + " a = 0\n"
- + " x = 0\n"
- + " if x: a = 5\n"
- + " return a\n"
- + "a = foo()"), env);
- assertEquals(0, env.lookup("a"));
+ eval("def foo():",
+ " a = 0",
+ " x = 0",
+ " if x: a = 5",
+ " return a",
+ "a = foo()");
+ assertEquals(0, lookup("a"));
}
@Test
public void testIfPass() throws Exception {
- exec(parseFileForSkylark(
- "def foo():\n"
- + " a = 1\n"
- + " x = True\n"
- + " if x: pass\n"
- + " return a\n"
- + "a = foo()"), env);
- assertEquals(1, env.lookup("a"));
+ eval("def foo():",
+ " a = 1",
+ " x = True",
+ " if x: pass",
+ " return a",
+ "a = foo()");
+ assertEquals(1, lookup("a"));
}
@Test
public void testNestedIf() throws Exception {
- executeNestedIf(0, 0, env);
- assertEquals(0, env.lookup("x"));
+ executeNestedIf(0, 0);
+ assertEquals(0, lookup("x"));
- executeNestedIf(1, 0, env);
- assertEquals(3, env.lookup("x"));
+ setUp();
+ executeNestedIf(1, 0);
+ assertEquals(3, lookup("x"));
- executeNestedIf(1, 1, env);
- assertEquals(5, env.lookup("x"));
+ setUp();
+ executeNestedIf(1, 1);
+ assertEquals(5, lookup("x"));
}
- private void executeNestedIf(int x, int y, Environment env) throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " x = " + x + "\n"
- + " y = " + y + "\n"
- + " a = 0\n"
- + " b = 0\n"
- + " if x:\n"
- + " if y:\n"
- + " a = 2\n"
- + " b = 3\n"
- + " return a + b\n"
- + "x = foo()");
- exec(input, env);
+ private void executeNestedIf(int x, int y) throws Exception {
+ String fun = String.format("foo%s%s", x, y);
+ eval("def " + fun + "():",
+ " x = " + x,
+ " y = " + y,
+ " a = 0",
+ " b = 0",
+ " if x:",
+ " if y:",
+ " a = 2",
+ " b = 3",
+ " return a + b",
+ "x = " + fun + "()");
}
@Test
public void testIfElse() throws Exception {
- executeIfElse("something", 2);
- executeIfElse("", 3);
+ executeIfElse("foo", "something", 2);
+ executeIfElse("bar", "", 3);
}
- private void executeIfElse(String y, int expectedA) throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " y = '" + y + "'\n"
- + " x = 5\n"
- + " if x:\n"
- + " if y: a = 2\n"
- + " else: a = 3\n"
- + " return a\n"
- + "a = foo()");
-
- exec(input, env);
- assertEquals(expectedA, env.lookup("a"));
+ private void executeIfElse(String fun, String y, int expected) throws Exception {
+ eval("def " + fun + "():",
+ " y = '" + y + "'",
+ " x = 5",
+ " if x:",
+ " if y: a = 2",
+ " else: a = 3",
+ " return a\n");
+ assertEquals(expected, eval(fun + "()"));
}
@Test
@@ -250,261 +228,216 @@
}
private void execIfElifElse(int x, int y, int v) throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " x = " + x + "\n"
- + " y = " + y + "\n"
- + " if x:\n"
- + " return 1\n"
- + " elif y:\n"
- + " return 2\n"
- + " else:\n"
- + " return 3\n"
- + "v = foo()");
- exec(input, env);
- assertEquals(v, env.lookup("v"));
+ eval("def foo():",
+ " x = " + x + "",
+ " y = " + y + "",
+ " if x:",
+ " return 1",
+ " elif y:",
+ " return 2",
+ " else:",
+ " return 3",
+ "v = foo()");
+ assertEquals(v, lookup("v"));
}
@Test
public void testForOnList() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " s = ''\n"
- + " for i in ['hello', ' ', 'world']:\n"
- + " s = s + i\n"
- + " return s\n"
- + "s = foo()\n");
-
- exec(input, env);
- assertEquals("hello world", env.lookup("s"));
+ eval("def foo():",
+ " s = ''",
+ " for i in ['hello', ' ', 'world']:",
+ " s = s + i",
+ " return s",
+ "s = foo()\n");
+ assertEquals("hello world", lookup("s"));
}
@SuppressWarnings("unchecked")
@Test
public void testForOnString() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " s = []\n"
- + " for i in 'abc':\n"
- + " s = s + [i]\n"
- + " return s\n"
- + "s = foo()\n");
-
- exec(input, env);
- assertThat((Iterable<Object>) env.lookup("s")).containsExactly("a", "b", "c").inOrder();
+ eval("def foo():",
+ " s = []",
+ " for i in 'abc':",
+ " s = s + [i]",
+ " return s",
+ "s = foo()\n");
+ assertThat((Iterable<Object>) lookup("s")).containsExactly("a", "b", "c").inOrder();
}
@Test
public void testForAssignmentList() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " d = ['a', 'b', 'c']\n"
- + " s = ''\n"
- + " for i in d:\n"
- + " s = s + i\n"
- + " d = ['d', 'e', 'f']\n" // check that we use the old list
- + " return s\n"
- + "s = foo()\n");
-
- exec(input, env);
- assertEquals("abc", env.lookup("s"));
+ eval("def foo():",
+ " d = ['a', 'b', 'c']",
+ " s = ''",
+ " for i in d:",
+ " s = s + i",
+ " d = ['d', 'e', 'f']", // check that we use the old list
+ " return s",
+ "s = foo()\n");
+ assertEquals("abc", lookup("s"));
}
@Test
public void testForAssignmentDict() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def func():\n"
- + " d = {'a' : 1, 'b' : 2, 'c' : 3}\n"
- + " s = ''\n"
- + " for i in d:\n"
- + " s = s + i\n"
- + " d = {'d' : 1, 'e' : 2, 'f' : 3}\n"
- + " return s\n"
- + "s = func()");
-
- exec(input, env);
- assertEquals("abc", env.lookup("s"));
+ eval("def func():",
+ " d = {'a' : 1, 'b' : 2, 'c' : 3}",
+ " s = ''",
+ " for i in d:",
+ " s = s + i",
+ " d = {'d' : 1, 'e' : 2, 'f' : 3}",
+ " return s",
+ "s = func()");
+ assertEquals("abc", lookup("s"));
}
@Test
public void testForNotIterable() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark(
- "def func():\n"
- + " for i in mock.value_of('1'): a = i\n"
- + "func()\n", MOCK_TYPES);
- checkEvalError(input, env, "type 'int' is not an iterable");
+ update("mock", new Mock());
+ checkEvalError("type 'int' is not iterable",
+ "def func():",
+ " for i in mock.value_of('1'): a = i",
+ "func()\n");
+
}
@Test
public void testForOnDictionary() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " d = {1: 'a', 2: 'b', 3: 'c'}\n"
- + " s = ''\n"
- + " for i in d: s = s + d[i]\n"
- + " return s\n"
- + "s = foo()");
-
- exec(input, env);
- assertEquals("abc", env.lookup("s"));
+ eval("def foo():",
+ " d = {1: 'a', 2: 'b', 3: 'c'}",
+ " s = ''",
+ " for i in d: s = s + d[i]",
+ " return s",
+ "s = foo()");
+ assertEquals("abc", lookup("s"));
}
@Test
public void testForLoopReuseVariable() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " s = ''\n"
- + " for i in ['a', 'b']:\n"
- + " for i in ['c', 'd']: s = s + i\n"
- + " return s\n"
- + "s = foo()");
-
- exec(input, env);
- assertEquals("cdcd", env.lookup("s"));
+ eval("def foo():",
+ " s = ''",
+ " for i in ['a', 'b']:",
+ " for i in ['c', 'd']: s = s + i",
+ " return s",
+ "s = foo()");
+ assertEquals("cdcd", lookup("s"));
}
@Test
public void testForLoopMultipleVariables() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " s = ''\n"
- + " for [i, j] in [[1, 2], [3, 4]]:\n"
- + " s = s + str(i) + str(j) + '.'\n"
- + " return s\n"
- + "s = foo()");
-
- exec(input, env);
- assertEquals("12.34.", env.lookup("s"));
+ eval("def foo():",
+ " s = ''",
+ " for [i, j] in [[1, 2], [3, 4]]:",
+ " s = s + str(i) + str(j) + '.'",
+ " return s",
+ "s = foo()");
+ assertEquals("12.34.", lookup("s"));
}
@Test
public void testNoneAssignment() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo(x=None):\n"
- + " x = 1\n"
- + " x = None\n"
- + " return 2\n"
- + "s = foo()");
-
- exec(input, env);
- assertEquals(2, env.lookup("s"));
+ eval("def foo(x=None):",
+ " x = 1",
+ " x = None",
+ " return 2",
+ "s = foo()");
+ assertEquals(2, lookup("s"));
}
@Test
public void testJavaCalls() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark(
- "b = mock.is_empty('a')", MOCK_TYPES);
- exec(input, env);
- assertEquals(Boolean.FALSE, env.lookup("b"));
+ update("mock", new Mock());
+ eval("b = mock.is_empty('a')");
+ assertEquals(Boolean.FALSE, lookup("b"));
}
@Test
public void testJavaCallsOnSubClass() throws Exception {
- env.update("mock", new MockSubClass());
- List<Statement> input = parseFileForSkylark(
- "b = mock.is_empty('a')", MOCK_TYPES);
- exec(input, env);
- assertEquals(Boolean.FALSE, env.lookup("b"));
+ update("mock", new MockSubClass());
+ eval("b = mock.is_empty('a')");
+ assertEquals(Boolean.FALSE, lookup("b"));
}
@Test
public void testJavaCallsOnInterface() throws Exception {
- env.update("mock", new MockSubClass());
- List<Statement> input = parseFileForSkylark(
- "b = mock.is_empty_interface('a')", MOCK_TYPES);
- exec(input, env);
- assertEquals(Boolean.FALSE, env.lookup("b"));
+ update("mock", new MockSubClass());
+ eval("b = mock.is_empty_interface('a')");
+ assertEquals(Boolean.FALSE, lookup("b"));
}
@Test
public void testJavaCallsNotSkylarkCallable() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark("mock.value()", MOCK_TYPES);
- checkEvalError(input, env, "No matching method found for value() in Mock");
+ update("mock", new Mock());
+ checkEvalError("No matching method found for value() in Mock", "mock.value()");
}
@Test
public void testJavaCallsNoMethod() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "s = 3.bad()");
- checkEvalError(input, env, "No matching method found for bad() in int");
+ checkEvalError("No matching method found for bad() in int", "s = 3.bad()");
}
@Test
public void testJavaCallsNoMethodErrorMsg() throws Exception {
- List<Statement> input = parseFileForSkylark(
+ checkEvalError("No matching method found for bad(string, string, string) in int",
"s = 3.bad('a', 'b', 'c')");
- checkEvalError(input, env,
- "No matching method found for bad(string, string, string) in int");
}
@Test
public void testJavaCallsMultipleMethod() throws Exception {
- env.update("mock", new MockMultipleMethodClass());
- List<Statement> input = parseFileForSkylark(
- "s = mock.method('string')", MOCK_TYPES);
- checkEvalError(input, env,
- "Multiple matching methods for method(string) in MockMultipleMethodClass");
+ update("mock", new MockMultipleMethodClass());
+ checkEvalError("Multiple matching methods for method(string) in MockMultipleMethodClass",
+ "s = mock.method('string')");
}
@Test
public void testJavaCallWithKwargs() throws Exception {
- List<Statement> input = parseFileForSkylark("comp = 3.compare_to(x = 4)");
- checkEvalError(input, env, "Keyword arguments are not allowed when calling a java method"
- + "\nwhile calling method 'compare_to' on object 3 of type int");
+ checkEvalError("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)");
}
@Test
public void testNoJavaCallsWithoutSkylark() throws Exception {
- List<Statement> input = parseFileForSkylark("s = 3.to_string()\n");
- checkEvalError(input, env, "No matching method found for to_string() in int");
+ checkEvalError("No matching method found for to_string() in int", "s = 3.to_string()\n");
}
@Test
public void testNoJavaCallsIfClassNotAnnotated() throws Exception {
- env.update("mock", new MockSubClass());
- List<Statement> input = parseFileForSkylark(
- "b = mock.is_empty_class_not_annotated('a')", MOCK_TYPES);
- checkEvalError(input, env,
- "No matching method found for is_empty_class_not_annotated(string) in MockSubClass");
+ update("mock", new MockSubClass());
+ checkEvalError(
+ "No matching method found for is_empty_class_not_annotated(string) in MockSubClass",
+ "b = mock.is_empty_class_not_annotated('a')");
}
@Test
public void testStructAccess() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark(
- "v = mock.struct_field", MOCK_TYPES);
- exec(input, env);
- assertEquals("a", env.lookup("v"));
+ update("mock", new Mock());
+ eval("v = mock.struct_field");
+ assertEquals("a", lookup("v"));
}
@Test
public void testStructAccessAsFuncall() throws Exception {
- env.update("mock", new Mock());
- checkEvalError(parseFileForSkylark("v = mock.struct_field()", MOCK_TYPES), env,
- "No matching method found for struct_field() in Mock");
+ update("mock", new Mock());
+ checkEvalError("No matching method found for struct_field() in Mock",
+ "v = mock.struct_field()");
}
@Test
public void testStructAccessOfMethod() throws Exception {
- env.update("mock", new Mock());
- checkEvalError(parseFileForSkylark(
- "v = mock.function", MOCK_TYPES), env, "Object of type 'Mock' has no field 'function'");
+ update("mock", new Mock());
+ checkEvalError("Object of type 'Mock' has no field 'function'",
+ "v = mock.function");
}
@Test
public void testConditionalStructConcatenation() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- exec(parseFileForSkylark(
- "def func():\n"
- + " x = struct(a = 1, b = 2)\n"
- + " if True:\n"
- + " x += struct(c = 1, d = 2)\n"
- + " return x\n"
- + "x = func()\n"), env);
- SkylarkClassObject x = (SkylarkClassObject) env.lookup("x");
+ eval("def func():",
+ " x = struct(a = 1, b = 2)",
+ " if True:",
+ " x += struct(c = 1, d = 2)",
+ " return x",
+ "x = func()\n");
+ SkylarkClassObject x = (SkylarkClassObject) lookup("x");
assertEquals(1, x.getValue("a"));
assertEquals(2, x.getValue("b"));
assertEquals(1, x.getValue("c"));
@@ -513,24 +446,24 @@
@Test
public void testJavaFunctionReturnsMutableObject() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark("mock.return_mutable()", MOCK_TYPES);
- checkEvalError(input, env, "Method 'return_mutable' returns a mutable object (type of Mock)");
+ update("mock", new Mock());
+ checkEvalError("Method 'return_mutable' returns a mutable object (type of Mock)",
+ "mock.return_mutable()");
}
@Test
public void testJavaFunctionReturnsNullFails() throws Exception {
- env.update("mock", new Mock());
- List<Statement> input = parseFileForSkylark("mock.nullfunc_failing('abc', 1)", MOCK_TYPES);
- checkEvalError(input, env, "Method invocation returned None,"
- + " please contact Skylark developers: nullfunc_failing(\"abc\", 1)");
+ update("mock", new Mock());
+ checkEvalError("Method invocation returned None,"
+ + " please contact Skylark developers: nullfunc_failing(\"abc\", 1)",
+ "mock.nullfunc_failing('abc', 1)");
}
@Test
public void testClassObjectAccess() throws Exception {
- env.update("mock", new MockClassObject());
- exec(parseFileForSkylark("v = mock.field", MOCK_TYPES), env);
- assertEquals("a", env.lookup("v"));
+ update("mock", new MockClassObject());
+ eval("v = mock.field");
+ assertEquals("a", lookup("v"));
}
@Test
@@ -542,132 +475,116 @@
@Test
public void testClassObjectCannotAccessNestedSet() throws Exception {
- env.update("mock", new MockClassObject());
- checkEvalError(parseFileForSkylark("v = mock.nset", MOCK_TYPES), env,
- "Type is not allowed in Skylark: EmptyNestedSet");
+ update("mock", new MockClassObject());
+ checkEvalError("Type is not allowed in Skylark: EmptyNestedSet", "v = mock.nset");
}
@Test
public void testJavaFunctionReturnsNone() throws Exception {
- env.update("mock", new Mock());
- exec(parseFileForSkylark("v = mock.nullfunc_working()", MOCK_TYPES), env);
- assertSame(Environment.NONE, env.lookup("v"));
+ update("mock", new Mock());
+ eval("v = mock.nullfunc_working()");
+ assertSame(Environment.NONE, lookup("v"));
}
@Test
public void testVoidJavaFunctionReturnsNone() throws Exception {
- env.update("mock", new Mock());
- exec(parseFileForSkylark("v = mock.voidfunc()", MOCK_TYPES), env);
- assertSame(Environment.NONE, env.lookup("v"));
+ update("mock", new Mock());
+ eval("v = mock.voidfunc()");
+ assertSame(Environment.NONE, lookup("v"));
}
@Test
public void testAugmentedAssignment() throws Exception {
- exec(parseFileForSkylark(
- "def f1(x):\n"
- + " x += 1\n"
- + " return x\n"
- + "\n"
- + "foo = f1(41)\n"), env);
- assertEquals(42, env.lookup("foo"));
+ eval("def f1(x):",
+ " x += 1",
+ " return x",
+ "",
+ "foo = f1(41)\n");
+ assertEquals(42, lookup("foo"));
}
@Test
public void testStaticDirectJavaCall() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "val = Mock.value_of('8')", MOCK_TYPES);
-
- env.update("Mock", Mock.class);
- exec(input, env);
- assertEquals(8, env.lookup("val"));
+ update("Mock", Mock.class);
+ eval("val = Mock.value_of('8')");
+ assertEquals(8, lookup("val"));
}
@Test
public void testStaticDirectJavaCallMethodIsNonStatic() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "val = Mock.is_empty('a')", MOCK_TYPES);
-
- env.update("Mock", Mock.class);
- checkEvalError(input, env, "Method 'is_empty' is not static");
+ update("Mock", Mock.class);
+ checkEvalError("Method 'is_empty' is not static", "val = Mock.is_empty('a')");
}
@Test
public void testDictComprehensions_IterationOrder() throws Exception {
- List<Statement> input = parseFileForSkylark(
- "def foo():\n"
- + " d = {x : x for x in ['c', 'a', 'b']}\n"
- + " s = ''\n"
- + " for a in d:\n"
- + " s += a\n"
- + " return s\n"
- + "s = foo()");
- exec(input, env);
- assertEquals("abc", env.lookup("s"));
+ eval("def foo():",
+ " d = {x : x for x in ['c', 'a', 'b']}",
+ " s = ''",
+ " for a in d:",
+ " s += a",
+ " return s",
+ "s = foo()");
+ assertEquals("abc", lookup("s"));
}
@Test
public void testStructCreation() throws Exception {
- exec(parseFileForSkylark("x = struct(a = 1, b = 2)"), env);
- assertThat(env.lookup("x")).isInstanceOf(ClassObject.class);
+ eval("x = struct(a = 1, b = 2)");
+ assertThat(lookup("x")).isInstanceOf(ClassObject.class);
}
@Test
public void testStructFields() throws Exception {
- exec(parseFileForSkylark("x = struct(a = 1, b = 2)"), env);
- ClassObject x = (ClassObject) env.lookup("x");
+ eval("x = struct(a = 1, b = 2)");
+ ClassObject x = (ClassObject) lookup("x");
assertEquals(1, x.getValue("a"));
assertEquals(2, x.getValue("b"));
}
@Test
public void testStructAccessingFieldsFromSkylark() throws Exception {
- exec(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "x1 = x.a\n"
- + "x2 = x.b\n"), env);
- assertEquals(1, env.lookup("x1"));
- assertEquals(2, env.lookup("x2"));
+ eval("x = struct(a = 1, b = 2)",
+ "x1 = x.a",
+ "x2 = x.b\n");
+ assertEquals(1, lookup("x1"));
+ assertEquals(2, lookup("x2"));
}
@Test
public void testStructAccessingUnknownField() throws Exception {
- checkEvalError(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "y = x.c\n"), env, "Object of type 'struct' has no field 'c'");
+ checkEvalError("Object of type 'struct' has no field 'c'",
+ "x = struct(a = 1, b = 2)",
+ "y = x.c\n");
}
@Test
public void testStructAccessingFieldsWithArgs() throws Exception {
- checkEvalError(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "x1 = x.a(1)\n"),
- env, "No matching method found for a(int) in struct");
+ checkEvalError("No matching method found for a(int) in struct",
+ "x = struct(a = 1, b = 2)",
+ "x1 = x.a(1)\n");
}
@Test
public void testStructPosArgs() throws Exception {
- checkEvalError(parseFileForSkylark(
- "x = struct(1, b = 2)\n"),
- env, "struct only supports keyword arguments");
+ checkEvalError("struct only supports keyword arguments", "x = struct(1, b = 2)\n");
}
@Test
public void testStructConcatenationFieldNames() throws Exception {
- exec(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "y = struct(c = 1, d = 2)\n"
- + "z = x + y\n"), env);
- SkylarkClassObject z = (SkylarkClassObject) env.lookup("z");
+ eval("x = struct(a = 1, b = 2)",
+ "y = struct(c = 1, d = 2)",
+ "z = x + y\n");
+ SkylarkClassObject z = (SkylarkClassObject) lookup("z");
assertEquals(ImmutableSet.of("a", "b", "c", "d"), z.getKeys());
}
@Test
public void testStructConcatenationFieldValues() throws Exception {
- exec(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "y = struct(c = 1, d = 2)\n"
- + "z = x + y\n"), env);
- SkylarkClassObject z = (SkylarkClassObject) env.lookup("z");
+ eval("x = struct(a = 1, b = 2)",
+ "y = struct(c = 1, d = 2)",
+ "z = x + y\n");
+ SkylarkClassObject z = (SkylarkClassObject) lookup("z");
assertEquals(1, z.getValue("a"));
assertEquals(2, z.getValue("b"));
assertEquals(1, z.getValue("c"));
@@ -676,216 +593,201 @@
@Test
public void testStructConcatenationCommonFields() throws Exception {
- checkEvalError(parseFileForSkylark(
- "x = struct(a = 1, b = 2)\n"
- + "y = struct(c = 1, a = 2)\n"
- + "z = x + y\n"), env, "Cannot concat structs with common field(s): a");
+ checkEvalError("Cannot concat structs with common field(s): a",
+ "x = struct(a = 1, b = 2)",
+ "y = struct(c = 1, a = 2)",
+ "z = x + y\n");
}
@Test
public void testDotExpressionOnNonStructObject() throws Exception {
- checkEvalError(parseFileForSkylark(
- "x = 'a'.field"), env, "Object of type 'string' has no field 'field'");
+ checkEvalError("Object of type 'string' has no field 'field'", "x = 'a'.field");
}
@Test
public void testPlusEqualsOnDict() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- exec(parseFileForSkylark(
- "def func():\n"
- + " d = {'a' : 1}\n"
- + " d += {'b' : 2}\n"
- + " return d\n"
- + "d = func()"), env);
- assertEquals(ImmutableMap.of("a", 1, "b", 2), env.lookup("d"));
+ eval("def func():",
+ " d = {'a' : 1}",
+ " d += {'b' : 2}",
+ " return d",
+ "d = func()");
+ assertEquals(ImmutableMap.of("a", 1, "b", 2), lookup("d"));
}
@Test
public void testDictAssignmentAsLValue() throws Exception {
- exec(parseFileForSkylark(
- "def func():\n"
- + " d = {'a' : 1}\n"
- + " d['b'] = 2\n"
- + " return d\n"
- + "d = func()"), env);
- assertEquals(ImmutableMap.of("a", 1, "b", 2), env.lookup("d"));
+ eval("def func():",
+ " d = {'a' : 1}",
+ " d['b'] = 2",
+ " return d",
+ "d = func()");
+ assertEquals(ImmutableMap.of("a", 1, "b", 2), lookup("d"));
}
@Test
public void testDictAssignmentAsLValueNoSideEffects() throws Exception {
- MethodLibrary.setupMethodEnvironment(env);
- exec(parseFileForSkylark(
- "def func(d):\n"
- + " d['b'] = 2\n"
- + "d = {'a' : 1}\n"
- + "func(d)"), env);
- assertEquals(ImmutableMap.of("a", 1), env.lookup("d"));
+ eval("def func(d):",
+ " d['b'] = 2",
+ "d = {'a' : 1}",
+ "func(d)");
+ assertEquals(ImmutableMap.of("a", 1), lookup("d"));
}
@Test
public void testListIndexAsLValueAsLValue() throws Exception {
- checkEvalError(parseFileForSkylark(
- "def id(l):\n"
- + " return l\n"
- + "def func():\n"
- + " l = id([1])\n"
- + " l[0] = 2\n"
- + " return l\n"
- + "l = func()"), env, "unsupported operand type(s) for +: 'list' and 'dict'");
+ checkEvalError("unsupported operand type(s) for +: 'list' and 'dict'",
+ "def id(l):",
+ " return l",
+ "def func():",
+ " l = id([1])",
+ " l[0] = 2",
+ " return l",
+ "l = func()");
}
@Test
public void testTopLevelDict() throws Exception {
- exec(parseFileForSkylark(
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " v = 'b'"), env);
- assertEquals("a", env.lookup("v"));
+ eval("if 1:",
+ " v = 'a'",
+ "else:",
+ " v = 'b'");
+ assertEquals("a", lookup("v"));
}
@Test
public void testUserFunctionKeywordArgs() throws Exception {
- exec(parseFileForSkylark(
- "def foo(a, b, c):\n"
- + " return a + b + c\n"
- + "s = foo(1, c=2, b=3)"), env);
- assertEquals(6, env.lookup("s"));
+ eval("def foo(a, b, c):",
+ " return a + b + c",
+ "s = foo(1, c=2, b=3)");
+ assertEquals(6, lookup("s"));
}
@Test
public void testNoneTrueFalseInSkylark() throws Exception {
- exec(parseFileForSkylark(
- "a = None\n"
- + "b = True\n"
- + "c = False"), env);
- assertSame(Environment.NONE, env.lookup("a"));
- assertTrue((Boolean) env.lookup("b"));
- assertFalse((Boolean) env.lookup("c"));
+ eval("a = None",
+ "b = True",
+ "c = False");
+ assertSame(Environment.NONE, lookup("a"));
+ assertTrue((Boolean) lookup("b"));
+ assertFalse((Boolean) lookup("c"));
}
@Test
public void testHasattr() throws Exception {
- exec(parseFileForSkylark(
- "s = struct(a=1)\n"
- + "x = hasattr(s, 'a')\n"
- + "y = hasattr(s, 'b')\n"), env);
- assertTrue((Boolean) env.lookup("x"));
- assertFalse((Boolean) env.lookup("y"));
+ eval("s = struct(a=1)",
+ "x = hasattr(s, 'a')",
+ "y = hasattr(s, 'b')\n");
+ assertTrue((Boolean) lookup("x"));
+ assertFalse((Boolean) lookup("y"));
}
@Test
public void testHasattrMethods() throws Exception {
- env.update("mock", new Mock());
- ValidationEnvironment validEnv = SkylarkModules.getValidationEnvironment();
- validEnv.update("mock", SkylarkType.of(Mock.class), null);
- exec(Parser.parseFileForSkylark(createLexer(
- "a = hasattr(mock, 'struct_field')\n"
- + "b = hasattr(mock, 'function')\n"
- + "c = hasattr(mock, 'is_empty')\n"
- + "d = hasattr('str', 'replace')\n"
- + "e = hasattr(mock, 'other')\n"),
- syntaxEvents.reporter(), null, validEnv).statements, env);
- assertTrue((Boolean) env.lookup("a"));
- assertTrue((Boolean) env.lookup("b"));
- assertTrue((Boolean) env.lookup("c"));
- assertTrue((Boolean) env.lookup("d"));
- assertFalse((Boolean) env.lookup("e"));
+ update("mock", new Mock());
+ eval("a = hasattr(mock, 'struct_field')",
+ "b = hasattr(mock, 'function')",
+ "c = hasattr(mock, 'is_empty')",
+ "d = hasattr('str', 'replace')",
+ "e = hasattr(mock, 'other')\n");
+ assertTrue((Boolean) lookup("a"));
+ assertTrue((Boolean) lookup("b"));
+ assertTrue((Boolean) lookup("c"));
+ assertTrue((Boolean) lookup("d"));
+ assertFalse((Boolean) lookup("e"));
}
@Test
public void testGetattr() throws Exception {
- exec(parseFileForSkylark(
- "s = struct(a='val')\n"
- + "x = getattr(s, 'a')\n"
- + "y = getattr(s, 'b', 'def')\n"
- + "z = getattr(s, 'b', default = 'def')\n"
- + "w = getattr(s, 'a', default='ignored')"), env);
- assertEquals("val", env.lookup("x"));
- assertEquals("def", env.lookup("y"));
- assertEquals("def", env.lookup("z"));
- assertEquals("val", env.lookup("w"));
+ eval("s = struct(a='val')",
+ "x = getattr(s, 'a')",
+ "y = getattr(s, 'b', 'def')",
+ "z = getattr(s, 'b', default = 'def')",
+ "w = getattr(s, 'a', default='ignored')");
+ assertEquals("val", lookup("x"));
+ assertEquals("def", lookup("y"));
+ assertEquals("def", lookup("z"));
+ assertEquals("val", lookup("w"));
}
@Test
public void testGetattrNoAttr() throws Exception {
- checkEvalError(parseFileForSkylark(
- "s = struct(a='val')\n"
- + "getattr(s, 'b')"),
- env, "Object of type 'struct' has no field 'b'");
+ checkEvalError("Object of type 'struct' has no field 'b'",
+ "s = struct(a='val')",
+ "getattr(s, 'b')");
}
@SuppressWarnings("unchecked")
@Test
public void testListAnTupleConcatenationDoesNotWorkInSkylark() throws Exception {
- checkEvalError(parseFileForSkylark("[1, 2] + (3, 4)"), env,
- "cannot concatenate lists and tuples");
+ checkEvalError("cannot concatenate lists and tuples", "[1, 2] + (3, 4)");
}
@Test
public void testCannotCreateMixedListInSkylark() throws Exception {
- env.update("mock", new Mock());
- checkEvalError(parseFileForSkylark("[mock.string(), 1, 2]", MOCK_TYPES), env,
- "Incompatible types in list: found a int but the previous elements were strings");
+ update("mock", new Mock());
+ checkEvalError(
+ "Incompatible types in list: found a int but the previous elements were strings",
+ "[mock.string(), 1, 2]");
}
@Test
public void testCannotConcatListInSkylarkWithDifferentGenericTypes() throws Exception {
- env.update("mock", new Mock());
- checkEvalError(parseFileForSkylark("mock.string_list() + [1, 2]", MOCK_TYPES), env,
- "cannot concatenate list of string with list of int");
+ update("mock", new Mock());
+ checkEvalError("cannot concatenate list of string with list of int",
+ "mock.string_list() + [1, 2]");
}
@SuppressWarnings("unchecked")
@Test
public void testConcatEmptyListWithNonEmptyWorks() throws Exception {
- exec(parseFileForSkylark("l = [] + ['a', 'b']", MOCK_TYPES), env);
- assertThat((Iterable<Object>) env.lookup("l")).containsExactly("a", "b").inOrder();
+ eval("l = [] + ['a', 'b']");
+ assertThat((Iterable<Object>) lookup("l")).containsExactly("a", "b").inOrder();
}
@Test
public void testFormatStringWithTuple() throws Exception {
- exec(parseFileForSkylark("v = '%s%s' % ('a', 1)"), env);
- assertEquals("a1", env.lookup("v"));
+ eval("v = '%s%s' % ('a', 1)");
+ assertEquals("a1", lookup("v"));
}
@Test
public void testSingletonTuple() throws Exception {
- exec(parseFileForSkylark("v = (1,)"), env);
- assertEquals("(1,)", env.lookup("v").toString());
+ eval("v = (1,)");
+ assertEquals("(1,)", lookup("v").toString());
}
@SuppressWarnings("unchecked")
@Test
public void testDirFindsClassObjectFields() throws Exception {
- env.update("mock", new MockClassObject());
- exec(parseFileForSkylark("v = dir(mock)", MOCK_TYPES), env);
- assertThat((Iterable<String>) env.lookup("v")).containsExactly("field", "nset").inOrder();
+ update("mock", new MockClassObject());
+ eval("v = dir(mock)");
+ assertThat((Iterable<String>) lookup("v")).containsExactly("field", "nset").inOrder();
}
@SuppressWarnings("unchecked")
@Test
public void testDirFindsJavaObjectStructFieldsAndMethods() throws Exception {
- env.update("mock", new Mock());
- exec(parseFileForSkylark("v = dir(mock)", MOCK_TYPES), env);
- assertThat((Iterable<String>) env.lookup("v")).containsExactly("function", "is_empty",
+ update("mock", new Mock());
+ eval("v = dir(mock)");
+ assertThat((Iterable<String>) lookup("v")).containsExactly("function", "is_empty",
"nullfunc_failing", "nullfunc_working", "return_mutable", "string", "string_list",
"struct_field", "value_of", "voidfunc").inOrder();
}
@Test
public void testPrint() throws Exception {
- exec(parseFileForSkylark("print('hello')"), env);
- syntaxEvents.assertContainsEvent("hello");
- exec(parseFileForSkylark("print('a', 'b')"), env);
- syntaxEvents.assertContainsEvent("a b");
- exec(parseFileForSkylark("print('a', 'b', sep='x')"), env);
- syntaxEvents.assertContainsEvent("axb");
+ setFailFast(false);
+ eval("print('hello')");
+ assertContainsEvent("hello");
+ eval("print('a', 'b')");
+ assertContainsEvent("a b");
+ eval("print('a', 'b', sep='x')");
+ assertContainsEvent("axb");
}
@Test
public void testPrintBadKwargs() throws Exception {
- checkEvalError("print(end='x', other='y')", "unexpected keywords: '[end, other]'");
+ checkEvalError("unexpected keywords: '[end, other]'", "print(end='x', other='y')");
}
@Test
@@ -906,7 +808,6 @@
// list
Object x = eval("[1,2] + [3,4]");
assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
- assertFalse(((SkylarkList) x).isTuple());
// tuple
x = eval("(1,2)");
@@ -918,43 +819,76 @@
assertTrue(((SkylarkList) x).isTuple());
}
- @SuppressWarnings("unchecked")
- @Override
- @Test
- public void testListExprs() throws Exception {
- assertThat((Iterable<Object>) eval("[1, 2, 3]")).containsExactly(1, 2, 3).inOrder();
- assertThat((Iterable<Object>) eval("(1, 2, 3)")).containsExactly(1, 2, 3).inOrder();
- }
-
@Override
@Test
public void testListConcatenation() throws Exception {}
+ @Test
+ public void testInFail() throws Exception {
+ checkEvalError("in operator only works on strings if the left operand is also a string",
+ "1 in '123'");
+ checkEvalError("ERROR 1:1: operand 'in' only works on "
+ + "strings, dictionaries, lists, sets or tuples, not on a(n) int",
+ "'a' in 1");
+ }
+
@Override
@Test
- public void testKeywordArgs() {}
+ public void testCompareStringInt() throws Exception {
+ checkEvalError("ERROR 1:1: bad comparison: int is incompatible with string at 1:8", "'a' >= 1");
+ }
+
+ @Override
+ @Test
+ public void testNotComparable() throws Exception {
+ checkEvalError("ERROR 1:1: list of ints is not comparable", "[1, 2] < [1, 3]");
+ }
+
+ @Override
+ @Test
+ public void testListComprehensionsMultipleVariablesFail() throws Exception {
+ checkEvalError("lvalue has length 3, but rvalue has has length 2",
+ "def foo (): return [x + y for x, y, z in [(1, 2), (3, 4)]]",
+ "foo()");
+
+ checkEvalError("type 'int' is not a collection",
+ "def bar (): return [x + y for x, y in (1, 2)]",
+ "bar()");
+
+ checkEvalError("lvalue has length 3, but rvalue has has length 2",
+ "[x + y for x, y, z in [(1, 2), (3, 4)]]");
+
+ // can't reuse the same local variable twice(!)
+ checkEvalError("ERROR 1:1: Variable x is read only", "[x + y for x, y in (1, 2)]");
+
+ checkEvalError("type 'int' is not a collection", "[x2 + y2 for x2, y2 in (1, 2)]");
+ }
+
+ @Override
+ @Test
+ public void testNotCallInt() throws Exception {
+ eval("sum = 123456");
+ assertEquals(123456, lookup("sum"));
+ checkEvalError("ERROR 1:1: sum is not a function but a(n) int", "sum(1, 2, 3, 4, 5, 6)");
+ assertEquals(123456, eval("sum"));
+ }
@Test
public void testConditionalExpressionAtToplevel() throws Exception {
- exec(parseFileForSkylark("x = 1 if 2 else 3"), env);
- assertEquals(1, env.lookup("x"));
+ eval("x = 1 if 2 else 3");
+ assertEquals(1, lookup("x"));
}
@Test
public void testConditionalExpressionInFunction() throws Exception {
- exec(parseFileForSkylark(
- "def foo(a, b, c):\n"
- + " return a+b if c else a-b\n"
- + "x = foo(23, 5, 0)"), env);
- assertEquals(18, env.lookup("x"));
+ eval("def foo(a, b, c): return a+b if c else a-b\n");
+ assertEquals(18, eval("foo(23, 5, 0)"));
}
@Test
public void testBadConditionalExpressionInFunction() throws Exception {
- syntaxEvents.setFailFast(false);
- parseFileForSkylark("def foo(a): return [] if a else 0\n");
- syntaxEvents.assertContainsEvent(
- "bad else case: int is incompatible with list at /some/file.txt:1:33");
- syntaxEvents.collector().clear();
+ setFailFast(false);
+ parseFile("def foo(a): return [] if a else 0\n");
+ assertContainsEvent("bad else case: int is incompatible with list at 1:33");
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkListTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkListTest.java
index a5fd942..81029b1 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkListTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkListTest.java
@@ -15,14 +15,9 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.MethodLibrary;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -33,7 +28,7 @@
* Tests for SkylarkList.
*/
@RunWith(JUnit4.class)
-public class SkylarkListTest extends AbstractEvaluationTestCase {
+public class SkylarkListTest extends EvaluationTestCase {
@Immutable
private static final class CustomIterable implements Iterable<Object> {
@@ -48,112 +43,92 @@
private static final SkylarkList list =
SkylarkList.lazyList(new CustomIterable(), Integer.class);
- private static final ImmutableMap<String, SkylarkType> extraObjects =
- ImmutableMap.of("lazy", SkylarkType.of(SkylarkList.class, Integer.class));
- private Environment env;
-
- @Before
- public void setUp() throws Exception {
-
- env = new SkylarkEnvironment(syntaxEvents.collector());
- env.update("lazy", list);
- MethodLibrary.setupMethodEnvironment(env);
+ @Override
+ public EvaluationContext newEvaluationContext() throws Exception {
+ return super.newEvaluationContext().update("lazy", list);
}
@Test
public void testLazyListIndex() throws Exception {
- checkError("Iterator requested", "a = lazy[0]");
+ checkEvalError("Iterator requested", "a = lazy[0]");
}
@Test
public void testLazyListSize() throws Exception {
- checkError("Iterator requested", "a = len(lazy)");
+ checkEvalError("Iterator requested", "a = len(lazy)");
}
@Test
public void testLazyListEmpty() throws Exception {
- checkError("Iterator requested", "if lazy:\n a = 1");
+ checkEvalError("Iterator requested", "if lazy:\n a = 1");
}
@Test
public void testLazyListConcat() throws Exception {
- exec("v = [1, 2] + lazy");
- assertThat(env.lookup("v")).isInstanceOf(SkylarkList.class);
+ eval("v = [1, 2] + lazy");
+ assertThat(lookup("v")).isInstanceOf(SkylarkList.class);
}
@Test
public void testConcatListIndex() throws Exception {
- exec("l = [1, 2] + [3, 4]",
+ eval("l = [1, 2] + [3, 4]",
"e0 = l[0]",
"e1 = l[1]",
"e2 = l[2]",
"e3 = l[3]");
- assertEquals(1, env.lookup("e0"));
- assertEquals(2, env.lookup("e1"));
- assertEquals(3, env.lookup("e2"));
- assertEquals(4, env.lookup("e3"));
+ assertEquals(1, lookup("e0"));
+ assertEquals(2, lookup("e1"));
+ assertEquals(3, lookup("e2"));
+ assertEquals(4, lookup("e3"));
}
@Test
public void testConcatListHierarchicalIndex() throws Exception {
- exec("l = [1] + (([2] + [3, 4]) + [5])",
+ eval("l = [1] + (([2] + [3, 4]) + [5])",
"e0 = l[0]",
"e1 = l[1]",
"e2 = l[2]",
"e3 = l[3]",
"e4 = l[4]");
- assertEquals(1, env.lookup("e0"));
- assertEquals(2, env.lookup("e1"));
- assertEquals(3, env.lookup("e2"));
- assertEquals(4, env.lookup("e3"));
- assertEquals(5, env.lookup("e4"));
+ assertEquals(1, lookup("e0"));
+ assertEquals(2, lookup("e1"));
+ assertEquals(3, lookup("e2"));
+ assertEquals(4, lookup("e3"));
+ assertEquals(5, lookup("e4"));
}
@Test
public void testConcatListSize() throws Exception {
- exec("l = [1, 2] + [3, 4]",
+ eval("l = [1, 2] + [3, 4]",
"s = len(l)");
- assertEquals(4, env.lookup("s"));
+ assertEquals(4, lookup("s"));
}
@Test
public void testConcatListToString() throws Exception {
- exec("l = [1, 2] + [3, 4]",
+ eval("l = [1, 2] + [3, 4]",
"s = str(l)");
- assertEquals("[1, 2, 3, 4]", env.lookup("s"));
+ assertEquals("[1, 2, 3, 4]", lookup("s"));
}
@Test
public void testConcatListNotEmpty() throws Exception {
- exec("l = [1, 2] + [3, 4]",
+ eval("l = [1, 2] + [3, 4]",
"if l:",
" v = 1",
"else:",
" v = 0");
- assertEquals(1, env.lookup("v"));
+ assertEquals(1, lookup("v"));
}
@Test
public void testConcatListEmpty() throws Exception {
- exec("l = [] + []",
+ eval("l = [] + []",
"if l:",
" v = 1",
"else:",
" v = 0");
- assertEquals(0, env.lookup("v"));
- }
-
- private void exec(String... input) throws Exception {
- exec(parseFileForSkylark(Joiner.on("\n").join(input), extraObjects), env);
- }
-
- private void checkError(String msg, String... input) throws Exception {
- try {
- exec(input);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage(msg);
- }
+ assertEquals(0, lookup("v"));
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
index 1c895d9..08123ac 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
@@ -15,15 +15,10 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.collect.nestedset.Order;
-import com.google.devtools.build.lib.packages.MethodLibrary;
-import com.google.devtools.build.lib.syntax.Environment.NoSuchVariableException;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -32,38 +27,29 @@
* Tests for SkylarkNestedSet.
*/
@RunWith(JUnit4.class)
-public class SkylarkNestedSetTest extends AbstractEvaluationTestCase {
-
- private Environment env;
-
- @Before
- public void setUp() throws Exception {
-
- env = new SkylarkEnvironment(syntaxEvents.collector());
- MethodLibrary.setupMethodEnvironment(env);
- }
+public class SkylarkNestedSetTest extends EvaluationTestCase {
@Test
public void testNsetBuilder() throws Exception {
- exec("n = set(order='stable')");
- assertThat(env.lookup("n")).isInstanceOf(SkylarkNestedSet.class);
+ eval("n = set(order='stable')");
+ assertThat(lookup("n")).isInstanceOf(SkylarkNestedSet.class);
}
@Test
public void testNsetOrder() throws Exception {
- exec("n = set(['a', 'b'], order='compile')");
+ eval("n = set(['a', 'b'], order='compile')");
assertEquals(Order.COMPILE_ORDER, get("n").getSet(String.class).getOrder());
}
@Test
public void testEmptyNsetGenericType() throws Exception {
- exec("n = set()");
+ eval("n = set()");
assertEquals(SkylarkType.TOP, get("n").getContentType());
}
@Test
public void testFunctionReturnsNset() throws Exception {
- exec("def func():",
+ eval("def func():",
" n = set()",
" n += ['a']",
" return n",
@@ -73,7 +59,7 @@
@Test
public void testNsetTwoReferences() throws Exception {
- exec("def func():",
+ eval("def func():",
" n1 = set()",
" n1 += ['a']",
" n2 = n1",
@@ -85,7 +71,7 @@
@Test
public void testNsetNestedItem() throws Exception {
- exec("def func():",
+ eval("def func():",
" n1 = set()",
" n2 = set()",
" n1 += ['a']",
@@ -98,13 +84,13 @@
@Test
public void testNsetNestedItemBadOrder() throws Exception {
- checkError("LINK_ORDER != COMPILE_ORDER",
+ checkEvalError("LINK_ORDER != COMPILE_ORDER",
"set(['a', 'b'], order='compile') + set(['c', 'd'], order='link')");
}
@Test
public void testNsetItemList() throws Exception {
- exec("def func():",
+ eval("def func():",
" n = set()",
" n += ['a', 'b']",
" return n",
@@ -114,7 +100,7 @@
@Test
public void testNsetFuncParamNoSideEffects() throws Exception {
- exec("def func1(n):",
+ eval("def func1(n):",
" n += ['b']",
"def func2():",
" n = set()",
@@ -127,7 +113,7 @@
@Test
public void testNsetTransitiveOrdering() throws Exception {
- exec("def func():",
+ eval("def func():",
" na = set(['a'], order='compile')",
" nb = set(['b'], order='compile')",
" nc = set(['c'], order='compile') + na",
@@ -139,7 +125,7 @@
@Test
public void testNsetOrdering() throws Exception {
- exec("def func():",
+ eval("def func():",
" na = set()",
" na += [4]",
" na += [2, 4]",
@@ -152,51 +138,35 @@
@Test
public void testNsetBadOrder() throws Exception {
- checkError("Invalid order: non_existing",
- "set(order='non_existing')");
+ checkEvalError("Invalid order: non_existing", "set(order='non_existing')");
}
@Test
public void testNsetBadRightOperand() throws Exception {
- checkError("cannot add 'string'-s to nested sets",
- "l = ['a']\n",
- "set() + l[0]");
+ checkEvalError("cannot add 'string'-s to nested sets", "l = ['a']\n" + "set() + l[0]");
}
@Test
public void testNsetBadCompositeItem() throws Exception {
- checkError("nested set item is composite (type of struct)",
- "set([struct(a='a')])");
+ checkEvalError("nested set item is composite (type of struct)", "set([struct(a='a')])");
}
@Test
public void testNsetToString() throws Exception {
- exec("s = set() + [2, 4, 6] + [3, 4, 5]",
+ eval("s = set() + [2, 4, 6] + [3, 4, 5]",
"x = str(s)");
- assertEquals("set([2, 4, 6, 3, 5])", env.lookup("x"));
+ assertEquals("set([2, 4, 6, 3, 5])", lookup("x"));
}
@Test
public void testNsetToStringWithOrder() throws Exception {
- exec("s = set(order = 'link') + [2, 4, 6] + [3, 4, 5]",
+ eval("s = set(order = 'link') + [2, 4, 6] + [3, 4, 5]",
"x = str(s)");
- assertEquals("set([2, 4, 6, 3, 5], order = \"link\")", env.lookup("x"));
+ assertEquals("set([2, 4, 6, 3, 5], order = \"link\")", lookup("x"));
}
- private void exec(String... input) throws Exception {
- exec(parseFileForSkylark(Joiner.on("\n").join(input)), env);
- }
-
- private SkylarkNestedSet get(String varname) throws NoSuchVariableException {
- return (SkylarkNestedSet) env.lookup(varname);
- }
-
- private void checkError(String msg, String... input) throws Exception {
- try {
- exec(input);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage(msg);
- }
+ @SuppressWarnings("unchecked")
+ private SkylarkNestedSet get(String varname) throws Exception {
+ return (SkylarkNestedSet) lookup(varname);
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java
index feb1c1b..0a60e91 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java
@@ -15,7 +15,6 @@
import static com.google.common.truth.Truth.assertThat;
-import com.google.common.base.Joiner;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget;
import com.google.devtools.build.lib.events.Event;
@@ -30,11 +29,11 @@
* Tests for the validation process of Skylark files.
*/
@RunWith(JUnit4.class)
-public class ValidationTests extends AbstractParserTestCase {
+public class ValidationTests extends EvaluationTestCase {
@Test
public void testIncompatibleLiteralTypesStringInt() {
- checkError("bad variable 'a': int is incompatible with string at /some/file.txt",
+ checkError("bad variable 'a': int is incompatible with string at 3:3",
"def foo():\n",
" a = '1'",
" a = 1");
@@ -42,7 +41,7 @@
@Test
public void testIncompatibleLiteralTypesDictString() {
- checkError("bad variable 'a': int is incompatible with dict of ints at /some/file.txt:3:3",
+ checkError("bad variable 'a': int is incompatible with dict of ints at 3:3",
"def foo():\n",
" a = {1 : 'x'}",
" a = 1");
@@ -50,7 +49,7 @@
@Test
public void testIncompatibleLiteralTypesInIf() {
- checkError("bad variable 'a': int is incompatible with string at /some/file.txt",
+ checkError("bad variable 'a': int is incompatible with string at 4:5",
"def foo():\n",
" if 1:",
" a = 'a'",
@@ -60,41 +59,41 @@
@Test
public void testAssignmentNotValidLValue() {
- checkError("can only assign to variables, not to ''a''", "'a' = 1");
+ checkError("can only assign to variables and tuples, not to ''a''", "'a' = 1");
}
@Test
public void testForNotIterable() throws Exception {
checkError("type 'int' is not iterable",
- "def func():\n"
- + " for i in 5: a = i\n");
+ "def func():\n",
+ " for i in 5: a = i\n");
}
@Test
public void testForIterableWithUknownArgument() throws Exception {
- parse("def func(x=None):\n"
- + " for i in x: a = i\n");
+ parse("def func(x=None):\n",
+ " for i in x: a = i\n");
}
@Test
public void testForNotIterableBinaryExpression() throws Exception {
checkError("type 'int' is not iterable",
- "def func():\n"
- + " for i in 1 + 1: a = i\n");
+ "def func():\n",
+ " for i in 1 + 1: a = i\n");
}
@Test
public void testOptionalArgument() throws Exception {
checkError("type 'int' is not iterable",
- "def func(x=5):\n"
- + " for i in x: a = i\n");
+ "def func(x=5):",
+ " for i in x: a = i\n");
}
@Test
public void testOptionalArgumentHasError() throws Exception {
checkError("unsupported operand type(s) for +: 'int' and 'string'",
- "def func(x=5+'a'):\n"
- + " return 0\n");
+ "def func(x=5+'a'):",
+ " return 0\n");
}
@Test
@@ -109,7 +108,7 @@
@Test
public void testTwoReturnTypes() throws Exception {
- checkError("bad return type of foo: string is incompatible with int at /some/file.txt:3:5",
+ checkError("bad return type of foo: string is incompatible with int at 3:5",
"def foo(x):",
" if x:",
" return 1",
@@ -128,7 +127,7 @@
@Test
public void testDynamicTypeCheck() throws Exception {
- checkError("bad variable 'a': string is incompatible with int at /some/file.txt:2:3",
+ checkError("bad variable 'a': string is incompatible with int at 2:3",
"def foo():",
" a = 1",
" a = '1'");
@@ -166,10 +165,10 @@
@Test
public void testLocalValidationEnvironmentsAreSeparated() throws Exception {
parse(
- "def func1():\n"
- + " a = 1\n"
- + "def func2():\n"
- + " a = 'abc'\n");
+ "def func1():",
+ " a = 1",
+ "def func2():",
+ " a = 'abc'\n");
}
@Test
@@ -213,108 +212,106 @@
@Test
public void testSkylarkGlobalVariablesAreReadonly() throws Exception {
checkError("Variable a is read only",
- "a = 1\n"
- + "a = 2");
+ "a = 1",
+ "a = 2");
}
@Test
public void testFunctionDefRecursion() throws Exception {
checkError("function 'func' does not exist",
- "def func():\n"
- + " func()\n");
+ "def func():",
+ " func()\n");
}
@Test
public void testMutualRecursion() throws Exception {
checkError("function 'bar' does not exist",
- "def foo(i):\n"
- + " bar(i)\n"
- + "def bar(i):\n"
- + " foo(i)\n"
- + "foo(4)");
+ "def foo(i):",
+ " bar(i)",
+ "def bar(i):",
+ " foo(i)",
+ "foo(4)");
}
@Test
public void testFunctionReturnValue() {
checkError("unsupported operand type(s) for +: 'int' and 'string'",
- "def foo(): return 1\n"
- + "a = foo() + 'a'\n");
+ "def foo(): return 1",
+ "a = foo() + 'a'\n");
}
@Test
public void testFunctionReturnValueInFunctionDef() {
checkError("unsupported operand type(s) for +: 'int' and 'string'",
- "def foo(): return 1\n"
- + "def bar(): a = foo() + 'a'\n");
+ "def foo(): return 1",
+ "def bar(): a = foo() + 'a'\n");
}
@Test
public void testFunctionDoesNotExistInFunctionDef() {
checkError("function 'foo' does not exist",
- "def bar(): a = foo() + 'a'\n"
- + "def foo(): return 1\n");
+ "def bar(): a = foo() + 'a'",
+ "def foo(): return 1\n");
}
@Test
public void testStructMembersAreImmutable() {
- checkError("can only assign to variables, not to 's.x'",
- "s = struct(x = 'a')\n"
- + "s.x = 'b'\n");
+ checkError("can only assign to variables and tuples, not to 's.x'",
+ "s = struct(x = 'a')",
+ "s.x = 'b'\n");
}
@Test
public void testStructDictMembersAreImmutable() {
- checkError("can only assign to variables, not to 's.x['b']'",
- "s = struct(x = {'a' : 1})\n"
- + "s.x['b'] = 2\n");
+ checkError("can only assign to variables and tuples, not to 's.x['b']'",
+ "s = struct(x = {'a' : 1})",
+ "s.x['b'] = 2\n");
}
@Test
public void testTupleAssign() throws Exception {
// TODO(bazel-team): fix our code so 'tuple' not 'list' gets printed.
checkError("unsupported operand type(s) for +: 'list' and 'dict of ints'",
- "d = (1, 2)\n"
- + "d[0] = 2\n");
+ "d = (1, 2)",
+ "d[0] = 2\n");
}
@Test
public void testAssignOnNonCollection() throws Exception {
checkError("unsupported operand type(s) for +: 'string' and 'dict of ints'",
- "d = 'abc'\n"
- + "d[0] = 2");
+ "d = 'abc'",
+ "d[0] = 2");
}
@Test
public void testNsetBadRightOperand() throws Exception {
- checkError("can only concatenate nested sets with other nested sets or list of items, "
- + "not 'string'", "set() + 'a'");
+ checkError("can only concatenate nested sets with other nested sets or list of items, ",
+ "not 'string'", "set() + 'a'");
}
@Test
public void testNsetBadItemType() throws Exception {
- checkError("bad nested set: set of ints is incompatible with set of strings "
- + "at /some/file.txt:1:1",
+ checkError("bad nested set: set of ints is incompatible with set of strings at 1:1",
"(set() + ['a']) + [1]");
}
@Test
public void testNsetBadNestedItemType() throws Exception {
- checkError("bad nested set: set of ints is incompatible with set of strings "
- + "at /some/file.txt:1:1",
+ checkError("bad nested set: set of ints is incompatible with set of strings at 1:1",
"(set() + ['b']) + (set() + [1])");
}
@Test
public void testTypeInferenceForMethodLibraryFunction() throws Exception {
- checkError("bad variable 'l': string is incompatible with int at /some/file.txt:2:3",
- "def foo():\n"
- + " l = len('abc')\n"
- + " l = 'a'");
+ checkError("bad variable 'l': string is incompatible with int at 2:3",
+ "def foo():",
+ " l = len('abc')",
+ " l = 'a'");
}
@Test
public void testListLiteralBadTypes() throws Exception {
- checkError("bad list literal: int is incompatible with string at /some/file.txt:1:1",
+ checkError("bad list literal: int is incompatible with string at 1:1",
"['a', 1]");
}
@@ -325,7 +322,7 @@
@Test
public void testDictLiteralBadKeyTypes() throws Exception {
- checkError("bad dict literal: int is incompatible with string at /some/file.txt:1:1",
+ checkError("bad dict literal: int is incompatible with string at 1:1",
"{'a': 1, 1: 2}");
}
@@ -336,15 +333,13 @@
@Test
public void testListConcatBadTypes() throws Exception {
- checkError("bad list concatenation: list of ints is incompatible with list of strings"
- + " at /some/file.txt:1:1",
+ checkError("bad list concatenation: list of ints is incompatible with list of strings at 1:1",
"['a'] + [1]");
}
@Test
public void testDictConcatBadKeyTypes() throws Exception {
- checkError("bad dict concatenation: dict of ints is incompatible with dict of strings "
- + "at /some/file.txt:1:1",
+ checkError("bad dict concatenation: dict of ints is incompatible with dict of strings at 1:1",
"{'a': 1} + {1: 2}");
}
@@ -365,13 +360,13 @@
@Test
public void testAndDifferentTypes() throws Exception {
- checkError("bad and operator: int is incompatible with string at /some/file.txt:1:1",
+ checkError("bad and operator: int is incompatible with string at 1:1",
"'ab' and 3");
}
@Test
public void testOrDifferentTypes() throws Exception {
- checkError("bad or operator: int is incompatible with string at /some/file.txt:1:1",
+ checkError("bad or operator: int is incompatible with string at 1:1",
"'ab' or 3");
}
@@ -382,20 +377,20 @@
@Test
public void testNoneAssignment() throws Exception {
- parse("def func():\n"
- + " a = None\n"
- + " a = 2\n"
- + " a = None\n");
+ parse("def func():",
+ " a = None",
+ " a = 2",
+ " a = None\n");
}
@Test
public void testNoneAssignmentError() throws Exception {
- checkError("bad variable 'a': string is incompatible with int at /some/file.txt",
- "def func():\n"
- + " a = None\n"
- + " a = 2\n"
- + " a = None\n"
- + " a = 'b'\n");
+ checkError("bad variable 'a': string is incompatible with int at 4:3",
+ "def func():",
+ " a = None",
+ " a = 2",
+ " a = None",
+ " a = 'b'\n");
}
@Test
@@ -409,14 +404,11 @@
@Test
public void testSlice() throws Exception {
- parse("def f(): "
- + "a = 'abc'; a = 'abcd'[2:]");
- parse("def f(): "
- + "b = ['abc']; b = ['abcd'][1:]");
- parse("def f(): "
- + "c = 'ab'; c = ['ab'][1:]");
+ parse("def f(): a = 'abc'; a = 'abcd'[2:]");
+ parse("def g(): b = ['abc']; b = ['abcd'][1:]");
+ parse("def h(): c = 'ab'; c = ['ab'][1:]");
checkError("bad variable 'c': string is incompatible with list of strings",
- "def f(): c = ['xy']; c = 'cx'[1:]");
+ "def i(): c = ['xy']; c = 'cx'[1:]");
}
@Test
@@ -426,80 +418,80 @@
@Test
public void testTypeInferenceForUserDefinedFunction() throws Exception {
- checkError("bad variable 'a': string is incompatible with int at /some/file.txt",
- "def func():\n"
- + " return 'a'\n"
- + "def foo():\n"
- + " a = 1\n"
- + " a = func()\n");
+ checkError("bad variable 'a': string is incompatible with int at 4:3",
+ "def func():",
+ " return 'a'",
+ "def foo():",
+ " a = 1",
+ " a = func()\n");
}
@Test
public void testCallingNonFunction() {
checkError("a is not a function",
- "a = '1':\n"
- + "a()\n");
+ "a = '1':",
+ "a()\n");
}
@Test
public void testFuncallArgument() {
checkError("unsupported operand type(s) for +: 'int' and 'string'",
- "def foo(x): return x\n"
- + "a = foo(1 + 'a')");
+ "def foo(x): return x",
+ "a = foo(1 + 'a')");
}
// Skylark built-in functions specific tests
@Test
public void testTypeInferenceForSkylarkBuiltinGlobalFunction() throws Exception {
- checkError("bad variable 'a': string is incompatible with function at /some/file.txt:3:3",
- "def impl(ctx): return None\n"
- + "def foo():\n"
- + " a = rule(impl)\n"
- + " a = 'a'\n");
+ checkError("bad variable 'a': string is incompatible with function at 3:3",
+ "def impl(ctx): return None",
+ "def foo():",
+ " a = rule(impl)",
+ " a = 'a'\n");
}
@Test
public void testTypeInferenceForSkylarkBuiltinObjectFunction() throws Exception {
- checkError("bad variable 'a': string is incompatible with Attribute at /some/file.txt",
- "def foo():\n"
- + " a = attr.int()\n"
- + " a = 'a'\n");
+ checkError("bad variable 'a': string is incompatible with Attribute at 2:3",
+ "def foo():",
+ " a = attr.int()",
+ " a = 'a'\n");
}
@Test
public void testFuncReturningDictAssignmentAsLValue() throws Exception {
- checkError("can only assign to variables, not to 'dict([])['b']'",
- "def dict():\n"
- + " return {'a': 1}\n"
- + "def func():\n"
- + " dict()['b'] = 2\n"
- + " return d\n");
+ checkError("can only assign to variables and tuples, not to 'dict([])['b']'",
+ "def dict():",
+ " return {'a': 1}",
+ "def func():",
+ " dict()['b'] = 2",
+ " return d\n");
}
@Test
public void testListIndexAsLValue() {
checkError("unsupported operand type(s) for +: 'list of ints' and 'dict of ints'",
- "def func():\n"
- + " l = [1]\n"
- + " l[0] = 2\n"
- + " return l\n");
+ "def func():",
+ " l = [1]",
+ " l[0] = 2",
+ " return l\n");
}
@Test
public void testStringIndexAsLValue() {
checkError("unsupported operand type(s) for +: 'string' and 'dict of ints'",
- "def func():\n"
- + " s = 'abc'\n"
- + " s[0] = 'd'\n"
- + " return s\n");
+ "def func():",
+ " s = 'abc'",
+ " s[0] = 'd'",
+ " return s\n");
}
@Test
public void testEmptyLiteralGenericIsSetInLaterConcatWorks() {
- parse("def func():\n"
- + " s = {}\n"
- + " s['a'] = 'b'\n");
+ parse("def func():",
+ " s = {}",
+ " s['a'] = 'b'\n");
}
@Test
@@ -510,117 +502,117 @@
@Test
public void testReadOnlyWorksForSimpleBranching() {
- parse("if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " v = 'b'");
+ parse("if 1:",
+ " v = 'a'",
+ "else:",
+ " v = 'b'");
}
@Test
public void testReadOnlyWorksForNestedBranching() {
- parse("if 1:\n"
- + " if 0:\n"
- + " v = 'a'\n"
- + " else:\n"
- + " v = 'b'\n"
- + "else:\n"
- + " if 0:\n"
- + " v = 'c'\n"
- + " else:\n"
- + " v = 'd'\n");
+ parse("if 1:",
+ " if 0:",
+ " v = 'a'",
+ " else:",
+ " v = 'b'",
+ "else:",
+ " if 0:",
+ " v = 'c'",
+ " else:",
+ " v = 'd'\n");
}
@Test
public void testTypeCheckWorksForSimpleBranching() {
- checkError("bad variable 'v': int is incompatible with string at /some/file.txt:2:3",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " v = 1");
+ checkError("bad variable 'v': int is incompatible with string at 2:3",
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " v = 1");
}
@Test
public void testTypeCheckWorksForNestedBranching() {
- checkError("bad variable 'v': int is incompatible with string at /some/file.txt:5:5",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " if 0:\n"
- + " v = 'b'\n"
- + " else:\n"
- + " v = 1\n");
+ checkError("bad variable 'v': int is incompatible with string at 5:5",
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " if 0:",
+ " v = 'b'",
+ " else:",
+ " v = 1\n");
}
@Test
public void testTypeCheckWorksForDifferentLevelBranches() {
- checkError("bad variable 'v': int is incompatible with string at /some/file.txt:2:3",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " if 0:\n"
- + " v = 1\n");
+ checkError("bad variable 'v': int is incompatible with string at 2:3",
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " if 0:",
+ " v = 1\n");
}
@Test
public void testReadOnlyWorksForDifferentLevelBranches() {
checkError("Variable v is read only",
- "if 1:\n"
- + " if 1:\n"
- + " v = 'a'\n"
- + " v = 'b'\n");
+ "if 1:",
+ " if 1:",
+ " v = 'a'",
+ " v = 'b'\n");
}
@Test
public void testReadOnlyWorksWithinSimpleBranch() {
checkError("Variable v is read only",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " v = 'b'\n"
- + " v = 'c'\n");
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " v = 'b'",
+ " v = 'c'\n");
}
@Test
public void testReadOnlyWorksWithinNestedBranch() {
checkError("Variable v is read only",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " if 1:\n"
- + " v = 'b'\n"
- + " else:\n"
- + " v = 'c'\n"
- + " v = 'd'\n");
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " if 1:",
+ " v = 'b'",
+ " else:",
+ " v = 'c'",
+ " v = 'd'\n");
}
@Test
public void testReadOnlyWorksAfterSimpleBranch() {
checkError("Variable v is read only",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " w = 'a'\n"
- + "v = 'b'");
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " w = 'a'",
+ "v = 'b'");
}
@Test
public void testReadOnlyWorksAfterNestedBranch() {
checkError("Variable v is read only",
- "if 1:\n"
- + " if 1:\n"
- + " v = 'a'\n"
- + "v = 'b'");
+ "if 1:",
+ " if 1:",
+ " v = 'a'",
+ "v = 'b'");
}
@Test
public void testReadOnlyWorksAfterNestedBranch2() {
checkError("Variable v is read only",
- "if 1:\n"
- + " v = 'a'\n"
- + "else:\n"
- + " if 0:\n"
- + " w = 1\n"
- + "v = 'b'\n");
+ "if 1:",
+ " v = 'a'",
+ "else:",
+ " if 0:",
+ " w = 1",
+ "v = 'b'\n");
}
@Test
@@ -684,18 +676,16 @@
@Test
public void testDollarErrorDoesNotLeak() throws Exception {
- syntaxEvents.setFailFast(false);
- String content = Joiner.on("\n").join(
- "def GenerateMapNames():",
+ setFailFast(false);
+ parseFile("def GenerateMapNames():",
" a = 2",
" b = [3, 4]",
" if a not b:",
" print(a)");
- parseFileForSkylark(content);
- syntaxEvents.assertContainsEvent("syntax error at 'not': expected :");
+ assertContainsEvent("syntax error at 'not': expected :");
// Parser uses "$error" symbol for error recovery.
// It should not be used in error messages.
- for (Event event : syntaxEvents.collector()) {
+ for (Event event : getEventCollector()) {
assertThat(event.getMessage()).doesNotContain("$error$");
}
}
@@ -782,13 +772,13 @@
}
private void parse(String... lines) {
- parseFileForSkylark(Joiner.on("\n").join(lines));
- syntaxEvents.assertNoEvents();
+ parseFile(lines);
+ assertNoEvents();
}
private void checkError(String errorMsg, String... lines) {
- syntaxEvents.setFailFast(false);
- parseFileForSkylark(Joiner.on("\n").join(lines));
- syntaxEvents.assertContainsEvent(errorMsg);
+ setFailFast(false);
+ parseFile(lines);
+ assertContainsEvent(errorMsg);
}
}