diff options
author | 2015-02-27 15:53:24 +0000 | |
---|---|---|
committer | 2015-03-05 14:15:34 +0000 | |
commit | ccf19eaa0045a26f2654311966b9ece51354ede1 (patch) | |
tree | 1d53337658d6ba82d789605406a2a4afd4900a78 /src/test/java/com | |
parent | 22513330de1212d05c2342d4290a057b214a9b96 (diff) |
Convert rest of syntax tests to JUnit4.
--
MOS_MIGRATED_REVID=87342725
Diffstat (limited to 'src/test/java/com')
10 files changed, 444 insertions, 14 deletions
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 index ba59864ffe..cba1bd61ed 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/AbstractParserTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/AbstractParserTestCase.java @@ -20,14 +20,12 @@ 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 junit.framework.TestCase; - import java.util.List; /** * Base class for test cases that use parsing services. */ -public abstract class AbstractParserTestCase extends TestCase { +public abstract class AbstractParserTestCase { public static final class EmptyPackageLocator implements CachingPackageLocator { @Override public Path getBuildFileForPackage(String packageName) { 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 045291364c..daa849b3ee 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 @@ -14,14 +14,23 @@ package com.google.devtools.build.lib.syntax; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import com.google.common.collect.Sets; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + /** * Tests of Environment. */ +@RunWith(JUnit4.class) public class EnvironmentTest extends AbstractEvaluationTestCase { // Test the API directly + @Test public void testLookupAndUpdate() throws Exception { Environment env = new Environment(); @@ -37,6 +46,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { assertEquals("bar", env.lookup("foo")); } + @Test public void testLookupWithDefault() throws Exception { Environment env = new Environment(); assertEquals(21, env.lookup("VERSION", 21)); @@ -44,6 +54,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { assertEquals(42, env.lookup("VERSION", 21)); } + @Test public void testDoubleUpdateSucceeds() throws Exception { Environment env = new Environment(); env.update("VERSION", 42); @@ -53,6 +64,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { } // Test assign through interpreter, lookup through API: + @Test public void testAssign() throws Exception { Environment env = new Environment(); @@ -69,6 +81,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { } // Test update through API, reference through interpreter: + @Test public void testReference() throws Exception { Environment env = new Environment(); @@ -85,6 +98,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { } // Test assign and reference through interpreter: + @Test public void testAssignAndReference() throws Exception { Environment env = new Environment(); @@ -100,6 +114,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { assertEquals("bar", eval(parseExpr("foo"), env)); } + @Test public void testGetVariableNames() throws Exception { Environment env = new Environment(); env.update("foo", "bar"); @@ -114,6 +129,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { nestedEnv.getVariableNames()); } + @Test public void testToString() throws Exception { Environment env = new Environment(); env.update("subject", new StringLiteral("Hello, 'world'.", '\'')); @@ -122,6 +138,7 @@ public class EnvironmentTest extends AbstractEvaluationTestCase { + "subject -> 'Hello, \\'world\\'.', }", env.toString()); } + @Test public void testBindToNullThrowsException() throws Exception { try { new Environment().update("some_name", 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 f7ed359dab..f33b500c32 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 @@ -14,6 +14,10 @@ package com.google.devtools.build.lib.syntax; import static com.google.common.truth.Truth.assertThat; +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.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -22,6 +26,11 @@ import com.google.common.collect.Lists; 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; @@ -31,13 +40,14 @@ import java.util.Map; /** * Test of evaluation behavior. (Implicitly uses lexer + parser.) */ +@RunWith(JUnit4.class) public class EvaluationTest extends AbstractEvaluationTestCase { protected Environment env; - @Override + @Before public void setUp() throws Exception { - super.setUp(); + PackageFactory factory = new PackageFactory(TestRuleClassProvider.getRuleClassProvider()); env = factory.getEnvironment(); } @@ -53,6 +63,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { return eval(parseExpr(input), env); } + @Test public void testExprs() throws Exception { assertEquals("fooxbar", eval("'%sx' % 'foo' + 'bar'")); @@ -70,6 +81,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { checkEvalError("3 % 'foo'", "unsupported operand type(s) for %: 'int' and 'string'"); } + @Test public void testListExprs() throws Exception { assertEquals(Arrays.asList(1, 2, 3), eval("[1, 2, 3]")); @@ -77,10 +89,12 @@ public class EvaluationTest extends AbstractEvaluationTestCase { eval("(1, 2, 3)")); } + @Test public void testStringFormatMultipleArgs() throws Exception { assertEquals("XYZ", eval("'%sY%s' % ('X', 'Z')")); } + @Test public void testAndOr() throws Exception { assertEquals(8, eval("8 or 9")); assertEquals(8, eval("8 or foo")); // check that 'foo' is not evaluated @@ -104,11 +118,13 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(Environment.NONE, eval("None and 1")); } + @Test public void testNot() throws Exception { assertEquals(false, eval("not 1")); assertEquals(true, eval("not ''")); } + @Test public void testNotWithLogicOperators() throws Exception { assertEquals(0, eval("0 and not 0")); assertEquals(0, eval("not 0 and 0")); @@ -123,16 +139,19 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(false, eval("not (1 or 0)")); } + @Test public void testNotWithArithmeticOperators() throws Exception { assertEquals(true, eval("not 0 + 0")); assertEquals(false, eval("not 2 - 1")); } + @Test public void testNotWithCollections() throws Exception { assertEquals(true, eval("not []")); assertEquals(false, eval("not {'a' : 1}")); } + @Test public void testEquality() throws Exception { assertEquals(true, eval("1 == 1")); assertEquals(false, eval("1 == 2")); @@ -143,6 +162,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(true, eval("None == None")); } + @Test public void testInequality() throws Exception { assertEquals(false, eval("1 != 1")); assertEquals(true, eval("1 != 2")); @@ -152,6 +172,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(true, eval("[1, 2] != [2, 1]")); } + @Test public void testEqualityPrecedence() throws Exception { assertEquals(true, eval("1 + 3 == 2 + 2")); assertEquals(true, eval("not 1 == 2")); @@ -160,6 +181,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(2, eval("2 or 3 == 3 and 1")); } + @Test public void testLessThan() throws Exception { assertEquals(true, eval("1 <= 1")); assertEquals(false, eval("1 < 1")); @@ -167,6 +189,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(false, eval("'c' < 'a'")); } + @Test public void testGreaterThan() throws Exception { assertEquals(true, eval("1 >= 1")); assertEquals(false, eval("1 > 1")); @@ -174,14 +197,17 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(true, eval("'c' > 'a'")); } + @Test public void testCompareStringInt() throws Exception { checkEvalError("'a' >= 1", "Cannot compare string with int"); } + @Test public void testNotComparable() throws Exception { checkEvalError("[1, 2] < [1, 3]", "[1, 2] is not comparable"); } + @Test public void testSumFunction() throws Exception { Function sum = new AbstractFunction("sum") { @Override @@ -216,6 +242,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(123456, eval("sum", env)); } + @Test public void testKeywordArgs() throws Exception { // This function returns the list of keyword-argument keys or values, @@ -248,6 +275,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { eval("keyval(1, foo=1, bar='bar', wiz=[1,2,3])", env)); } + @Test public void testMult() throws Exception { assertEquals(42, eval("6 * 7")); @@ -256,10 +284,12 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals("100000", eval("'1' + '0' * 5")); } + @Test public void testConcatStrings() throws Exception { assertEquals("foobar", eval("'foo' + 'bar'")); } + @Test public void testConcatLists() throws Exception { // list Object x = eval("[1,2] + [3,4]"); @@ -276,6 +306,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { } @SuppressWarnings("unchecked") + @Test public void testListComprehensions() throws Exception { Iterable<Object> eval = (Iterable<Object>) eval( "['foo/%s.java' % x for x in []]"); @@ -311,6 +342,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { // 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)) @@ -318,6 +350,7 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals(3, env.lookup("x")); // (x is global) } + @Test public void testDictComprehensions() throws Exception { assertEquals(Collections.emptyMap(), eval("{x : x for x in []}")); assertEquals(ImmutableMap.of(1, 1, 2, 2), eval("{x : x for x in [1, 2]}")); @@ -329,18 +362,21 @@ public class EvaluationTest extends AbstractEvaluationTestCase { eval("{'k_' + x : 'v_' + x for x in ['a', 'b']}")); } + @Test public void testDictComprehensions_MultipleKey() throws Exception { assertEquals(ImmutableMap.of(1, 1, 2, 2), eval("{x : x for x in [1, 2, 1]}")); assertEquals(ImmutableMap.of("ab", "ab", "c", "c"), eval("{x : x for x in ['ab', 'c', 'a' + 'b']}")); } + @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 + 'a': x for x in [1, 2]}", parseExpr("{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)); @@ -348,21 +384,25 @@ public class EvaluationTest extends AbstractEvaluationTestCase { checkEvalError("(1, 2) + [3, 4]", "can only concatenate list (not \"tuple\") to list"); } + @Test public void testListComprehensionFailsOnNonSequence() throws Exception { checkEvalError("[x + 1 for x in 123]", "type 'int' is not an iterable"); } @SuppressWarnings("unchecked") + @Test public void testListComprehensionOnString() throws Exception { 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, not to 'x + 1'"); } + @Test public void testListComprehensionOnDictionary() throws Exception { List<Statement> input = parseFile("val = ['var_' + n for n in {'a':1,'b':2}]"); exec(input, env); @@ -372,58 +412,71 @@ public class EvaluationTest extends AbstractEvaluationTestCase { assertEquals("var_b", Iterables.get(result, 1)); } + @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]", env.lookup("l").toString()); } + @Test public void testInOnListContains() throws Exception { assertEquals(Boolean.TRUE, eval("'b' in ['a', 'b']")); } + @Test public void testInOnListDoesNotContain() throws Exception { assertEquals(Boolean.FALSE, eval("'c' in ['a', 'b']")); } + @Test public void testInOnTupleContains() throws Exception { assertEquals(Boolean.TRUE, eval("'b' in ('a', 'b')")); } + @Test public void testInOnTupleDoesNotContain() throws Exception { assertEquals(Boolean.FALSE, eval("'c' in ('a', 'b')")); } + @Test public void testInOnDictContains() throws Exception { assertEquals(Boolean.TRUE, eval("'b' in {'a' : 1, 'b' : 2}")); } + @Test public void testInOnDictDoesNotContainKey() throws Exception { assertEquals(Boolean.FALSE, eval("'c' in {'a' : 1, 'b' : 2}")); } + @Test public void testInOnDictDoesNotContainVal() throws Exception { assertEquals(Boolean.FALSE, eval("1 in {'a' : 1, 'b' : 2}")); } + @Test public void testInOnStringContains() throws Exception { assertEquals(Boolean.TRUE, eval("'b' in 'abc'")); } + @Test public void testInOnStringDoesNotContain() throws Exception { assertEquals(Boolean.FALSE, eval("'d' in 'abc'")); } + @Test public void testInOnStringLeftNotString() throws Exception { checkEvalError("1 in '123'", "in operator only works on strings if the left operand is also a string"); } + @Test public void testInFailsOnNonIterable() throws Exception { checkEvalError("'a' in 1", "in operator only works on lists, tuples, dictionaries and strings"); } + @Test public void testInCompositeForPrecedence() throws Exception { assertEquals(0, eval("not 'a' in ['a'] or 0")); } @@ -437,27 +490,32 @@ public class EvaluationTest extends AbstractEvaluationTestCase { }; } + @Test public void testPercOnObject() throws Exception { env.update("obj", createObjWithStr()); assertEquals("str marker", eval("'%s' % obj", env)); } + @Test public void testPercOnObjectList() throws Exception { env.update("obj", createObjWithStr()); assertEquals("str marker str marker", eval("'%s %s' % (obj, obj)", env)); } + @Test public void testPercOnObjectInvalidFormat() throws Exception { env.update("obj", createObjWithStr()); checkEvalError("'%d' % obj", env, "invalid arguments for format string"); } @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(); } + @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)"); 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 fc14922e2e..eaefb6918e 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 @@ -14,12 +14,20 @@ package com.google.devtools.build.lib.syntax; 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; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -27,6 +35,7 @@ import java.util.Map; /** * A test class for functions and scoping. */ +@RunWith(JUnit4.class) public class FunctionTest extends AbstractEvaluationTestCase { private Environment env; @@ -35,12 +44,13 @@ public class FunctionTest extends AbstractEvaluationTestCase { ImmutableMap.<String, SkylarkType>of( "outer_func", SkylarkFunctionType.of("outer_func", SkylarkType.NONE)); - @Override + @Before public void setUp() throws Exception { - super.setUp(); + env = new SkylarkEnvironment(syntaxEvents.collector()); } + @Test public void testFunctionDef() throws Exception { List<Statement> input = parseFileForSkylark( "def func(a,b,c):\n" @@ -55,6 +65,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertThat(stmt.getStatements()).hasSize(2); } + @Test public void testFunctionDefDuplicateArguments() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark( @@ -63,6 +74,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { syntaxEvents.assertContainsEvent("duplicate parameter name in function definition"); } + @Test public void testFunctionDefCallOuterFunc() throws Exception { final List<Object> params = new ArrayList<>(); List<Statement> input = parseFileForSkylark( @@ -89,6 +101,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { env.update("outer_func", outerFunc); } + @Test public void testFunctionDefNoEffectOutsideScope() throws Exception { List<Statement> input = parseFileForSkylark( "def func():\n" @@ -99,6 +112,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("a")); } + @Test public void testFunctionDefGlobalVaribleReadInFunction() throws Exception { List<Statement> input = parseFileForSkylark( "a = 1\n" @@ -110,6 +124,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("c")); } + @Test public void testFunctionDefLocalGlobalScope() throws Exception { List<Statement> input = parseFileForSkylark( "a = 1\n" @@ -122,6 +137,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(2, env.lookup("c")); } + @Test public void testFunctionDefLocalVariableReferencedBeforeAssignment() throws Exception { List<Statement> input = parseFileForSkylark( "a = 1\n" @@ -138,6 +154,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { } } + @Test public void testFunctionDefLocalVariableReferencedAfterAssignment() throws Exception { List<Statement> input = parseFileForSkylark( "a = 1\n" @@ -152,6 +169,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { } @SuppressWarnings("unchecked") + @Test public void testSkylarkGlobalComprehensionIsAllowed() throws Exception { List<Statement> input = parseFileForSkylark( "a = [i for i in [1, 2, 3]]\n"); @@ -159,6 +177,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertThat((Iterable<Object>) env.lookup("a")).containsExactly(1, 2, 3).inOrder(); } + @Test public void testFunctionReturn() throws Exception { List<Statement> input = parseFileForSkylark( "def func():\n" @@ -168,6 +187,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(2, env.lookup("b")); } + @Test public void testFunctionReturnFromALoop() throws Exception { List<Statement> input = parseFileForSkylark( "def func():\n" @@ -178,6 +198,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("b")); } + @Test public void testFunctionExecutesProperly() throws Exception { List<Statement> input = parseFileForSkylark( "def func(a):\n" @@ -192,6 +213,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(2, env.lookup("d")); } + @Test public void testFunctionCallFromFunction() throws Exception { final List<Object> params = new ArrayList<>(); List<Statement> input = parseFileForSkylark( @@ -207,6 +229,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertThat(params).containsExactly(1, 2).inOrder(); } + @Test public void testFunctionCallFromFunctionReadGlobalVar() throws Exception { List<Statement> input = parseFileForSkylark( "a = 1\n" @@ -219,6 +242,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("b")); } + @Test public void testSingleLineFunction() throws Exception { List<Statement> input = parseFileForSkylark( "def func(): return 'a'\n" @@ -227,6 +251,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals("a", env.lookup("s")); } + @Test public void testFunctionReturnsDictionary() throws Exception { MethodLibrary.setupMethodEnvironment(env); List<Statement> input = parseFileForSkylark( @@ -237,6 +262,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("a")); } + @Test public void testFunctionReturnsList() throws Exception { MethodLibrary.setupMethodEnvironment(env); List<Statement> input = parseFileForSkylark( @@ -248,6 +274,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { } @SuppressWarnings("unchecked") + @Test public void testFunctionListArgumentsAreImmutable() throws Exception { MethodLibrary.setupMethodEnvironment(env); List<Statement> input = parseFileForSkylark( @@ -259,6 +286,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertThat((Iterable<Object>) env.lookup("l")).containsExactly(1); } + @Test public void testFunctionDictArgumentsAreImmutable() throws Exception { MethodLibrary.setupMethodEnvironment(env); List<Statement> input = parseFileForSkylark( @@ -270,6 +298,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(ImmutableMap.of("a", 1), env.lookup("d")); } + @Test public void testFunctionNameAliasing() throws Exception { List<Statement> input = parseFileForSkylark( "def func(a):\n" @@ -280,6 +309,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(2, env.lookup("r")); } + @Test public void testCallingFunctionsWithMixedModeArgs() throws Exception { List<Statement> input = parseFileForSkylark( "def func(a, b, c):\n" @@ -299,6 +329,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { + " return r\n"; } + @Test public void testWhichOptionalArgsAreDefinedForFunctions() throws Exception { List<Statement> input = parseFileForSkylark( functionWithOptionalArgs() @@ -313,6 +344,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals("4ac", env.lookup("v4")); } + @Test public void testDefaultArguments() throws Exception { List<Statement> input = parseFileForSkylark( "def func(a, b = 'b', c = 'c'):\n" @@ -328,6 +360,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals("aby", env.lookup("v4")); } + @Test public void testDefaultArgumentsInsufficientArgNum() throws Exception { checkError("func(a, b = null, c = null) received insufficient arguments", "def func(a, b = 'b', c = 'c'):", @@ -335,6 +368,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { "func()"); } + @Test public void testKwargs() throws Exception { List<Statement> input = parseFileForSkylark( "def foo(a, b = 'b', c = 'c'):\n" @@ -349,6 +383,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals("xyz", env.lookup("v3")); } + @Test public void testKwargsBadKey() throws Exception { checkError("Keywords must be strings, not int", "def func(a, b):", @@ -356,6 +391,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { "func('a', **{3: 1})"); } + @Test public void testKwargsIsNotDict() throws Exception { checkError("Argument after ** must be a dictionary, not int", "def func(a, b):", @@ -363,6 +399,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { "func('a', **42)"); } + @Test public void testKwargsCollision() throws Exception { checkError("func(a, b) got multiple values for keyword argument 'b'", "def func(a, b):", @@ -370,6 +407,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { "func('a', 'b', **{'b': 'foo'})"); } + @Test public void testKwargsCollisionWithNamed() throws Exception { checkError("duplicate keyword 'b' in call to func", "def func(a, b):", @@ -377,6 +415,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { "func('a', b = 'b', **{'b': 'foo'})"); } + @Test public void testDefaultArguments2() throws Exception { List<Statement> input = parseFileForSkylark( "a = 2\n" @@ -389,6 +428,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals(2, env.lookup("v")); } + @Test public void testMixingPositionalOptional() throws Exception { List<Statement> input = parseFileForSkylark( "def f(name, value = '', optional = ''): return value\n" @@ -397,6 +437,7 @@ public class FunctionTest extends AbstractEvaluationTestCase { assertEquals("value", env.lookup("v")); } + @Test public void testStarArg() throws Exception { List<Statement> input = parseFileForSkylark( "def f(name, value = '1', optional = '2'): return name + value + optional\n" 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 c7c2c40134..cb879f8c41 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 @@ -13,13 +13,21 @@ // limitations under the License. package com.google.devtools.build.lib.syntax; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import com.google.common.collect.ImmutableList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + import java.util.Arrays; /** * Tests for {@link MixedModeFunction}. */ +@RunWith(JUnit4.class) public class MixedModeFunctionTest extends AbstractEvaluationTestCase { private Environment singletonEnv(String id, Object value) { @@ -91,6 +99,7 @@ public class MixedModeFunctionTest extends AbstractEvaluationTestCase { } } + @Test public void testNoSurplusArguments() throws Exception { checkMixedModeFunctions(false, "mixed(foo, bar = null)", @@ -110,6 +119,7 @@ public class MixedModeFunctionTest extends AbstractEvaluationTestCase { }); } + @Test public void testOnlyNamedArguments() throws Exception { checkMixedModeFunctions(true, "mixed(foo, bar = null)", 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 e698728553..a4fa5d1f9a 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 @@ -15,16 +15,24 @@ package com.google.devtools.build.lib.syntax; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +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.devtools.build.lib.events.Location; import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + import java.util.List; /** * Tests of parser behaviour. - * */ +@RunWith(JUnit4.class) public class ParserTest extends AbstractParserTestCase { private static String getText(String text, ASTNode node) { @@ -57,6 +65,7 @@ public class ParserTest extends AbstractParserTestCase { return f.getArguments().get(index).getValue(); } + @Test public void testPrecedence1() throws Exception { BinaryOperatorExpression e = (BinaryOperatorExpression) parseExpr("'%sx' % 'foo' + 'bar'"); @@ -64,24 +73,28 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(Operator.PLUS, e.getOperator()); } + @Test public void testPrecedence2() throws Exception { BinaryOperatorExpression e = (BinaryOperatorExpression) parseExpr("('%sx' % 'foo') + 'bar'"); assertEquals(Operator.PLUS, e.getOperator()); } + @Test public void testPrecedence3() throws Exception { BinaryOperatorExpression e = (BinaryOperatorExpression) parseExpr("'%sx' % ('foo' + 'bar')"); assertEquals(Operator.PERCENT, e.getOperator()); } + @Test public void testPrecedence4() throws Exception { BinaryOperatorExpression e = (BinaryOperatorExpression) parseExpr("1 + - (2 - 3)"); assertEquals(Operator.PLUS, e.getOperator()); } + @Test public void testUnaryMinusExpr() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("-5"); FuncallExpression e2 = (FuncallExpression) parseExpr("- 5"); @@ -96,6 +109,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(5, (int) arg0.getValue()); } + @Test public void testFuncallExpr() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("foo(1, 2, bar=wiz)"); @@ -117,6 +131,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("wiz", arg2val.getName()); } + @Test public void testMethCallExpr() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("foo.foo(1, 2, bar=wiz)"); @@ -139,6 +154,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("wiz", arg2val.getName()); } + @Test public void testChainedMethCallExpr() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("foo.replace().split(1)"); @@ -153,6 +169,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(1, (int) arg0.getValue()); } + @Test public void testPropRefExpr() throws Exception { DotExpression e = (DotExpression) parseExpr("foo.foo"); @@ -160,6 +177,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("foo", ident.getName()); } + @Test public void testStringMethExpr() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("'foo'.foo()"); @@ -169,26 +187,31 @@ public class ParserTest extends AbstractParserTestCase { assertThat(e.getArguments()).isEmpty(); } + @Test public void testStringLiteralOptimizationValue() throws Exception { StringLiteral l = (StringLiteral) parseExpr("'abc' + 'def'"); assertEquals("abcdef", l.value); } + @Test public void testStringLiteralOptimizationToString() throws Exception { StringLiteral l = (StringLiteral) parseExpr("'abc' + 'def'"); assertEquals("'abcdef'", l.toString()); } + @Test public void testStringLiteralOptimizationLocation() throws Exception { StringLiteral l = (StringLiteral) parseExpr("'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); } + @Test public void testSubstring() throws Exception { FuncallExpression e = (FuncallExpression) parseExpr("'FOO.CC'[:].lower()[1:]"); assertEquals("$substring", e.getFunction().getName()); @@ -214,6 +237,7 @@ public class ParserTest extends AbstractParserTestCase { } } + @Test public void testErrorRecovery() throws Exception { syntaxEvents.setFailFast(false); @@ -245,6 +269,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(3, (int) arg2.getValue()); } + @Test public void testDoesntGetStuck() throws Exception { syntaxEvents.setFailFast(false); @@ -262,6 +287,7 @@ public class ParserTest extends AbstractParserTestCase { // i.e. there were some events } + @Test public void testSecondaryLocation() { String expr = "f(1 % 2)"; FuncallExpression call = (FuncallExpression) parseExpr(expr); @@ -269,6 +295,7 @@ public class ParserTest extends AbstractParserTestCase { assertTrue(arg.getLocation().getEndOffset() < call.getLocation().getEndOffset()); } + @Test public void testPrimaryLocation() { String expr = "f(1 + 2)"; FuncallExpression call = (FuncallExpression) parseExpr(expr); @@ -276,6 +303,7 @@ public class ParserTest extends AbstractParserTestCase { assertTrue(arg.getLocation().getEndOffset() < call.getLocation().getEndOffset()); } + @Test public void testAssignLocation() { String expr = "a = b;c = d\n"; List<Statement> statements = parseFile(expr); @@ -283,12 +311,14 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(5, statement.getLocation().getEndOffset()); } + @Test public void testAssign() { String expr = "list[0] = 5; dict['key'] = value\n"; List<Statement> statements = parseFile(expr); assertThat(statements).hasSize(2); } + @Test public void testInvalidAssign() { syntaxEvents.setFailFast(false); parseExpr("1 + (b = c)"); @@ -296,10 +326,12 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.collector().clear(); } + @Test public void testAugmentedAssign() throws Exception { assertEquals("[x = x + 1\n]", parseFile("x += 1").toString()); } + @Test public void testPrettyPrintFunctions() throws Exception { assertEquals("[x[1:3]\n]", parseFile("x[1:3]").toString()); assertEquals("[str[42]\n]", parseFile("str[42]").toString()); @@ -307,6 +339,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("[new_file(['hello'])\n]", parseFile("new_file('hello')").toString()); } + @Test public void testFuncallLocation() { String expr = "a(b);c = d\n"; List<Statement> statements = parseFile(expr); @@ -314,6 +347,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(4, statement.getLocation().getEndOffset()); } + @Test public void testSpecialFuncallLocation() throws Exception { List<Statement> statements = parseFile("-x\n"); assertLocation(0, 3, statements.get(0).getLocation()); @@ -325,6 +359,7 @@ public class ParserTest extends AbstractParserTestCase { assertLocation(0, 10, statements.get(0).getLocation()); } + @Test public void testListPositions() throws Exception { String expr = "[0,f(1),2]"; ListLiteral list = (ListLiteral) parseExpr(expr); @@ -334,6 +369,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("2", getText(expr, getElem(list, 2))); } + @Test public void testDictPositions() throws Exception { String expr = "{1:2,2:f(1),3:4}"; DictionaryLiteral list = (DictionaryLiteral) parseExpr(expr); @@ -343,6 +379,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("3:4", getText(expr, getElem(list, 2))); } + @Test public void testArgumentPositions() throws Exception { String stmt = "f(0,g(1,2),2)"; FuncallExpression f = (FuncallExpression) parseExpr(stmt); @@ -352,6 +389,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals("2", getText(stmt, getArg(f, 2))); } + @Test public void testListLiterals1() throws Exception { ListLiteral list = (ListLiteral) parseExpr("[0,1,2]"); assertFalse(list.isTuple()); @@ -362,6 +400,7 @@ public class ParserTest extends AbstractParserTestCase { } } + @Test public void testTupleLiterals2() throws Exception { ListLiteral tuple = (ListLiteral) parseExpr("(0,1,2)"); assertTrue(tuple.isTuple()); @@ -372,12 +411,14 @@ public class ParserTest extends AbstractParserTestCase { } } + @Test public void testTupleLiterals3() throws Exception { ListLiteral emptyTuple = (ListLiteral) parseExpr("()"); assertTrue(emptyTuple.isTuple()); assertThat(emptyTuple.getElements()).isEmpty(); } + @Test public void testTupleLiterals4() throws Exception { ListLiteral singletonTuple = (ListLiteral) parseExpr("(42,)"); assertTrue(singletonTuple.isTuple()); @@ -385,17 +426,20 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(42, getIntElem(singletonTuple, 0)); } + @Test public void testTupleLiterals5() throws Exception { IntegerLiteral intLit = (IntegerLiteral) parseExpr("(42)"); // not a tuple! assertEquals(42, (int) intLit.getValue()); } + @Test public void testListLiterals6() throws Exception { ListLiteral emptyList = (ListLiteral) parseExpr("[]"); assertFalse(emptyList.isTuple()); assertThat(emptyList.getElements()).isEmpty(); } + @Test public void testListLiterals7() throws Exception { ListLiteral singletonList = (ListLiteral) parseExpr("[42,]"); assertFalse(singletonList.isTuple()); @@ -403,6 +447,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(42, getIntElem(singletonList, 0)); } + @Test public void testListLiterals8() throws Exception { ListLiteral singletonList = (ListLiteral) parseExpr("[42]"); // a singleton assertFalse(singletonList.isTuple()); @@ -410,6 +455,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(42, getIntElem(singletonList, 0)); } + @Test public void testDictionaryLiterals() throws Exception { DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpr("{1:42}"); // a singleton dictionary @@ -419,12 +465,14 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(42, getIntElem(tuple, false)); } + @Test public void testDictionaryLiterals1() throws Exception { DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpr("{}"); // an empty dictionary assertThat(dictionaryList.getEntries()).isEmpty(); } + @Test public void testDictionaryLiterals2() throws Exception { DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpr("{1:42,}"); // a singleton dictionary @@ -434,6 +482,7 @@ public class ParserTest extends AbstractParserTestCase { assertEquals(42, getIntElem(tuple, false)); } + @Test public void testDictionaryLiterals3() throws Exception { DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpr("{1:42,2:43,3:44}"); assertThat(dictionaryList.getEntries()).hasSize(3); @@ -444,6 +493,7 @@ public class ParserTest extends AbstractParserTestCase { } } + @Test public void testListLiterals9() throws Exception { ListLiteral singletonList = (ListLiteral) parseExpr("[ abi + opt_level + \'/include\' ]"); @@ -451,6 +501,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(singletonList.getElements()).hasSize(1); } + @Test public void testListComprehensionSyntax() throws Exception { syntaxEvents.setFailFast(false); @@ -475,6 +526,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.collector().clear(); } + @Test public void testListComprehension() throws Exception { ListComprehension list = (ListComprehension) parseExpr( @@ -491,22 +543,26 @@ public class ParserTest extends AbstractParserTestCase { assertThat(list.getLists()).hasSize(2); } + @Test public void testParserContainsErrorsIfSyntaxException() throws Exception { syntaxEvents.setFailFast(false); parseExpr("'foo' %%"); syntaxEvents.assertContainsEvent("syntax error at '%'"); } + @Test public void testParserDoesNotContainErrorsIfSuccess() throws Exception { parseExpr("'foo'"); } + @Test public void testParserContainsErrors() throws Exception { syntaxEvents.setFailFast(false); parseStmt("+"); syntaxEvents.assertContainsEvent("syntax error at '+'"); } + @Test public void testSemicolonAndNewline() throws Exception { List<Statement> stmts = parseFile( "foo='bar'; foo(bar)" + '\n' @@ -516,6 +572,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(4); } + @Test public void testSemicolonAndNewline2() throws Exception { syntaxEvents.setFailFast(false); List<Statement> stmts = parseFile( @@ -526,6 +583,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(2); } + @Test public void testExprAsStatement() throws Exception { List<Statement> stmts = parseFile( "li = []\n" @@ -536,6 +594,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(4); } + @Test public void testParseBuildFileWithSingeRule() throws Exception { List<Statement> stmts = parseFile( "genrule(name = 'foo'," + '\n' @@ -547,6 +606,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(1); } + @Test public void testParseBuildFileWithMultipleRules() throws Exception { List<Statement> stmts = parseFile( "genrule(name = 'foo'," + '\n' @@ -563,6 +623,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(2); } + @Test public void testParseBuildFileWithComments() throws Exception { Parser.ParseResult result = parseFileWithComments( "# Test BUILD file" + '\n' @@ -578,6 +639,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(result.comments).hasSize(2); } + @Test public void testParseBuildFileWithManyComments() throws Exception { Parser.ParseResult result = parseFileWithComments( "# 1" + '\n' @@ -614,6 +676,7 @@ public class ParserTest extends AbstractParserTestCase { .that(result.comments.size()).isEqualTo(10); // One per '#' } + @Test public void testMissingComma() throws Exception { syntaxEvents.setFailFast(false); // Regression test. @@ -623,6 +686,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("syntax error at 'srcs'"); } + @Test public void testDoubleSemicolon() throws Exception { syntaxEvents.setFailFast(false); // Regression test. @@ -630,6 +694,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("syntax error at ';'"); } + @Test public void testFunctionDefinitionErrorRecovery() throws Exception { // Parser skips over entire function definitions, and reports a meaningful // error. @@ -645,6 +710,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(2); } + @Test public void testFunctionDefinitionIgnored() throws Exception { // Parser skips over entire function definitions without reporting error, // when parsePython is set to true. @@ -666,6 +732,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(2); } + @Test public void testMissingBlock() throws Exception { syntaxEvents.setFailFast(false); List<Statement> stmts = parseFile( @@ -677,6 +744,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("expected an indented block"); } + @Test public void testInvalidDef() throws Exception { syntaxEvents.setFailFast(false); parseFile( @@ -687,6 +755,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("syntax error at 'EOF'"); } + @Test public void testSkipIfBlock() throws Exception { // Skip over 'if' blocks, when parsePython is set List<Statement> stmts = parseFile( @@ -700,6 +769,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts).hasSize(2); } + @Test public void testSkipIfBlockFail() throws Exception { // Do not parse 'if' blocks, when parsePython is not set syntaxEvents.setFailFast(false); @@ -713,6 +783,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("This Python-style construct is not supported"); } + @Test public void testForLoopMultipleVariablesFail() throws Exception { // For loops with multiple variables are not allowed, when parsePython is not set syntaxEvents.setFailFast(false); @@ -723,6 +794,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("For loops with multiple variables are not yet supported."); } + @Test public void testForLoopMultipleVariables() throws Exception { // For loops with multiple variables is ok, when parsePython is set List<Statement> stmts1 = parseFile( @@ -741,6 +813,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmts3).hasSize(1); } + @Test public void testForLoopBadSyntax() throws Exception { syntaxEvents.setFailFast(false); parseFile( @@ -749,6 +822,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testForLoopBadSyntax2() throws Exception { syntaxEvents.setFailFast(false); parseFile( @@ -757,18 +831,21 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testFunCallBadSyntax() throws Exception { syntaxEvents.setFailFast(false); parseFile("f(1,\n"); syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testFunCallBadSyntax2() throws Exception { syntaxEvents.setFailFast(false); parseFile("f(1, 5, ,)\n"); syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testLoadOneSymbol() throws Exception { List<Statement> statements = parseFileForSkylark( "load('/foo/bar/file', 'fun_test')\n"); @@ -777,6 +854,7 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmt.getSymbols()).hasSize(1); } + @Test public void testLoadMultipleSymbols() throws Exception { List<Statement> statements = parseFileForSkylark( "load('file', 'foo', 'bar')\n"); @@ -785,36 +863,42 @@ public class ParserTest extends AbstractParserTestCase { assertThat(stmt.getSymbols()).hasSize(2); } + @Test public void testLoadSyntaxError() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("load(non_quoted, 'a')\n"); syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testLoadSyntaxError2() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("load('non_quoted', a)\n"); syntaxEvents.assertContainsEvent("syntax error"); } + @Test public void testLoadNotAtTopLevel() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("if 1: load(8)\n"); syntaxEvents.assertContainsEvent("function 'load' does not exist"); } + @Test public void testParseErrorNotComparison() throws Exception { syntaxEvents.setFailFast(false); parseFile("2 < not 3"); syntaxEvents.assertContainsEvent("syntax error at 'not'"); } + @Test public void testNotWithArithmeticOperatorsBadSyntax() throws Exception { syntaxEvents.setFailFast(false); parseFile("0 + not 0"); syntaxEvents.assertContainsEvent("syntax error at 'not'"); } + @Test public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n"); @@ -822,6 +906,7 @@ public class ParserTest extends AbstractParserTestCase { "a mandatory positional parameter must not follow an optional parameter"); } + @Test public void testKwargBeforePositionalArg() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark( @@ -830,6 +915,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("unexpected tokens after kwarg"); } + @Test public void testDuplicateKwarg() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark( @@ -838,6 +924,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("unexpected tokens after kwarg"); } + @Test public void testUnnamedStar() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark( @@ -845,6 +932,7 @@ public class ParserTest extends AbstractParserTestCase { syntaxEvents.assertContainsEvent("no star, star-star or named-only parameters (for now)"); } + @Test public void testTopLevelForFails() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("for i in []: 0\n"); @@ -852,6 +940,7 @@ public class ParserTest extends AbstractParserTestCase { "for loops are not allowed on top-level. Put it into a function"); } + @Test public void testNestedFunctionFails() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark( @@ -862,12 +951,14 @@ public class ParserTest extends AbstractParserTestCase { "nested functions are not allowed. Move the function to top-level"); } + @Test public void testIncludeFailureSkylark() throws Exception { syntaxEvents.setFailFast(false); parseFileForSkylark("include('//foo:bar')"); syntaxEvents.assertContainsEvent("function 'include' does not exist"); } + @Test public void testIncludeFailure() throws Exception { syntaxEvents.setFailFast(false); parseFile("include('nonexistent')\n"); 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 ff3c700760..3e0b0f3285 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java @@ -14,6 +14,10 @@ package com.google.devtools.build.lib.syntax; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; @@ -31,11 +35,16 @@ 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; +import org.junit.Test; +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 { @SkylarkModule(name = "Mock", doc = "") @@ -152,6 +161,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { return env; } + @Test public void testSimpleIf() throws Exception { exec(parseFileForSkylark( "def foo():\n" @@ -163,6 +173,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(0, env.lookup("a")); } + @Test public void testNestedIf() throws Exception { executeNestedIf(0, 0, env); assertEquals(0, env.lookup("x")); @@ -190,6 +201,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { exec(input, env); } + @Test public void testIfElse() throws Exception { executeIfElse("something", 2); executeIfElse("", 3); @@ -210,14 +222,17 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(expectedA, env.lookup("a")); } + @Test public void testIfElifElse_IfExecutes() throws Exception { execIfElifElse(1, 0, 1); } + @Test public void testIfElifElse_ElifExecutes() throws Exception { execIfElifElse(0, 1, 2); } + @Test public void testIfElifElse_ElseExecutes() throws Exception { execIfElifElse(0, 0, 3); } @@ -238,6 +253,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(v, env.lookup("v")); } + @Test public void testForOnList() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -252,6 +268,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @SuppressWarnings("unchecked") + @Test public void testForOnString() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -265,6 +282,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertThat((Iterable<Object>) env.lookup("s")).containsExactly("a", "b", "c").inOrder(); } + @Test public void testForAssignmentList() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -280,6 +298,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("abc", env.lookup("s")); } + @Test public void testForAssignmentDict() throws Exception { List<Statement> input = parseFileForSkylark( "def func():\n" @@ -295,6 +314,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("abc", env.lookup("s")); } + @Test public void testForNotIterable() throws Exception { env.update("mock", new Mock()); List<Statement> input = parseFileForSkylark( @@ -304,6 +324,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { checkEvalError(input, env, "type 'int' is not an iterable"); } + @Test public void testForOnDictionary() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -317,6 +338,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("abc", env.lookup("s")); } + @Test public void testForLoopReuseVariable() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -330,6 +352,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("cdcd", env.lookup("s")); } + @Test public void testNoneAssignment() throws Exception { List<Statement> input = parseFileForSkylark( "def foo(x=None):\n" @@ -342,6 +365,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(2, env.lookup("s")); } + @Test public void testJavaCalls() throws Exception { env.update("mock", new Mock()); List<Statement> input = parseFileForSkylark( @@ -350,6 +374,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(Boolean.FALSE, env.lookup("b")); } + @Test public void testJavaCallsOnSubClass() throws Exception { env.update("mock", new MockSubClass()); List<Statement> input = parseFileForSkylark( @@ -358,6 +383,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(Boolean.FALSE, env.lookup("b")); } + @Test public void testJavaCallsOnInterface() throws Exception { env.update("mock", new MockSubClass()); List<Statement> input = parseFileForSkylark( @@ -366,18 +392,21 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(Boolean.FALSE, env.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"); } + @Test public void testJavaCallsNoMethod() throws Exception { List<Statement> input = parseFileForSkylark( "s = 3.bad()"); checkEvalError(input, env, "No matching method found for bad() in int"); } + @Test public void testJavaCallsNoMethodErrorMsg() throws Exception { List<Statement> input = parseFileForSkylark( "s = 3.bad('a', 'b', 'c')"); @@ -385,6 +414,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { "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( @@ -393,17 +423,20 @@ public class SkylarkEvaluationTest extends EvaluationTest { "Multiple matching methods for method(string) in MockMultipleMethodClass"); } + @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"); } + @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"); } + @Test public void testNoJavaCallsIfClassNotAnnotated() throws Exception { env.update("mock", new MockSubClass()); List<Statement> input = parseFileForSkylark( @@ -412,6 +445,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { "No matching method found for is_empty_class_not_annotated(string) in MockSubClass"); } + @Test public void testStructAccess() throws Exception { env.update("mock", new Mock()); List<Statement> input = parseFileForSkylark( @@ -420,24 +454,28 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("a", env.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"); } + @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'"); } + @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)"); } + @Test public void testJavaFunctionReturnsNullFails() throws Exception { env.update("mock", new Mock()); List<Statement> input = parseFileForSkylark("mock.nullfunc_failing('abc', 1)", MOCK_TYPES); @@ -445,30 +483,35 @@ public class SkylarkEvaluationTest extends EvaluationTest { + " please contact Skylark developers: 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")); } + @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"); } + @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")); } + @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")); } + @Test public void testAugmentedAssignment() throws Exception { exec(parseFileForSkylark( "def f1(x):\n" @@ -479,6 +522,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(42, env.lookup("foo")); } + @Test public void testStaticDirectJavaCall() throws Exception { List<Statement> input = parseFileForSkylark( "val = Mock.value_of('8')", MOCK_TYPES); @@ -488,6 +532,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(8, env.lookup("val")); } + @Test public void testStaticDirectJavaCallMethodIsNonStatic() throws Exception { List<Statement> input = parseFileForSkylark( "val = Mock.is_empty('a')", MOCK_TYPES); @@ -496,6 +541,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { checkEvalError(input, env, "Method 'is_empty' is not static"); } + @Test public void testDictComprehensions_IterationOrder() throws Exception { List<Statement> input = parseFileForSkylark( "def foo():\n" @@ -509,11 +555,13 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("cab", env.lookup("s")); } + @Test public void testStructCreation() throws Exception { exec(parseFileForSkylark("x = struct(a = 1, b = 2)"), env); assertThat(env.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"); @@ -521,6 +569,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(2, x.getValue("b")); } + @Test public void testStructAccessingFieldsFromSkylark() throws Exception { exec(parseFileForSkylark( "x = struct(a = 1, b = 2)\n" @@ -530,12 +579,14 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(2, env.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'"); } + @Test public void testStructAccessingFieldsWithArgs() throws Exception { checkEvalError(parseFileForSkylark( "x = struct(a = 1, b = 2)\n" @@ -543,12 +594,14 @@ public class SkylarkEvaluationTest extends EvaluationTest { env, "No matching method found for a(int) in struct"); } + @Test public void testStructPosArgs() throws Exception { checkEvalError(parseFileForSkylark( "x = struct(1, b = 2)\n"), env, "struct only supports keyword arguments"); } + @Test public void testStructConcatenationFieldNames() throws Exception { exec(parseFileForSkylark( "x = struct(a = 1, b = 2)\n" @@ -558,6 +611,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(ImmutableSet.of("a", "b", "c", "d"), z.getKeys()); } + @Test public void testStructConcatenationFieldValues() throws Exception { exec(parseFileForSkylark( "x = struct(a = 1, b = 2)\n" @@ -570,6 +624,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(2, z.getValue("d")); } + @Test public void testStructConcatenationCommonFields() throws Exception { checkEvalError(parseFileForSkylark( "x = struct(a = 1, b = 2)\n" @@ -577,11 +632,13 @@ public class SkylarkEvaluationTest extends EvaluationTest { + "z = x + y\n"), env, "Cannot concat structs with common field(s): a"); } + @Test public void testDotExpressionOnNonStructObject() throws Exception { checkEvalError(parseFileForSkylark( "x = 'a'.field"), env, "Object of type 'string' has no field 'field'"); } + @Test public void testPlusEqualsOnDict() throws Exception { MethodLibrary.setupMethodEnvironment(env); exec(parseFileForSkylark( @@ -593,6 +650,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(ImmutableMap.of("a", 1, "b", 2), env.lookup("d")); } + @Test public void testDictAssignmentAsLValue() throws Exception { exec(parseFileForSkylark( "def func():\n" @@ -603,6 +661,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(ImmutableMap.of("a", 1, "b", 2), env.lookup("d")); } + @Test public void testDictAssignmentAsLValueNoSideEffects() throws Exception { MethodLibrary.setupMethodEnvironment(env); exec(parseFileForSkylark( @@ -613,6 +672,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(ImmutableMap.of("a", 1), env.lookup("d")); } + @Test public void testListIndexAsLValueAsLValue() throws Exception { checkEvalError(parseFileForSkylark( "def id(l):\n" @@ -624,6 +684,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { + "l = func()"), env, "unsupported operand type(s) for +: 'list' and 'dict'"); } + @Test public void testTopLevelDict() throws Exception { exec(parseFileForSkylark( "if 1:\n" @@ -633,6 +694,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("a", env.lookup("v")); } + @Test public void testUserFunctionKeywordArgs() throws Exception { exec(parseFileForSkylark( "def foo(a, b, c):\n" @@ -641,6 +703,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals(6, env.lookup("s")); } + @Test public void testNoneTrueFalseInSkylark() throws Exception { exec(parseFileForSkylark( "a = None\n" @@ -651,6 +714,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertFalse((Boolean) env.lookup("c")); } + @Test public void testHasattr() throws Exception { exec(parseFileForSkylark( "s = struct(a=1)\n" @@ -660,6 +724,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertFalse((Boolean) env.lookup("y")); } + @Test public void testHasattrMethods() throws Exception { env.update("mock", new Mock()); ValidationEnvironment validEnv = SkylarkModules.getValidationEnvironment(); @@ -678,6 +743,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertFalse((Boolean) env.lookup("e")); } + @Test public void testGetattr() throws Exception { exec(parseFileForSkylark( "s = struct(a='val')\n" @@ -691,6 +757,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { assertEquals("val", env.lookup("w")); } + @Test public void testGetattrNoAttr() throws Exception { checkEvalError(parseFileForSkylark( "s = struct(a='val')\n" @@ -699,17 +766,20 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @SuppressWarnings("unchecked") + @Test public void testListAnTupleConcatenationDoesNotWorkInSkylark() throws Exception { checkEvalError(parseFileForSkylark("[1, 2] + (3, 4)"), env, "cannot concatenate lists and tuples"); } + @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"); } + @Test public void testCannotConcatListInSkylarkWithDifferentGenericTypes() throws Exception { env.update("mock", new Mock()); checkEvalError(parseFileForSkylark("mock.string_list() + [1, 2]", MOCK_TYPES), env, @@ -717,17 +787,20 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @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(); } + @Test public void testFormatStringWithTuple() throws Exception { exec(parseFileForSkylark("v = '%s%s' % ('a', 1)"), env); assertEquals("a1", env.lookup("v")); } @SuppressWarnings("unchecked") + @Test public void testDirFindsClassObjectFields() throws Exception { env.update("mock", new MockClassObject()); exec(parseFileForSkylark("v = dir(mock)", MOCK_TYPES), env); @@ -735,6 +808,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @SuppressWarnings("unchecked") + @Test public void testDirFindsJavaObjectStructFieldsAndMethods() throws Exception { env.update("mock", new Mock()); exec(parseFileForSkylark("v = dir(mock)", MOCK_TYPES), env); @@ -743,6 +817,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { "struct_field", "value_of", "voidfunc").inOrder(); } + @Test public void testPrint() throws Exception { exec(parseFileForSkylark("print('hello')"), env); syntaxEvents.assertContainsEvent("hello"); @@ -752,10 +827,12 @@ public class SkylarkEvaluationTest extends EvaluationTest { syntaxEvents.assertContainsEvent("axb"); } + @Test public void testPrintBadKwargs() throws Exception { checkEvalError("print(end='x', other='y')", "unexpected keywords: '[end, other]'"); } + @Test public void testSkylarkTypes() { assertEquals(TransitiveInfoCollection.class, EvalUtils.getSkylarkType(FileConfiguredTarget.class)); @@ -768,6 +845,7 @@ public class SkylarkEvaluationTest extends EvaluationTest { @SuppressWarnings("unchecked") @Override + @Test public void testConcatLists() throws Exception { // list Object x = eval("[1,2] + [3,4]"); @@ -786,14 +864,17 @@ public class SkylarkEvaluationTest extends EvaluationTest { @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 {} @Override + @Test public void testKeywordArgs() {} } 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 23471980f9..e3ee1e1630 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 @@ -13,16 +13,26 @@ // limitations under the License. package com.google.devtools.build.lib.syntax; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +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; + import java.util.Iterator; /** * Tests for SkylarkList. */ +@RunWith(JUnit4.class) public class SkylarkListTest extends AbstractEvaluationTestCase { @Immutable @@ -43,31 +53,36 @@ public class SkylarkListTest extends AbstractEvaluationTestCase { private Environment env; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + env = new SkylarkEnvironment(syntaxEvents.collector()); env.update("lazy", list); MethodLibrary.setupMethodEnvironment(env); } + @Test public void testLazyListIndex() throws Exception { checkError("Iterator requested", "a = lazy[0]"); } + @Test public void testLazyListSize() throws Exception { checkError("Iterator requested", "a = len(lazy)"); } + @Test public void testLazyListEmpty() throws Exception { checkError("Iterator requested", "if lazy:\n a = 1"); } + @Test public void testLazyListConcat() throws Exception { exec("v = [1, 2] + lazy"); assertTrue(env.lookup("v") instanceof SkylarkList); } + @Test public void testConcatListIndex() throws Exception { exec("l = [1, 2] + [3, 4]", "e0 = l[0]", @@ -80,6 +95,7 @@ public class SkylarkListTest extends AbstractEvaluationTestCase { assertEquals(4, env.lookup("e3")); } + @Test public void testConcatListHierarchicalIndex() throws Exception { exec("l = [1] + (([2] + [3, 4]) + [5])", "e0 = l[0]", @@ -94,18 +110,21 @@ public class SkylarkListTest extends AbstractEvaluationTestCase { assertEquals(5, env.lookup("e4")); } + @Test public void testConcatListSize() throws Exception { exec("l = [1, 2] + [3, 4]", "s = len(l)"); assertEquals(4, env.lookup("s")); } + @Test public void testConcatListToString() throws Exception { exec("l = [1, 2] + [3, 4]", "s = str(l)"); assertEquals("[1, 2, 3, 4]", env.lookup("s")); } + @Test public void testConcatListNotEmpty() throws Exception { exec("l = [1, 2] + [3, 4]", "if l:", @@ -115,6 +134,7 @@ public class SkylarkListTest extends AbstractEvaluationTestCase { assertEquals(1, env.lookup("v")); } + @Test public void testConcatListEmpty() throws Exception { exec("l = [] + []", "if l:", 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 622f0440a9..48a5672934 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 @@ -13,41 +13,55 @@ // limitations under the License. package com.google.devtools.build.lib.syntax; +import static org.junit.Assert.assertEquals; +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.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; + /** * Tests for SkylarkNestedSet. */ +@RunWith(JUnit4.class) public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { private Environment env; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + env = new SkylarkEnvironment(syntaxEvents.collector()); MethodLibrary.setupMethodEnvironment(env); } + @Test public void testNsetBuilder() throws Exception { exec("n = set(order='stable')"); assertTrue(env.lookup("n") instanceof SkylarkNestedSet); } + @Test public void testNsetOrder() throws Exception { exec("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()"); assertEquals(SkylarkType.TOP, get("n").getContentType()); } + @Test public void testFunctionReturnsNset() throws Exception { exec("def func():", " n = set()", @@ -57,6 +71,7 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("a"), get("s").toCollection()); } + @Test public void testNsetTwoReferences() throws Exception { exec("def func():", " n1 = set()", @@ -68,6 +83,7 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("a"), get("n").toCollection()); } + @Test public void testNsetNestedItem() throws Exception { exec("def func():", " n1 = set()", @@ -80,11 +96,13 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("b", "a"), get("n").toCollection()); } + @Test public void testNsetNestedItemBadOrder() throws Exception { checkError("LINK_ORDER != COMPILE_ORDER", "set(['a', 'b'], order='compile') + set(['c', 'd'], order='link')"); } + @Test public void testNsetItemList() throws Exception { exec("def func():", " n = set()", @@ -94,6 +112,7 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("a", "b"), get("n").toCollection()); } + @Test public void testNsetFuncParamNoSideEffects() throws Exception { exec("def func1(n):", " n += ['b']", @@ -106,6 +125,7 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("a"), get("n").toCollection()); } + @Test public void testNsetTransitiveOrdering() throws Exception { exec("def func():", " na = set(['a'], order='compile')", @@ -117,6 +137,7 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of("b", "a", "c"), get("n").toCollection()); } + @Test public void testNsetOrdering() throws Exception { exec("def func():", " na = set()", @@ -129,22 +150,26 @@ public class SkylarkNestedSetTest extends AbstractEvaluationTestCase { assertEquals(ImmutableList.of(4, 2, 3, 5), get("n").toCollection()); } + @Test public void testNsetBadOrder() throws Exception { checkError("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]"); } + @Test public void testNsetBadCompositeItem() throws Exception { checkError("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]", "x = str(s)"); 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 49c552e83c..62b0d85425 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,11 +15,17 @@ package com.google.devtools.build.lib.syntax; import com.google.common.base.Joiner; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + /** * Tests for the validation process of Skylark files. */ +@RunWith(JUnit4.class) public class ValidationTests extends AbstractParserTestCase { + @Test public void testIncompatibleLiteralTypesStringInt() { checkError("bad variable 'a': int is incompatible with string at /some/file.txt", "def foo():\n", @@ -27,6 +33,7 @@ public class ValidationTests extends AbstractParserTestCase { " a = 1"); } + @Test public void testIncompatibleLiteralTypesDictString() { checkError("bad variable 'a': int is incompatible with dict of ints at /some/file.txt:3:3", "def foo():\n", @@ -34,6 +41,7 @@ public class ValidationTests extends AbstractParserTestCase { " a = 1"); } + @Test public void testIncompatibleLiteralTypesInIf() { checkError("bad variable 'a': int is incompatible with string at /some/file.txt", "def foo():\n", @@ -43,47 +51,56 @@ public class ValidationTests extends AbstractParserTestCase { " a = 1"); } + @Test public void testAssignmentNotValidLValue() { checkError("can only assign to variables, 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"); } + @Test public void testForIterableWithUknownArgument() throws Exception { 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"); } + @Test public void testOptionalArgument() throws Exception { checkError("type 'int' is not iterable", "def func(x=5):\n" + " 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"); } + @Test public void testTopLevelForStatement() throws Exception { checkError("'For' is not allowed as a top level statement", "for i in [1,2,3]: a = i\n"); } + @Test public void testReturnOutsideFunction() throws Exception { checkError("Return statements must be inside a function", "return 2\n"); } + @Test public void testTwoReturnTypes() throws Exception { checkError("bad return type of foo: string is incompatible with int at /some/file.txt:3:5", "def foo(x):", @@ -93,6 +110,7 @@ public class ValidationTests extends AbstractParserTestCase { " return 'a'"); } + @Test public void testTwoFunctionsWithTheSameName() throws Exception { checkError("function foo already exists", "def foo():", @@ -101,6 +119,7 @@ public class ValidationTests extends AbstractParserTestCase { " return 1"); } + @Test public void testDynamicTypeCheck() throws Exception { checkError("bad variable 'a': string is incompatible with int at /some/file.txt:2:3", "def foo():", @@ -108,6 +127,7 @@ public class ValidationTests extends AbstractParserTestCase { " a = '1'"); } + @Test public void testFunctionLocalVariable() throws Exception { checkError("name 'a' is not defined", "def func2(b):", @@ -118,6 +138,7 @@ public class ValidationTests extends AbstractParserTestCase { " func2(2)"); } + @Test public void testFunctionLocalVariableDoesNotEffectGlobalValidationEnv() throws Exception { checkError("name 'a' is not defined", "def func1():", @@ -126,6 +147,7 @@ public class ValidationTests extends AbstractParserTestCase { " b = a"); } + @Test public void testFunctionParameterDoesNotEffectGlobalValidationEnv() throws Exception { checkError("name 'a' is not defined", "def func1(a):", @@ -134,6 +156,7 @@ public class ValidationTests extends AbstractParserTestCase { " b = a"); } + @Test public void testLocalValidationEnvironmentsAreSeparated() throws Exception { parse( "def func1():\n" @@ -142,49 +165,59 @@ public class ValidationTests extends AbstractParserTestCase { + " a = 'abc'\n"); } + @Test public void testListComprehensionNotIterable() throws Exception { checkError("type 'int' is not iterable", "[i for i in 1 for j in [2]]"); } + @Test public void testListComprehensionNotIterable2() throws Exception { checkError("type 'int' is not iterable", "[i for i in [1] for j in 123]"); } + @Test public void testListIsNotComparable() { checkError("list of strings is not comparable", "['a'] > 1"); } + @Test public void testStringCompareToInt() { checkError("bad comparison: int is incompatible with string", "'a' > 1"); } + @Test public void testInOnInt() { checkError("operand 'in' only works on strings, dictionaries, " + "lists, sets or tuples, not on a(n) int", "1 in 2"); } + @Test public void testUnsupportedOperator() { checkError("unsupported operand type(s) for -: 'string' and 'int'", "'a' - 1"); } + @Test public void testBuiltinSymbolsAreReadOnly() throws Exception { checkError("Variable rule is read only", "rule = 1"); } + @Test public void testSkylarkGlobalVariablesAreReadonly() throws Exception { checkError("Variable a is read only", "a = 1\n" + "a = 2"); } + @Test public void testFunctionDefRecursion() throws Exception { checkError("function 'func' does not exist", "def func():\n" + " func()\n"); } + @Test public void testMutualRecursion() throws Exception { checkError("function 'bar' does not exist", "def foo(i):\n" @@ -194,36 +227,42 @@ public class ValidationTests extends AbstractParserTestCase { + "foo(4)"); } + @Test public void testFunctionReturnValue() { checkError("unsupported operand type(s) for +: 'int' and 'string'", "def foo(): return 1\n" + "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"); } + @Test public void testFunctionDoesNotExistInFunctionDef() { checkError("function 'foo' does not exist", "def bar(): a = foo() + 'a'\n" + "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"); } + @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"); } + @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'", @@ -231,29 +270,34 @@ public class ValidationTests extends AbstractParserTestCase { + "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"); } + @Test public void testNsetBadRightOperand() throws Exception { 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", "(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", "(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" @@ -261,62 +305,75 @@ public class ValidationTests extends AbstractParserTestCase { + " l = 'a'"); } + @Test public void testListLiteralBadTypes() throws Exception { checkError("bad list literal: int is incompatible with string at /some/file.txt:1:1", "['a', 1]"); } + @Test public void testTupleLiteralWorksForDifferentTypes() throws Exception { parse("('a', 1)"); } + @Test public void testDictLiteralBadKeyTypes() throws Exception { checkError("bad dict literal: int is incompatible with string at /some/file.txt:1:1", "{'a': 1, 1: 2}"); } + @Test public void testDictLiteralDifferentValueTypeWorks() throws Exception { parse("{'a': 1, 'b': 'c'}"); } + @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", "['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", "{'a': 1} + {1: 2}"); } + @Test public void testDictLiteralBadKeyType() throws Exception { checkError("Dict cannot contain composite type 'list of strings' as key", "{['a']: 1}"); } + @Test public void testAndTypeInfer() throws Exception { checkError("unsupported operand type(s) for +: 'string' and 'int'", "('a' and 'b') + 1"); } + @Test public void testOrTypeInfer() throws Exception { checkError("unsupported operand type(s) for +: 'string' and 'int'", "('' or 'b') + 1"); } + @Test public void testAndDifferentTypes() throws Exception { checkError("bad and operator: int is incompatible with string at /some/file.txt: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", "'ab' or 3"); } + @Test public void testOrNone() throws Exception { parse("a = None or 3"); } + @Test public void testNoneAssignment() throws Exception { parse("def func():\n" + " a = None\n" @@ -324,6 +381,7 @@ public class ValidationTests extends AbstractParserTestCase { + " 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" @@ -333,10 +391,12 @@ public class ValidationTests extends AbstractParserTestCase { + " a = 'b'\n"); } + @Test public void testDictComprehensionNotOnList() throws Exception { checkError("Dict comprehension elements must be a list", "{k : k for k in 'abc'}"); } + @Test public void testTypeInferenceForUserDefinedFunction() throws Exception { checkError("bad variable 'a': string is incompatible with int at /some/file.txt", "def func():\n" @@ -346,12 +406,14 @@ public class ValidationTests extends AbstractParserTestCase { + " a = func()\n"); } + @Test public void testCallingNonFunction() { checkError("a is not a function", "a = '1':\n" + "a()\n"); } + @Test public void testFuncallArgument() { checkError("unsupported operand type(s) for +: 'int' and 'string'", "def foo(x): return x\n" @@ -360,6 +422,7 @@ public class ValidationTests extends AbstractParserTestCase { // 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" @@ -368,6 +431,7 @@ public class ValidationTests extends AbstractParserTestCase { + " 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" @@ -375,6 +439,7 @@ public class ValidationTests extends AbstractParserTestCase { + " a = 'a'\n"); } + @Test public void testFuncReturningDictAssignmentAsLValue() throws Exception { checkError("can only assign to variables, not to 'dict([])['b']'", "def dict():\n" @@ -384,6 +449,7 @@ public class ValidationTests extends AbstractParserTestCase { + " return d\n"); } + @Test public void testListIndexAsLValue() { checkError("unsupported operand type(s) for +: 'list of ints' and 'dict of ints'", "def func():\n" @@ -392,6 +458,7 @@ public class ValidationTests extends AbstractParserTestCase { + " return l\n"); } + @Test public void testStringIndexAsLValue() { checkError("unsupported operand type(s) for +: 'string' and 'dict of ints'", "def func():\n" @@ -400,17 +467,20 @@ public class ValidationTests extends AbstractParserTestCase { + " return s\n"); } + @Test public void testEmptyLiteralGenericIsSetInLaterConcatWorks() { parse("def func():\n" + " s = {}\n" + " s['a'] = 'b'\n"); } + @Test public void testTypeIsInferredForStructs() { checkError("unsupported operand type(s) for +: 'struct' and 'string'", "(struct(a = 1) + struct(b = 1)) + 'x'"); } + @Test public void testReadOnlyWorksForSimpleBranching() { parse("if 1:\n" + " v = 'a'\n" @@ -418,6 +488,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 'b'"); } + @Test public void testReadOnlyWorksForNestedBranching() { parse("if 1:\n" + " if 0:\n" @@ -431,6 +502,7 @@ public class ValidationTests extends AbstractParserTestCase { + " 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" @@ -439,6 +511,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 1"); } + @Test public void testTypeCheckWorksForNestedBranching() { checkError("bad variable 'v': int is incompatible with string at /some/file.txt:5:5", "if 1:\n" @@ -450,6 +523,7 @@ public class ValidationTests extends AbstractParserTestCase { + " 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" @@ -459,6 +533,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 1\n"); } + @Test public void testReadOnlyWorksForDifferentLevelBranches() { checkError("Variable v is read only", "if 1:\n" @@ -467,6 +542,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 'b'\n"); } + @Test public void testReadOnlyWorksWithinSimpleBranch() { checkError("Variable v is read only", "if 1:\n" @@ -476,6 +552,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 'c'\n"); } + @Test public void testReadOnlyWorksWithinNestedBranch() { checkError("Variable v is read only", "if 1:\n" @@ -488,6 +565,7 @@ public class ValidationTests extends AbstractParserTestCase { + " v = 'd'\n"); } + @Test public void testReadOnlyWorksAfterSimpleBranch() { checkError("Variable v is read only", "if 1:\n" @@ -497,6 +575,7 @@ public class ValidationTests extends AbstractParserTestCase { + "v = 'b'"); } + @Test public void testReadOnlyWorksAfterNestedBranch() { checkError("Variable v is read only", "if 1:\n" @@ -505,6 +584,7 @@ public class ValidationTests extends AbstractParserTestCase { + "v = 'b'"); } + @Test public void testReadOnlyWorksAfterNestedBranch2() { checkError("Variable v is read only", "if 1:\n" @@ -515,29 +595,34 @@ public class ValidationTests extends AbstractParserTestCase { + "v = 'b'\n"); } + @Test public void testModulesReadOnlyInFuncDefBody() { checkError("Variable cmd_helper is read only", "def func():", " cmd_helper = set()"); } + @Test public void testBuiltinGlobalFunctionsReadOnlyInFuncDefBody() { checkError("Variable rule is read only", "def func():", " rule = 'abc'"); } + @Test public void testBuiltinGlobalFunctionsReadOnlyAsFuncDefArg() { checkError("Variable rule is read only", "def func(rule):", " return rule"); } + @Test public void testFilesModulePlusStringErrorMessage() throws Exception { checkError("unsupported operand type(s) for +: 'cmd_helper (a language module)' and 'string'", "cmd_helper += 'a'"); } + @Test public void testFunctionReturnsFunction() { parse( "def impl(ctx):", @@ -549,19 +634,23 @@ public class ValidationTests extends AbstractParserTestCase { " skylark_rule(name = name)"); } + @Test public void testTypeForBooleanLiterals() { parse("len([1, 2]) == 0 and True"); parse("len([1, 2]) == 0 and False"); } + @Test public void testLoadRelativePathOneSegment() throws Exception { parse("load('extension', 'a')\n"); } + @Test public void testLoadAbsolutePathMultipleSegments() throws Exception { parse("load('/pkg/extension', 'a')\n"); } + @Test public void testLoadRelativePathMultipleSegments() throws Exception { checkError("Path 'pkg/extension.bzl' is not valid. It should either start with " + "a slash or refer to a file in the current directory.", |