Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 1 | // Copyright 2014 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.syntax; |
| 15 | |
| 16 | import static com.google.common.truth.Truth.assertThat; |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 17 | import static org.junit.Assert.assertEquals; |
| 18 | import static org.junit.Assert.assertFalse; |
| 19 | import static org.junit.Assert.assertTrue; |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 20 | |
| 21 | import com.google.common.collect.ImmutableList; |
| 22 | import com.google.common.collect.ImmutableMap; |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 23 | import com.google.devtools.build.lib.testutil.TestMode; |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 24 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 25 | import org.junit.Test; |
| 26 | import org.junit.runner.RunWith; |
| 27 | import org.junit.runners.JUnit4; |
| 28 | |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 29 | import java.util.Arrays; |
| 30 | import java.util.Collections; |
| 31 | import java.util.List; |
| 32 | import java.util.Map; |
| 33 | |
| 34 | /** |
| 35 | * Test of evaluation behavior. (Implicitly uses lexer + parser.) |
| 36 | */ |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 37 | @RunWith(JUnit4.class) |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 38 | public class EvaluationTest extends EvaluationTestCase { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 39 | public EvaluationTest() throws Exception { |
| 40 | super.setMode(TestMode.BUILD); |
| 41 | } |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 42 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 43 | /** |
| 44 | * Creates a new instance of {@code ModalTestCase}. |
| 45 | * |
| 46 | * <p>If a test uses this method, it allows potential subclasses to run the very same test in a |
| 47 | * different mode in subclasses |
| 48 | */ |
| 49 | protected ModalTestCase newTest() { |
| 50 | return new BuildTest(); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 51 | } |
| 52 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 53 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 54 | public void testExprs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 55 | newTest() |
Francois-Rene Rideau | 0f7ba34 | 2015-08-31 16:16:21 +0000 | [diff] [blame] | 56 | .testStatement("'%sx' % 'foo' + 'bar1'", "fooxbar1") |
| 57 | .testStatement("('%sx' % 'foo') + 'bar2'", "fooxbar2") |
| 58 | .testStatement("'%sx' % ('foo' + 'bar3')", "foobar3x") |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 59 | .testStatement("123 + 456", 579) |
| 60 | .testStatement("456 - 123", 333) |
| 61 | .testStatement("8 % 3", 2) |
| 62 | .testIfErrorContains("unsupported operand type(s) for %: 'int' and 'string'", "3 % 'foo'"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 63 | } |
| 64 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 65 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 66 | public void testListExprs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 67 | newTest().testExactOrder("[1, 2, 3]", 1, 2, 3).testExactOrder("(1, 2, 3)", 1, 2, 3); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 68 | } |
| 69 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 70 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 71 | public void testStringFormatMultipleArgs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 72 | newTest().testStatement("'%sY%s' % ('X', 'Z')", "XYZ"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 73 | } |
| 74 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 75 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 76 | public void testAndOr() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 77 | new BuildTest() |
| 78 | .testStatement("8 or 9", 8) |
| 79 | .testStatement("0 or 9", 9) |
| 80 | .testStatement("8 and 9", 9) |
| 81 | .testStatement("0 and 9", 0) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 82 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 83 | .testStatement("1 and 2 or 3", 2) |
| 84 | .testStatement("0 and 2 or 3", 3) |
| 85 | .testStatement("1 and 0 or 3", 3) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 86 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 87 | .testStatement("1 or 2 and 3", 1) |
| 88 | .testStatement("0 or 2 and 3", 3) |
| 89 | .testStatement("0 or 0 and 3", 0) |
| 90 | .testStatement("1 or 0 and 3", 1) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 91 | |
Francois-Rene Rideau | 0f7ba34 | 2015-08-31 16:16:21 +0000 | [diff] [blame] | 92 | .testStatement("None and 1", Runtime.NONE) |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 93 | .testStatement("\"\" or 9", 9) |
| 94 | .testStatement("\"abc\" or 9", "abc") |
Francois-Rene Rideau | 0f7ba34 | 2015-08-31 16:16:21 +0000 | [diff] [blame] | 95 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 96 | // check that 'foo' is not evaluated |
| 97 | .testStatement("8 or foo", 8) |
| 98 | .testStatement("0 and foo", 0); |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 99 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 100 | new SkylarkTest() |
| 101 | .testIfErrorContains("name 'google' is not defined", "0 and google") |
| 102 | .testIfErrorContains("name 'google' is not defined", "8 or google"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 103 | } |
| 104 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 105 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 106 | public void testNot() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 107 | newTest().testStatement("not 1", false).testStatement("not ''", true); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 108 | } |
| 109 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 110 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 111 | public void testNotWithLogicOperators() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 112 | newTest() |
| 113 | .testStatement("not (0 and 0)", true) |
| 114 | .testStatement("not (1 or 0)", false) |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 115 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 116 | .testStatement("0 and not 0", 0) |
| 117 | .testStatement("not 0 and 0", 0) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 118 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 119 | .testStatement("1 and not 0", true) |
| 120 | .testStatement("not 0 or 0", true) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 121 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 122 | .testStatement("not 1 or 0", 0) |
| 123 | .testStatement("not 1 or 1", 1); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 124 | } |
| 125 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 126 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 127 | public void testNotWithArithmeticOperators() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 128 | newTest().testStatement("not 0 + 0", true).testStatement("not 2 - 1", false); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 129 | } |
| 130 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 131 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 132 | public void testNotWithCollections() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 133 | newTest().testStatement("not []", true).testStatement("not {'a' : 1}", false); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 134 | } |
| 135 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 136 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 137 | public void testEquality() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 138 | newTest() |
| 139 | .testStatement("1 == 1", true) |
| 140 | .testStatement("1 == 2", false) |
| 141 | .testStatement("'hello' == 'hel' + 'lo'", true) |
| 142 | .testStatement("'hello' == 'bye'", false) |
| 143 | .testStatement("None == None", true) |
| 144 | .testStatement("[1, 2] == [1, 2]", true) |
| 145 | .testStatement("[1, 2] == [2, 1]", false); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 146 | } |
| 147 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 148 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 149 | public void testInequality() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 150 | newTest() |
| 151 | .testStatement("1 != 1", false) |
| 152 | .testStatement("1 != 2", true) |
| 153 | .testStatement("'hello' != 'hel' + 'lo'", false) |
| 154 | .testStatement("'hello' != 'bye'", true) |
| 155 | .testStatement("[1, 2] != [1, 2]", false) |
| 156 | .testStatement("[1, 2] != [2, 1]", true); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 157 | } |
| 158 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 159 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 160 | public void testEqualityPrecedence() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 161 | newTest() |
| 162 | .testStatement("1 + 3 == 2 + 2", true) |
| 163 | .testStatement("not 1 == 2", true) |
| 164 | .testStatement("not 1 != 2", false) |
| 165 | .testStatement("2 and 3 == 3 or 1", true) |
| 166 | .testStatement("2 or 3 == 3 and 1", 2); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 169 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 170 | public void testLessThan() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 171 | newTest() |
| 172 | .testStatement("1 <= 1", true) |
| 173 | .testStatement("1 < 1", false) |
| 174 | .testStatement("'a' <= 'b'", true) |
| 175 | .testStatement("'c' < 'a'", false); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 176 | } |
| 177 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 178 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 179 | public void testGreaterThan() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 180 | newTest() |
| 181 | .testStatement("1 >= 1", true) |
| 182 | .testStatement("1 > 1", false) |
| 183 | .testStatement("'a' >= 'b'", false) |
| 184 | .testStatement("'c' > 'a'", true); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 185 | } |
| 186 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 187 | @Test |
Francois-Rene Rideau | 6fc5ee7 | 2015-03-12 20:55:17 +0000 | [diff] [blame] | 188 | public void testConditionalExpressions() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 189 | newTest() |
| 190 | .testStatement("1 if True else 2", 1) |
| 191 | .testStatement("1 if False else 2", 2) |
| 192 | .testStatement("1 + 2 if 3 + 4 else 5 + 6", 3); |
Francois-Rene Rideau | 6fc5ee7 | 2015-03-12 20:55:17 +0000 | [diff] [blame] | 193 | |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 194 | setFailFast(false); |
| 195 | parseExpression("1 if 2"); |
| 196 | assertContainsEvent( |
Francois-Rene Rideau | 6fc5ee7 | 2015-03-12 20:55:17 +0000 | [diff] [blame] | 197 | "missing else clause in conditional expression or semicolon before if"); |
Francois-Rene Rideau | 6fc5ee7 | 2015-03-12 20:55:17 +0000 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | @Test |
Laurent Le Brun | ac8aae8 | 2015-04-16 11:42:55 +0000 | [diff] [blame] | 201 | public void testListComparison() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 202 | newTest() |
| 203 | .testStatement("[] < [1]", true) |
| 204 | .testStatement("[1] < [1, 1]", true) |
| 205 | .testStatement("[1, 1] < [1, 2]", true) |
| 206 | .testStatement("[1, 2] < [1, 2, 3]", true) |
| 207 | .testStatement("[1, 2, 3] <= [1, 2, 3]", true) |
Laurent Le Brun | ac8aae8 | 2015-04-16 11:42:55 +0000 | [diff] [blame] | 208 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 209 | .testStatement("['a', 'b'] > ['a']", true) |
| 210 | .testStatement("['a', 'b'] >= ['a']", true) |
| 211 | .testStatement("['a', 'b'] < ['a']", false) |
| 212 | .testStatement("['a', 'b'] <= ['a']", false) |
Laurent Le Brun | ac8aae8 | 2015-04-16 11:42:55 +0000 | [diff] [blame] | 213 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 214 | .testStatement("('a', 'b') > ('a', 'b')", false) |
| 215 | .testStatement("('a', 'b') >= ('a', 'b')", true) |
| 216 | .testStatement("('a', 'b') < ('a', 'b')", false) |
| 217 | .testStatement("('a', 'b') <= ('a', 'b')", true) |
Laurent Le Brun | ac8aae8 | 2015-04-16 11:42:55 +0000 | [diff] [blame] | 218 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 219 | .testStatement("[[1, 1]] > [[1, 1], []]", false) |
Florian Weikert | f31b947 | 2015-08-04 16:36:58 +0000 | [diff] [blame] | 220 | .testStatement("[[1, 1]] < [[1, 1], []]", true); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 221 | } |
| 222 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 223 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 224 | public void testSumFunction() throws Exception { |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 225 | BaseFunction sum = new BaseFunction("sum") { |
| 226 | @Override |
| 227 | public Object call(List<Object> args, Map<String, Object> kwargs, |
| 228 | FuncallExpression ast, Environment env) { |
| 229 | int sum = 0; |
| 230 | for (Object arg : args) { |
| 231 | sum += (Integer) arg; |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 232 | } |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 233 | return sum; |
| 234 | } |
| 235 | }; |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 236 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 237 | newTest().update(sum.getName(), sum).testStatement("sum(1, 2, 3, 4, 5, 6)", 21) |
| 238 | .testStatement("sum", sum).testStatement("sum(a=1, b=2)", 0); |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 239 | } |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 240 | |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 241 | @Test |
| 242 | public void testNotCallInt() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 243 | newTest().setUp("sum = 123456").testLookup("sum", 123456) |
| 244 | .testIfExactError("'int' object is not callable", "sum(1, 2, 3, 4, 5, 6)") |
| 245 | .testStatement("sum", 123456); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 246 | } |
| 247 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 248 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 249 | public void testKeywordArgs() throws Exception { |
| 250 | |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 251 | // This function returns the map of keyword arguments passed to it. |
| 252 | BaseFunction kwargs = new BaseFunction("kwargs") { |
| 253 | @Override |
| 254 | public Object call(List<Object> args, |
| 255 | final Map<String, Object> kwargs, |
| 256 | FuncallExpression ast, |
| 257 | Environment env) { |
| 258 | return kwargs; |
| 259 | } |
| 260 | }; |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 261 | |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 262 | newTest() |
| 263 | .update(kwargs.getName(), kwargs) |
| 264 | .testEval( |
| 265 | "kwargs(foo=1, bar='bar', wiz=[1,2,3]).items()", |
| 266 | "[('bar', 'bar'), ('foo', 1), ('wiz', [1, 2, 3])]"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 267 | } |
| 268 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 269 | @Test |
Laurent Le Brun | bd71674 | 2015-04-15 11:05:03 +0000 | [diff] [blame] | 270 | public void testModulo() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 271 | newTest() |
| 272 | .testStatement("6 % 2", 0) |
| 273 | .testStatement("6 % 4", 2) |
| 274 | .testStatement("3 % 6", 3) |
| 275 | .testStatement("7 % -4", -1) |
| 276 | .testStatement("-7 % 4", 1) |
| 277 | .testStatement("-7 % -4", -3) |
| 278 | .testIfExactError("integer modulo by zero", "5 % 0"); |
Laurent Le Brun | bd71674 | 2015-04-15 11:05:03 +0000 | [diff] [blame] | 279 | } |
| 280 | |
| 281 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 282 | public void testMult() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 283 | newTest() |
| 284 | .testStatement("6 * 7", 42) |
| 285 | .testStatement("3 * 'ab'", "ababab") |
| 286 | .testStatement("0 * 'ab'", "") |
| 287 | .testStatement("'1' + '0' * 5", "100000"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 288 | } |
| 289 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 290 | @Test |
Laurent Le Brun | 8a52826 | 2015-04-15 14:23:35 +0000 | [diff] [blame] | 291 | public void testDivision() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 292 | newTest() |
| 293 | .testStatement("6 / 2", 3) |
| 294 | .testStatement("6 / 4", 1) |
| 295 | .testStatement("3 / 6", 0) |
| 296 | .testStatement("7 / -2", -4) |
| 297 | .testStatement("-7 / 2", -4) |
| 298 | .testStatement("-7 / -2", 3) |
| 299 | .testStatement("2147483647 / 2", 1073741823) |
Laurent Le Brun | 7bda87e | 2015-08-24 15:13:53 +0000 | [diff] [blame] | 300 | .testIfErrorContains("unsupported operand type(s) for /: 'string' and 'int'", "'str' / 2") |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 301 | .testIfExactError("integer division by zero", "5 / 0"); |
Laurent Le Brun | 8a52826 | 2015-04-15 14:23:35 +0000 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | @Test |
| 305 | public void testOperatorPrecedence() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 306 | newTest() |
| 307 | .testStatement("2 + 3 * 4", 14) |
| 308 | .testStatement("2 + 3 / 4", 2) |
| 309 | .testStatement("2 * 3 + 4 / -2", 4); |
Laurent Le Brun | 8a52826 | 2015-04-15 14:23:35 +0000 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 313 | public void testConcatStrings() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 314 | newTest().testStatement("'foo' + 'bar'", "foobar"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 315 | } |
| 316 | |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 317 | @SuppressWarnings("unchecked") |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 318 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 319 | public void testConcatLists() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 320 | // TODO(fwe): cannot be handled by current testing suite |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 321 | // list |
| 322 | Object x = eval("[1,2] + [3,4]"); |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 323 | assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder(); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 324 | assertEquals(Arrays.asList(1, 2, 3, 4), x); |
| 325 | assertFalse(EvalUtils.isImmutable(x)); |
| 326 | |
| 327 | // tuple |
| 328 | x = eval("(1,2) + (3,4)"); |
| 329 | assertEquals(Arrays.asList(1, 2, 3, 4), x); |
| 330 | assertTrue(EvalUtils.isImmutable(x)); |
| 331 | |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 332 | checkEvalError("can only concatenate List (not \"Tuple\") to List", |
| 333 | "(1,2) + [3,4]"); // list + tuple |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 334 | } |
| 335 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 336 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 337 | public void testListComprehensions() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 338 | newTest() |
| 339 | .testExactOrder("['foo/%s.java' % x for x in []]") |
| 340 | .testExactOrder("['foo/%s.java' % y for y in ['bar', 'wiz', 'quux']]", "foo/bar.java", |
| 341 | "foo/wiz.java", "foo/quux.java") |
| 342 | .testExactOrder("['%s/%s.java' % (z, t) " + "for z in ['foo', 'bar'] " |
| 343 | + "for t in ['baz', 'wiz', 'quux']]", |
| 344 | "foo/baz.java", |
| 345 | "foo/wiz.java", |
| 346 | "foo/quux.java", |
| 347 | "bar/baz.java", |
| 348 | "bar/wiz.java", |
| 349 | "bar/quux.java") |
| 350 | .testExactOrder("['%s/%s.java' % (b, b) " + "for a in ['foo', 'bar'] " |
| 351 | + "for b in ['baz', 'wiz', 'quux']]", |
| 352 | "baz/baz.java", |
| 353 | "wiz/wiz.java", |
| 354 | "quux/quux.java", |
| 355 | "baz/baz.java", |
| 356 | "wiz/wiz.java", |
| 357 | "quux/quux.java") |
| 358 | .testExactOrder("['%s/%s.%s' % (c, d, e) " + "for c in ['foo', 'bar'] " |
| 359 | + "for d in ['baz', 'wiz', 'quux'] " + "for e in ['java', 'cc']]", |
| 360 | "foo/baz.java", |
| 361 | "foo/baz.cc", |
| 362 | "foo/wiz.java", |
| 363 | "foo/wiz.cc", |
| 364 | "foo/quux.java", |
| 365 | "foo/quux.cc", |
| 366 | "bar/baz.java", |
| 367 | "bar/baz.cc", |
| 368 | "bar/wiz.java", |
| 369 | "bar/wiz.cc", |
| 370 | "bar/quux.java", |
| 371 | "bar/quux.cc"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 372 | } |
| 373 | |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 374 | @Test |
Laurent Le Brun | 5202166 | 2015-05-18 09:28:26 +0000 | [diff] [blame] | 375 | public void testNestedListComprehensions() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 376 | newTest().testExactOrder("li = [[1, 2], [3, 4]]\n" + "[j for i in li for j in i]", 1, 2, |
| 377 | 3, 4).testExactOrder("input = [['abc'], ['def', 'ghi']]\n" |
| 378 | + "['%s %s' % (b, c) for a in input for b in a for c in b]", |
| 379 | "abc a", |
| 380 | "abc b", |
| 381 | "abc c", |
| 382 | "def d", |
| 383 | "def e", |
| 384 | "def f", |
| 385 | "ghi g", |
| 386 | "ghi h", |
| 387 | "ghi i"); |
Laurent Le Brun | 5202166 | 2015-05-18 09:28:26 +0000 | [diff] [blame] | 388 | } |
| 389 | |
| 390 | @Test |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 391 | public void testListComprehensionsMultipleVariables() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 392 | newTest().testEval("[x + y for x, y in [(1, 2), (3, 4)]]", "[3, 7]").testEval( |
| 393 | "[z + t for (z, t) in [[1, 2], [3, 4]]]", "[3, 7]"); |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 394 | } |
| 395 | |
| 396 | @Test |
| 397 | public void testListComprehensionsMultipleVariablesFail() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 398 | newTest().testIfExactError("lvalue has length 3, but rvalue has has length 2", |
| 399 | "[x + y for x, y, z in [(1, 2), (3, 4)]]").testIfExactError( |
| 400 | "type 'int' is not a collection", "[x + y for x, y in (1, 2)]"); |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | @Test |
Laurent Le Brun | b4c5474 | 2015-05-18 13:11:05 +0000 | [diff] [blame] | 404 | public void testListComprehensionsWithFiltering() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 405 | newTest() |
| 406 | .setUp("range3 = [0, 1, 2]") |
| 407 | .testEval("[a for a in (4, None, 2, None, 1) if a != None]", "[4, 2, 1]") |
| 408 | .testEval("[b+c for b in [0, 1, 2] for c in [0, 1, 2] if b + c > 2]", "[3, 3, 4]") |
| 409 | .testEval("[d+e for d in range3 if d % 2 == 1 for e in range3]", "[1, 2, 3]") |
| 410 | .testEval("[[f,g] for f in [0, 1, 2, 3, 4] if f for g in [5, 6, 7, 8] if f * g % 12 == 0 ]", |
| 411 | "[[2, 6], [3, 8], [4, 6]]") |
| 412 | .testEval("[h for h in [4, 2, 0, 1] if h]", "[4, 2, 1]"); |
Laurent Le Brun | b4c5474 | 2015-05-18 13:11:05 +0000 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | @Test |
| 416 | public void testListComprehensionDefinitionOrder() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 417 | newTest().testIfErrorContains("name 'y' is not defined", |
Laurent Le Brun | b4c5474 | 2015-05-18 13:11:05 +0000 | [diff] [blame] | 418 | "[x for x in (1, 2) if y for y in (3, 4)]"); |
| 419 | } |
| 420 | |
| 421 | @Test |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 422 | public void testTupleDestructuring() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 423 | newTest() |
| 424 | .setUp("a, b = 1, 2") |
| 425 | .testLookup("a", 1) |
| 426 | .testLookup("b", 2) |
| 427 | .setUp("c, d = {'key1':2, 'key2':3}") |
| 428 | .testLookup("c", "key1") |
| 429 | .testLookup("d", "key2"); |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 430 | } |
| 431 | |
| 432 | @Test |
Laurent Le Brun | 2e78d61 | 2015-04-15 09:06:46 +0000 | [diff] [blame] | 433 | public void testHeterogeneousDict() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 434 | newTest().setUp("d = {'str': 1, 2: 3}", "a = d['str']", "b = d[2]").testLookup("a", 1) |
| 435 | .testLookup("b", 3); |
Laurent Le Brun | 2e78d61 | 2015-04-15 09:06:46 +0000 | [diff] [blame] | 436 | } |
| 437 | |
| 438 | @Test |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 439 | public void testRecursiveTupleDestructuring() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 440 | newTest() |
| 441 | .setUp("((a, b), (c, d)) = [(1, 2), (3, 4)]") |
| 442 | .testLookup("a", 1) |
| 443 | .testLookup("b", 2) |
| 444 | .testLookup("c", 3) |
| 445 | .testLookup("d", 4); |
Laurent Le Brun | 741824b | 2015-03-20 15:10:19 +0000 | [diff] [blame] | 446 | } |
| 447 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 448 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 449 | public void testListComprehensionModifiesGlobalEnv() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 450 | new SkylarkTest().update("x", 42).testIfExactError("ERROR 1:1: Variable x is read only", |
| 451 | "[x + 1 for x in [1,2,3]]"); |
| 452 | new BuildTest().update("x", 42).setUp("y =[x + 1 for x in [1,2,3]]") |
| 453 | .testExactOrder("y", 2, 3, 4).testLookup("x", 3); // (x is global) |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 454 | } |
| 455 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 456 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 457 | public void testDictComprehensions() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 458 | newTest() |
| 459 | .testStatement("{a : a for a in []}", Collections.emptyMap()) |
| 460 | .testStatement("{b : b for b in [1, 2]}", ImmutableMap.of(1, 1, 2, 2)) |
| 461 | .testStatement("{c : 'v_' + c for c in ['a', 'b']}", |
| 462 | ImmutableMap.of("a", "v_a", "b", "v_b")) |
| 463 | .testStatement("{'k_' + d : d for d in ['a', 'b']}", |
| 464 | ImmutableMap.of("k_a", "a", "k_b", "b")) |
| 465 | .testStatement("{'k_' + e : 'v_' + e for e in ['a', 'b']}", |
| 466 | ImmutableMap.of("k_a", "v_a", "k_b", "v_b")) |
| 467 | .testStatement("{x+y : x*y for x, y in [[2, 3]]}", ImmutableMap.of(5, 6)); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 468 | } |
| 469 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 470 | @Test |
Laurent Le Brun | 2e78d61 | 2015-04-15 09:06:46 +0000 | [diff] [blame] | 471 | public void testDictComprehensionOnNonIterable() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 472 | newTest().testIfExactError("type 'int' is not iterable", "{k : k for k in 3}"); |
Laurent Le Brun | 2e78d61 | 2015-04-15 09:06:46 +0000 | [diff] [blame] | 473 | } |
| 474 | |
| 475 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 476 | public void testDictComprehensions_MultipleKey() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 477 | newTest().testStatement("{x : x for x in [1, 2, 1]}", ImmutableMap.of(1, 1, 2, 2)) |
| 478 | .testStatement("{y : y for y in ['ab', 'c', 'a' + 'b']}", |
| 479 | ImmutableMap.of("ab", "ab", "c", "c")); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 480 | } |
| 481 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 482 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 483 | public void testDictComprehensions_ToString() throws Exception { |
Francois-Rene Rideau | 5f3e30c | 2015-04-10 19:08:39 +0000 | [diff] [blame] | 484 | assertEquals("{x: x for x in [1, 2]}", |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame^] | 485 | parseExpression("{x : x for x in [1, 2]}").toString()); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 486 | assertEquals("{x + 'a': x for x in [1, 2]}", |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame^] | 487 | parseExpression("{x + 'a' : x for x in [1, 2]}").toString()); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 488 | } |
| 489 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 490 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 491 | public void testListConcatenation() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 492 | newTest() |
| 493 | .testStatement("[1, 2] + [3, 4]", Arrays.asList(1, 2, 3, 4)) |
| 494 | .testStatement("(1, 2) + (3, 4)", ImmutableList.of(1, 2, 3, 4)) |
| 495 | .testIfExactError("can only concatenate Tuple (not \"List\") to Tuple", "[1, 2] + (3, 4)") |
| 496 | .testIfExactError("can only concatenate List (not \"Tuple\") to List", "(1, 2) + [3, 4]"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 497 | } |
| 498 | |
Greg Estren | b3dece0 | 2015-05-14 17:18:41 +0000 | [diff] [blame] | 499 | @SuppressWarnings("unchecked") |
| 500 | @Test |
| 501 | public void testSelectorListConcatenation() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 502 | // TODO(fwe): cannot be handled by current testing suite |
Greg Estren | b3dece0 | 2015-05-14 17:18:41 +0000 | [diff] [blame] | 503 | SelectorList x = (SelectorList) eval("select({'foo': ['FOO'], 'bar': ['BAR']}) + []"); |
| 504 | List<Object> elements = x.getElements(); |
| 505 | assertThat(elements.size()).isEqualTo(2); |
| 506 | assertThat(elements.get(0)).isInstanceOf(SelectorValue.class); |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 507 | assertThat((Iterable<Object>) elements.get(1)).isEmpty(); |
Greg Estren | b3dece0 | 2015-05-14 17:18:41 +0000 | [diff] [blame] | 508 | } |
| 509 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 510 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 511 | public void testListComprehensionFailsOnNonSequence() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 512 | newTest().testIfErrorContains("type 'int' is not iterable", "[x + 1 for x in 123]"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 513 | } |
| 514 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 515 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 516 | public void testListComprehensionOnString() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 517 | newTest().testExactOrder("[x for x in 'abc']", "a", "b", "c"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 518 | } |
| 519 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 520 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 521 | public void testInvalidAssignment() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 522 | newTest().testIfErrorContains( |
| 523 | "can only assign to variables and tuples, not to 'x + 1'", "x + 1 = 2"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 524 | } |
| 525 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 526 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 527 | public void testListComprehensionOnDictionary() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 528 | newTest().testExactOrder("val = ['var_' + n for n in {'a':1,'b':2}] ; val", "var_a", "var_b"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 529 | } |
| 530 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 531 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 532 | public void testListComprehensionOnDictionaryCompositeExpression() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 533 | new BuildTest() |
| 534 | .setUp("d = {1:'a',2:'b'}", "l = [d[x] for x in d]") |
| 535 | .testLookup("l", ImmutableList.of("a", "b")); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 536 | } |
| 537 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 538 | @Test |
Laurent Le Brun | ab0ca1a | 2015-03-31 17:13:25 +0000 | [diff] [blame] | 539 | public void testInOperator() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 540 | newTest() |
| 541 | .testStatement("'b' in ['a', 'b']", Boolean.TRUE) |
| 542 | .testStatement("'c' in ['a', 'b']", Boolean.FALSE) |
| 543 | .testStatement("'b' in ('a', 'b')", Boolean.TRUE) |
| 544 | .testStatement("'c' in ('a', 'b')", Boolean.FALSE) |
| 545 | .testStatement("'b' in {'a' : 1, 'b' : 2}", Boolean.TRUE) |
| 546 | .testStatement("'c' in {'a' : 1, 'b' : 2}", Boolean.FALSE) |
| 547 | .testStatement("1 in {'a' : 1, 'b' : 2}", Boolean.FALSE) |
| 548 | .testStatement("'b' in 'abc'", Boolean.TRUE) |
| 549 | .testStatement("'d' in 'abc'", Boolean.FALSE); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 550 | } |
| 551 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 552 | @Test |
Laurent Le Brun | e3f4ed7 | 2015-05-08 14:47:26 +0000 | [diff] [blame] | 553 | public void testNotInOperator() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 554 | newTest() |
| 555 | .testStatement("'b' not in ['a', 'b']", Boolean.FALSE) |
| 556 | .testStatement("'c' not in ['a', 'b']", Boolean.TRUE) |
| 557 | .testStatement("'b' not in ('a', 'b')", Boolean.FALSE) |
| 558 | .testStatement("'c' not in ('a', 'b')", Boolean.TRUE) |
| 559 | .testStatement("'b' not in {'a' : 1, 'b' : 2}", Boolean.FALSE) |
| 560 | .testStatement("'c' not in {'a' : 1, 'b' : 2}", Boolean.TRUE) |
| 561 | .testStatement("1 not in {'a' : 1, 'b' : 2}", Boolean.TRUE) |
| 562 | .testStatement("'b' not in 'abc'", Boolean.FALSE) |
| 563 | .testStatement("'d' not in 'abc'", Boolean.TRUE); |
Laurent Le Brun | e3f4ed7 | 2015-05-08 14:47:26 +0000 | [diff] [blame] | 564 | } |
| 565 | |
| 566 | @Test |
Laurent Le Brun | ab0ca1a | 2015-03-31 17:13:25 +0000 | [diff] [blame] | 567 | public void testInFail() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 568 | newTest() |
| 569 | .testIfExactError( |
| 570 | "in operator only works on strings if the left operand is also a string", "1 in '123'") |
| 571 | .testIfExactError( |
| 572 | "in operator only works on lists, tuples, sets, dicts and strings", "'a' in 1"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 573 | } |
| 574 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 575 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 576 | public void testInCompositeForPrecedence() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 577 | newTest().testStatement("not 'a' in ['a'] or 0", 0); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 578 | } |
| 579 | |
| 580 | private Object createObjWithStr() { |
| 581 | return new Object() { |
| 582 | @Override |
| 583 | public String toString() { |
| 584 | return "str marker"; |
| 585 | } |
| 586 | }; |
| 587 | } |
| 588 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 589 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 590 | public void testPercOnObject() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 591 | newTest().update("obj", createObjWithStr()).testStatement("'%s' % obj", "str marker"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 592 | } |
| 593 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 594 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 595 | public void testPercOnObjectList() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 596 | newTest().update("obj", createObjWithStr()).testStatement("'%s %s' % (obj, obj)", |
| 597 | "str marker str marker"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 598 | } |
| 599 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 600 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 601 | public void testPercOnObjectInvalidFormat() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 602 | newTest().update("obj", createObjWithStr()).testIfExactError( |
| 603 | "invalid argument str marker for format pattern %d", "'%d' % obj"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 604 | } |
| 605 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 606 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 607 | public void testDictKeys() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 608 | newTest().testExactOrder("v = {'a': 1}.keys() + ['b', 'c'] ; v", "a", "b", "c"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 609 | } |
| 610 | |
Han-Wen Nienhuys | ccf19ea | 2015-02-27 15:53:24 +0000 | [diff] [blame] | 611 | @Test |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 612 | public void testDictKeysTooManyArgs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 613 | newTest().testIfExactError( |
| 614 | "too many (2) positional arguments in call to keys(self: dict)", "{'a': 1}.keys('abc')"); |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 615 | } |
| 616 | |
| 617 | @Test |
| 618 | public void testDictKeysTooManyKeyArgs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 619 | newTest().testIfExactError("unexpected keyword 'arg' in call to keys(self: dict)", |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 620 | "{'a': 1}.keys(arg='abc')"); |
| 621 | } |
| 622 | |
| 623 | @Test |
| 624 | public void testDictKeysDuplicateKeyArgs() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 625 | newTest().testIfExactError("duplicate keywords 'arg', 'k' in call to keys", |
Francois-Rene Rideau | 76023b9 | 2015-04-17 15:31:59 +0000 | [diff] [blame] | 626 | "{'a': 1}.keys(arg='abc', arg='def', k=1, k=2)"); |
| 627 | } |
| 628 | |
| 629 | @Test |
| 630 | public void testArgBothPosKey() throws Exception { |
Florian Weikert | 28da365 | 2015-07-01 14:52:30 +0000 | [diff] [blame] | 631 | newTest().testIfErrorContains( |
| 632 | "arguments 'old', 'new' passed both by position and by name " |
Francois-Rene Rideau | 537a90b | 2015-04-22 06:47:31 +0000 | [diff] [blame] | 633 | + "in call to replace(self: string, ", |
| 634 | "'banana'.replace('a', 'o', 3, old='a', new=4)"); |
Ulf Adams | 89f012d | 2015-02-26 13:39:28 +0000 | [diff] [blame] | 635 | } |
| 636 | } |