blob: 3451238e01c8db07a6e1829e0ba42b9da02af279 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Ulf Adams89f012d2015-02-26 13:39:28 +00002//
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.
14package com.google.devtools.build.lib.syntax;
15
16import static com.google.common.truth.Truth.assertThat;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000017import static org.junit.Assert.assertEquals;
18import static org.junit.Assert.assertNotNull;
Ulf Adams89f012d2015-02-26 13:39:28 +000019
Ulf Adams89f012d2015-02-26 13:39:28 +000020import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000021import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
Ulf Adams89f012d2015-02-26 13:39:28 +000022
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000023import org.junit.Test;
24import org.junit.runner.RunWith;
25import org.junit.runners.JUnit4;
26
Ulf Adams89f012d2015-02-26 13:39:28 +000027import java.util.ArrayList;
28import java.util.List;
29import java.util.Map;
30
31/**
32 * A test class for functions and scoping.
33 */
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000034@RunWith(JUnit4.class)
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000035public class FunctionTest extends EvaluationTestCase {
Ulf Adams89f012d2015-02-26 13:39:28 +000036
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000037 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000038 public void testFunctionDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000039 eval("def func(a,b,c):",
40 " a = 1",
41 " b = a\n");
42 UserDefinedFunction stmt = (UserDefinedFunction) lookup("func");
Ulf Adams89f012d2015-02-26 13:39:28 +000043 assertNotNull(stmt);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000044 assertThat(stmt.getName()).isEqualTo("func");
45 assertThat(stmt.getFunctionSignature().getSignature().getShape().getMandatoryPositionals())
46 .isEqualTo(3);
Ulf Adams89f012d2015-02-26 13:39:28 +000047 assertThat(stmt.getStatements()).hasSize(2);
48 }
49
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000050 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000051 public void testFunctionDefDuplicateArguments() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000052 setFailFast(false);
53 parseFile("def func(a,b,a):",
54 " a = 1\n");
Ulf Adamsc708f962015-10-22 12:02:28 +000055 assertContainsError("duplicate parameter name in function definition");
Ulf Adams89f012d2015-02-26 13:39:28 +000056 }
57
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000058 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000059 public void testFunctionDefCallOuterFunc() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000060 List<Object> params = new ArrayList<>();
61 createOuterFunction(params);
62 eval("def func(a):",
63 " outer_func(a)",
64 "func(1)",
65 "func(2)");
Ulf Adams89f012d2015-02-26 13:39:28 +000066 assertThat(params).containsExactly(1, 2).inOrder();
67 }
68
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000069 private void createOuterFunction(final List<Object> params) throws Exception {
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +000070 BaseFunction outerFunc = new BaseFunction("outer_func") {
Ulf Adams89f012d2015-02-26 13:39:28 +000071 @Override
72 public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
73 Environment env) throws EvalException, InterruptedException {
74 params.addAll(args);
Francois-Rene Rideau0f7ba342015-08-31 16:16:21 +000075 return Runtime.NONE;
Ulf Adams89f012d2015-02-26 13:39:28 +000076 }
77 };
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000078 update("outer_func", outerFunc);
Ulf Adams89f012d2015-02-26 13:39:28 +000079 }
80
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000081 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000082 public void testFunctionDefNoEffectOutsideScope() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000083 update("a", 1);
84 eval("def func():",
85 " a = 2",
86 "func()\n");
87 assertEquals(1, lookup("a"));
Ulf Adams89f012d2015-02-26 13:39:28 +000088 }
89
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000090 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000091 public void testFunctionDefGlobalVaribleReadInFunction() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000092 eval("a = 1",
93 "def func():",
94 " b = a",
95 " return b",
96 "c = func()\n");
97 assertEquals(1, lookup("c"));
Ulf Adams89f012d2015-02-26 13:39:28 +000098 }
99
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000100 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000101 public void testFunctionDefLocalGlobalScope() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000102 eval("a = 1",
103 "def func():",
104 " a = 2",
105 " b = a",
106 " return b",
107 "c = func()\n");
108 assertEquals(2, lookup("c"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000109 }
110
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000111 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000112 public void testFunctionDefLocalVariableReferencedBeforeAssignment() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000113 checkEvalErrorContains("Variable 'a' is referenced before assignment.",
114 "a = 1",
115 "def func():",
116 " b = a",
117 " a = 2",
118 " return b",
119 "c = func()\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000120 }
121
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000122 @Test
Jon Brandvein83e3acb2016-08-11 18:53:26 +0000123 public void testFunctionDefLocalVariableReferencedInCallBeforeAssignment() throws Exception {
124 checkEvalErrorContains("Variable 'a' is referenced before assignment.",
125 "def dummy(x):",
126 " pass",
127 "a = 1",
128 "def func():",
129 " dummy(a)",
130 " a = 2",
131 "func()\n");
132 }
133
134 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000135 public void testFunctionDefLocalVariableReferencedAfterAssignment() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000136 eval("a = 1",
137 "def func():",
138 " a = 2",
139 " b = a",
140 " a = 3",
141 " return b",
142 "c = func()\n");
143 assertEquals(2, lookup("c"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000144 }
145
146 @SuppressWarnings("unchecked")
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000147 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000148 public void testSkylarkGlobalComprehensionIsAllowed() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000149 eval("a = [i for i in [1, 2, 3]]\n");
150 assertThat((Iterable<Object>) lookup("a")).containsExactly(1, 2, 3).inOrder();
Ulf Adams89f012d2015-02-26 13:39:28 +0000151 }
152
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000153 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000154 public void testFunctionReturn() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000155 eval("def func():",
156 " return 2",
157 "b = func()\n");
158 assertEquals(2, lookup("b"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000159 }
160
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000161 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000162 public void testFunctionReturnFromALoop() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000163 eval("def func():",
164 " for i in [1, 2, 3, 4, 5]:",
165 " return i",
166 "b = func()\n");
167 assertEquals(1, lookup("b"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000168 }
169
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000170 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000171 public void testFunctionExecutesProperly() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000172 eval("def func(a):",
173 " b = 1",
174 " if a:",
175 " b = 2",
176 " return b",
177 "c = func(0)",
178 "d = func(1)\n");
179 assertEquals(1, lookup("c"));
180 assertEquals(2, lookup("d"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000181 }
182
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000183 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000184 public void testFunctionCallFromFunction() throws Exception {
185 final List<Object> params = new ArrayList<>();
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000186 createOuterFunction(params);
187 eval("def func2(a):",
188 " outer_func(a)",
189 "def func1(b):",
190 " func2(b)",
191 "func1(1)",
192 "func1(2)\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000193 assertThat(params).containsExactly(1, 2).inOrder();
194 }
195
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000196 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000197 public void testFunctionCallFromFunctionReadGlobalVar() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000198 eval("a = 1",
199 "def func2():",
200 " return a",
201 "def func1():",
202 " return func2()",
203 "b = func1()\n");
204 assertEquals(1, lookup("b"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000205 }
206
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000207 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000208 public void testSingleLineFunction() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000209 eval("def func(): return 'a'",
210 "s = func()\n");
211 assertEquals("a", lookup("s"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000212 }
213
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000214 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000215 public void testFunctionReturnsDictionary() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000216 eval("def func(): return {'a' : 1}",
217 "d = func()",
218 "a = d['a']\n");
219 assertEquals(1, lookup("a"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000220 }
221
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000222 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000223 public void testFunctionReturnsList() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000224 eval("def func(): return [1, 2, 3]",
225 "d = func()",
226 "a = d[1]\n");
227 assertEquals(2, lookup("a"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000228 }
229
230 @SuppressWarnings("unchecked")
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000231 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000232 public void testFunctionListArgumentsAreImmutable() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000233 eval("l = [1]",
234 "def func(l):",
235 " l += [2]",
236 "func(l)");
237 assertThat((Iterable<Object>) lookup("l")).containsExactly(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000238 }
239
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000240 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000241 public void testFunctionDictArgumentsAreImmutable() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000242 eval("d = {'a' : 1}",
243 "def func(d):",
244 " d += {'a' : 2}",
245 "func(d)");
246 assertEquals(ImmutableMap.of("a", 1), lookup("d"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000247 }
248
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000249 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000250 public void testFunctionNameAliasing() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000251 eval("def func(a):",
252 " return a + 1",
253 "alias = func",
254 "r = alias(1)");
255 assertEquals(2, lookup("r"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000256 }
257
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000258 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000259 public void testCallingFunctionsWithMixedModeArgs() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000260 eval("def func(a, b, c):",
261 " return a + b + c",
262 "v = func(1, c = 2, b = 3)");
263 assertEquals(6, lookup("v"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000264 }
265
266 private String functionWithOptionalArgs() {
267 return "def func(a, b = None, c = None):\n"
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000268 + " r = a + 'a'\n"
269 + " if b:\n"
270 + " r += 'b'\n"
271 + " if c:\n"
272 + " r += 'c'\n"
273 + " return r\n";
Ulf Adams89f012d2015-02-26 13:39:28 +0000274 }
275
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000276 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000277 public void testWhichOptionalArgsAreDefinedForFunctions() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000278 eval(functionWithOptionalArgs(),
279 "v1 = func('1', 1, 1)",
280 "v2 = func(b = 2, a = '2', c = 2)",
281 "v3 = func('3')",
282 "v4 = func('4', c = 1)\n");
283 assertEquals("1abc", lookup("v1"));
284 assertEquals("2abc", lookup("v2"));
285 assertEquals("3a", lookup("v3"));
286 assertEquals("4ac", lookup("v4"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000287 }
288
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000289 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000290 public void testDefaultArguments() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000291 eval("def func(a, b = 'b', c = 'c'):",
292 " return a + b + c",
293 "v1 = func('a', 'x', 'y')",
294 "v2 = func(b = 'x', a = 'a', c = 'y')",
295 "v3 = func('a')",
296 "v4 = func('a', c = 'y')\n");
297 assertEquals("axy", lookup("v1"));
298 assertEquals("axy", lookup("v2"));
299 assertEquals("abc", lookup("v3"));
300 assertEquals("aby", lookup("v4"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000301 }
302
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000303 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000304 public void testDefaultArgumentsInsufficientArgNum() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000305 checkEvalError("insufficient arguments received by func(a, b = \"b\", c = \"c\") "
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +0000306 + "(got 0, expected at least 1)",
Ulf Adams89f012d2015-02-26 13:39:28 +0000307 "def func(a, b = 'b', c = 'c'):",
308 " return a + b + c",
309 "func()");
310 }
311
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000312 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000313 public void testKwargs() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000314 eval("def foo(a, b = 'b', *, c, d = 'd'):",
315 " return a + b + c + d",
316 "args = {'a': 'x', 'c': 'z'}",
317 "v1 = foo(**args)",
318 "v2 = foo('x', c = 'c', d = 'e', **{'b': 'y'})",
319 "v3 = foo(c = 'z', a = 'x', **{'b': 'y', 'd': 'f'})");
320 assertEquals("xbzd", lookup("v1"));
321 assertEquals("xyce", lookup("v2"));
322 assertEquals("xyzf", lookup("v3"));
323 UserDefinedFunction foo = (UserDefinedFunction) lookup("foo");
Francois-Rene Rideau012f7892015-03-31 17:27:01 +0000324 assertEquals("foo(a, b = \"b\", *, c, d = \"d\")", foo.toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000325 }
326
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000327 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000328 public void testKwargsBadKey() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000329 checkEvalError("Keywords must be strings, not int",
330 "def func(a, b): return a + b",
Ulf Adams89f012d2015-02-26 13:39:28 +0000331 "func('a', **{3: 1})");
332 }
333
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000334 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000335 public void testKwargsIsNotDict() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000336 checkEvalError("Argument after ** must be a dictionary, not int",
337 "def func(a, b): return a + b",
Ulf Adams89f012d2015-02-26 13:39:28 +0000338 "func('a', **42)");
339 }
340
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000341 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000342 public void testKwargsCollision() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000343 checkEvalError("argument 'b' passed both by position and by name in call to func(a, b)",
344 "def func(a, b): return a + b",
Ulf Adams89f012d2015-02-26 13:39:28 +0000345 "func('a', 'b', **{'b': 'foo'})");
346 }
347
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000348 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000349 public void testKwargsCollisionWithNamed() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000350 checkEvalError("duplicate keyword 'b' in call to func",
351 "def func(a, b): return a + b",
Ulf Adams89f012d2015-02-26 13:39:28 +0000352 "func('a', b = 'b', **{'b': 'foo'})");
353 }
354
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000355 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000356 public void testDefaultArguments2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000357 eval("a = 2",
358 "def foo(x=a): return x",
359 "def bar():",
360 " a = 3",
361 " return foo()",
362 "v = bar()\n");
363 assertEquals(2, lookup("v"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000364 }
365
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000366 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000367 public void testMixingPositionalOptional() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000368 eval("def f(name, value = '', optional = ''): return value",
369 "v = f('name', 'value')\n");
370 assertEquals("value", lookup("v"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000371 }
372
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000373 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000374 public void testStarArg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000375 eval("def f(name, value = '1', optional = '2'): return name + value + optional",
376 "v1 = f(*['name', 'value'])",
377 "v2 = f('0', *['name', 'value'])",
378 "v3 = f('0', *['b'], optional = '3')",
379 "v4 = f(*[],name='a')\n");
380 assertEquals("namevalue2", lookup("v1"));
381 assertEquals("0namevalue", lookup("v2"));
382 assertEquals("0b3", lookup("v3"));
383 assertEquals("a12", lookup("v4"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000384 }
385
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +0000386 @Test
387 public void testStarParam() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000388 eval("def f(name, value = '1', *rest, mandatory, optional = '2'):",
389 " r = name + value + mandatory + optional + '|'",
390 " for x in rest: r += x",
391 " return r",
392 "v1 = f('a', 'b', mandatory = 'z')",
393 "v2 = f('a', 'b', 'c', 'd', mandatory = 'z')",
394 "v3 = f('a', *['b', 'c', 'd'], mandatory = 'y', optional = 'z')",
395 "v4 = f(*['a'], **{'value': 'b', 'mandatory': 'c'})",
396 "v5 = f('a', 'b', 'c', *['d', 'e'], mandatory = 'f', **{'optional': 'g'})\n");
397 assertEquals("abz2|", lookup("v1"));
398 assertEquals("abz2|cd", lookup("v2"));
399 assertEquals("abyz|cd", lookup("v3"));
400 assertEquals("abc2|", lookup("v4"));
401 assertEquals("abfg|cde", lookup("v5"));
Ulf Adams89f012d2015-02-26 13:39:28 +0000402 }
403}