name:
src/test/java/io/protobase/f7/transpiler/TranspilationVisitorTest.java
-rw-r--r--
24952
1package io.protobase.f7.transpiler;
2
3import com.google.common.collect.ImmutableList;
4import io.protobase.f7.antlr.F7Lexer;
5import io.protobase.f7.antlr.F7Parser;
6import io.protobase.f7.errors.DivException;
7import io.protobase.f7.errors.F7Exception;
8import io.protobase.f7.errors.NAException;
9import io.protobase.f7.errors.NameException;
10import io.protobase.f7.errors.NullException;
11import io.protobase.f7.errors.NumException;
12import io.protobase.f7.errors.ParseException;
13import io.protobase.f7.errors.RefException;
14import io.protobase.f7.errors.ValueException;
15import io.protobase.f7.formulas.FormulaName;
16import io.protobase.f7.models.BinaryOperationNode;
17import io.protobase.f7.models.CellQuery;
18import io.protobase.f7.models.ErrorNode;
19import io.protobase.f7.models.FormulaNode;
20import io.protobase.f7.models.ListNode;
21import io.protobase.f7.models.Node;
22import io.protobase.f7.models.NumberNode;
23import io.protobase.f7.models.RangeNode;
24import io.protobase.f7.models.RangeQueryNode;
25import io.protobase.f7.models.TextNode;
26import io.protobase.f7.models.UnaryMinusOperationNode;
27import io.protobase.f7.models.UnaryPercentOperationNode;
28import io.protobase.f7.models.VariableNode;
29import io.protobase.f7.spreadsheet.ParseErrorListener;
30import org.antlr.v4.runtime.CharStreams;
31import org.antlr.v4.runtime.CommonTokenStream;
32import org.antlr.v4.runtime.misc.ParseCancellationException;
33import org.junit.Test;
34
35import java.io.ByteArrayInputStream;
36import java.io.IOException;
37import java.nio.charset.StandardCharsets;
38
39import static com.google.common.truth.Truth.assertThat;
40
41public class TranspilationVisitorTest {
42 private static final TranspilationVisitor visitor = new TranspilationVisitor();
43
44 @Test
45 public void numberNode() {
46 run("10.0e2", new NumberNode(10.0e2));
47 run("10.0e-2", new NumberNode(10.0e-2));
48 run("81739821", new NumberNode(81739821.0));
49 run("1.00000000001", new NumberNode(1.00000000001));
50 run("199", new NumberNode(199.0));
51 run("201", new NumberNode(201.0));
52 run("9187312.222", new NumberNode(9187312.222));
53 }
54
55 @Test
56 public void textNode() {
57 run("\"Hello Friend!\"", new TextNode("Hello Friend!"));
58 run("\"\"", new TextNode(""));
59 }
60
61 @Test
62 public void listNode() {
63 run("{1.1}", ListNode.builder()
64 .value(0, 0, new NumberNode(1.1))
65 .build());
66 run("{1.1, 4.4, \"Third\"}", ListNode.builder()
67 .value(0, 0, new NumberNode(1.1))
68 .value(1, 0, new NumberNode(4.4))
69 .value(2, 0, new TextNode("Third"))
70 .build());
71 }
72
73 @Test
74 public void listNode_nested() {
75 run("{1, {2}, {{3}}}", ListNode.builder()
76 .value(0, 0, new NumberNode(1.0))
77 .value(1, 0, new NumberNode(2.0))
78 .value(2, 0, new NumberNode(3.0))
79 .build());
80 run("{1, {2}, {{3}}, {4}, {{{{{5}}}}}}", ListNode.builder()
81 .value(0, 0, new NumberNode(1.0))
82 .value(1, 0, new NumberNode(2.0))
83 .value(2, 0, new NumberNode(3.0))
84 .value(3, 0, new NumberNode(4.0))
85 .value(4, 0, new NumberNode(5.0))
86 .build());
87 run("{}", new ErrorNode(new RefException()));
88 run("{1, {}}", ListNode.builder()
89 .value(0, 0, new NumberNode(1.0))
90 .value(1, 0, new ErrorNode(new RefException()))
91 .build());
92 run("{1, {}, {{}}}", ListNode.builder()
93 .value(0, 0, new NumberNode(1.0))
94 .value(1, 0, new ErrorNode(new RefException()))
95 .value(2, 0, new ErrorNode(new RefException()))
96 .build());
97 run("{1, {2}, {{3}}, {{{4, 5, 6, {}, {8}}}}}", ListNode.builder()
98 .value(0, 0, new NumberNode(1.0))
99 .value(1, 0, new NumberNode(2.0))
100 .value(2, 0, new NumberNode(3.0))
101 .value(3, 0, new NumberNode(4.0))
102 .value(4, 0, new NumberNode(5.0))
103 .value(5, 0, new NumberNode(6.0))
104 .value(6, 0, new ErrorNode(new RefException()))
105 .value(7, 0, new NumberNode(8.0))
106 .build());
107 run("{{{{{{1}}}}}}", ListNode.builder()
108 .value(0, 0, new NumberNode(1.0))
109 .build());
110 run("{{10, {}, {{}}}}", ListNode.builder()
111 .value(0, 0, new NumberNode(10.0))
112 .value(1, 0, new ErrorNode(new RefException()))
113 .value(2, 0, new ErrorNode(new RefException()))
114 .build());
115 }
116
117 @Test
118 public void listNode_multiDimensional() {
119 run("{1,2,3}", ListNode.builder()
120 .value(0, 0, new NumberNode(1.0))
121 .value(1, 0, new NumberNode(2.0))
122 .value(2, 0, new NumberNode(3.0))
123 .build());
124
125 run("{{1;2;3},{4;5;6}}", ListNode.builder()
126 .value(0, 0, new NumberNode(1.0))
127 .value(0, 1, new NumberNode(2.0))
128 .value(0, 2, new NumberNode(3.0))
129 .value(1, 0, new NumberNode(4.0))
130 .value(1, 1, new NumberNode(5.0))
131 .value(1, 2, new NumberNode(6.0))
132 .build());
133
134 run("{{1,2,3};{4,5,6}}", ListNode.builder()
135 .value(0, 0, new NumberNode(1.0))
136 .value(1, 0, new NumberNode(2.0))
137 .value(2, 0, new NumberNode(3.0))
138 .value(0, 1, new NumberNode(4.0))
139 .value(1, 1, new NumberNode(5.0))
140 .value(2, 1, new NumberNode(6.0))
141 .build());
142
143 run("{{1,2,3},{4,5,6}}", ListNode.builder()
144 .value(0, 0, new NumberNode(1.0))
145 .value(1, 0, new NumberNode(2.0))
146 .value(2, 0, new NumberNode(3.0))
147 .value(3, 0, new NumberNode(4.0))
148 .value(4, 0, new NumberNode(5.0))
149 .value(5, 0, new NumberNode(6.0))
150 .build());
151
152 run("{{1;2;3}}", ListNode.builder()
153 .value(0, 0, new NumberNode(1.0))
154 .value(0, 1, new NumberNode(2.0))
155 .value(0, 2, new NumberNode(3.0))
156 .build());
157
158 run("{{1,2;3,4}}", ListNode.builder()
159 .value(0, 0, new NumberNode(1.0))
160 .value(1, 0, new NumberNode(2.0))
161 .value(0, 1, new NumberNode(3.0))
162 .value(1, 1, new NumberNode(4.0))
163 .build());
164
165 run("{1,2;3,4}", ListNode.builder()
166 .value(0, 0, new NumberNode(1.0))
167 .value(1, 0, new NumberNode(2.0))
168 .value(0, 1, new NumberNode(3.0))
169 .value(1, 1, new NumberNode(4.0))
170 .build());
171
172 run("{1;{2;3;4}}", ListNode.builder()
173 .value(0, 0, new NumberNode(1.0))
174 .value(0, 1, new NumberNode(2.0))
175 .value(0, 2, new NumberNode(3.0))
176 .value(0, 3, new NumberNode(4.0))
177 .build());
178
179 run("{{{1.1, 2.1, 3.1};{1.2, 2.2, 3.2}};{{1.3, 2.3, 3.3};{1.4, 2.4, 3.4}};{{1.5, 2.5, 3.5};{1.6, 2.6, 3.6}}}", ListNode.builder()
180 .value(0, 0, new NumberNode(1.1))
181 .value(1, 0, new NumberNode(2.1))
182 .value(2, 0, new NumberNode(3.1))
183 .value(0, 1, new NumberNode(1.2))
184 .value(1, 1, new NumberNode(2.2))
185 .value(2, 1, new NumberNode(3.2))
186 .value(0, 2, new NumberNode(1.3))
187 .value(1, 2, new NumberNode(2.3))
188 .value(2, 2, new NumberNode(3.3))
189 .value(0, 3, new NumberNode(1.4))
190 .value(1, 3, new NumberNode(2.4))
191 .value(2, 3, new NumberNode(3.4))
192 .value(0, 4, new NumberNode(1.5))
193 .value(1, 4, new NumberNode(2.5))
194 .value(2, 4, new NumberNode(3.5))
195 .value(0, 5, new NumberNode(1.6))
196 .value(1, 5, new NumberNode(2.6))
197 .value(2, 5, new NumberNode(3.6))
198 .build());
199 }
200
201 @Test
202 public void listNode_multiDimensionalAndMissingValues() {
203 run("{1,2;3;4;5;6}", ListNode.builder()
204 .value(0, 0, new NumberNode(1.0))
205 .value(1, 0, new NumberNode(2.0))
206 .value(0, 1, new NumberNode(3.0))
207 .value(0, 2, new NumberNode(4.0))
208 .value(0, 3, new NumberNode(5.0))
209 .value(0, 4, new NumberNode(6.0))
210 .build());
211 }
212
213 @Test
214 public void formulaNode_empty() {
215 run("RAND()", new FormulaNode(FormulaName.RAND.toString()));
216 run("TRUE()", new FormulaNode(FormulaName.TRUE.toString()));
217 run("FALSE()", new FormulaNode(FormulaName.FALSE.toString()));
218 }
219
220 @Test
221 public void formulaNode() {
222 run("POW(2, 6)", FormulaNode.builder()
223 .name(FormulaName.POW.toString())
224 .value(new NumberNode(2.0))
225 .value(new NumberNode(6.0))
226 .build());
227 run("SUM(1.829173, {8.12983271})", FormulaNode.builder()
228 .name(FormulaName.SUM.toString())
229 .value(new NumberNode(1.829173))
230 .value(ListNode.builder().value(0, 0, new NumberNode(8.12983271)).build())
231 .build());
232 }
233
234 @Test
235 public void variableNode() {
236 run("TRUE", new VariableNode("TRUE"));
237 run("True", new VariableNode("True"));
238 run("tRuE", new VariableNode("tRuE"));
239 run("FALSE", new VariableNode("FALSE"));
240 run("False", new VariableNode("False"));
241 run("fAlSe", new VariableNode("fAlSe"));
242 run("false", new VariableNode("false"));
243 run("My_Special_Variable_That_Might_Exist", new VariableNode("My_Special_Variable_That_Might_Exist"));
244 run("Variable_That_Is_Longer_Than_Two_Hundred_And_Fifty_Five_Characters_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Farm_Old_McDonald_Had_A_Fa",
245 new ErrorNode(new ParseException()));
246 }
247
248 @Test
249 public void errorNode() {
250 run("#NUM!", new ErrorNode(new NumException()));
251 run("#DIV/0!", new ErrorNode(new DivException()));
252 run("#VALUE!", new ErrorNode(new ValueException()));
253 run("#REF!", new ErrorNode(new RefException()));
254 run("#NAME?", new ErrorNode(new NameException()));
255 run("#NUM!", new ErrorNode(new NumException()));
256 run("#N/A", new ErrorNode(new NAException()));
257 run("#ERROR!", new ErrorNode(new ParseException()));
258 }
259
260 @Test
261 public void testAddition() {
262 run("1 + 1", new BinaryOperationNode(new NumberNode(1.0), "+", new NumberNode(1.0)));
263 run("1 + 0", new BinaryOperationNode(new NumberNode(1.0), "+", new NumberNode(0.0)));
264 run("1 + 2.12121", new BinaryOperationNode(new NumberNode(1.0), "+", new NumberNode(2.12121)));
265 run("1e10 + 2.12121", new BinaryOperationNode(new NumberNode(1e10), "+", new NumberNode(2.12121)));
266 }
267
268 @Test
269 public void testAddition_withList() {
270 ListNode singleOne = ListNode.builder()
271 .value(0, 0, new NumberNode(1.0))
272 .build();
273 run("1 + {1}", new BinaryOperationNode(new NumberNode(1.0), "+", singleOne));
274 run("1 + {1, 44}", new BinaryOperationNode(new NumberNode(1.0), "+", ListNode.builder()
275 .value(0, 0, new NumberNode(1.0))
276 .value(1, 0, new NumberNode(44.0))
277 .build()));
278 run("{1} + {1}", new BinaryOperationNode(singleOne, "+", singleOne));
279 }
280
281 @Test
282 public void testAddition_withErrors() {
283 run("3 + #VALUE!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new ValueException())));
284 run("3 + #DIV/0!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new DivException())));
285 run("3 + #NUM!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new NumException())));
286 run("3 + #NAME?", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new NameException())));
287 run("3 + #NULL!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new NullException())));
288 run("3 + #N/A", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new NAException())));
289 run("3 + #REF!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new RefException())));
290 run("3 + #ERROR!", new BinaryOperationNode(new NumberNode(3.0), "+", new ErrorNode(new ParseException())));
291 }
292
293 @Test
294 public void testSubtraction() {
295 run("1 - 1", new BinaryOperationNode(new NumberNode(1.0), "-", new NumberNode(1.0)));
296 run("3 - 1", new BinaryOperationNode(new NumberNode(3.0), "-", new NumberNode(1.0)));
297 run("3.1e3 - 4.2e10", new BinaryOperationNode(new NumberNode(3.1e3), "-", new NumberNode(4.2e10)));
298 }
299
300 @Test
301 public void testSubtraction_withList() {
302 ListNode singleOne = ListNode.builder()
303 .value(0, 0, new NumberNode(1.0))
304 .build();
305 run("1 - {1}", new BinaryOperationNode(new NumberNode(1.0), "-", singleOne));
306 run("1 - {1, 44}", new BinaryOperationNode(new NumberNode(1.0), "-", ListNode.builder()
307 .value(0, 0, new NumberNode(1.0))
308 .value(1, 0, new NumberNode(44.0))
309 .build()));
310 run("{1} - {1}", new BinaryOperationNode(singleOne, "-", singleOne));
311 }
312
313 @Test
314 public void testSubtraction_withErrors() {
315 run("3 - #VALUE!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new ValueException())));
316 run("3 - #DIV/0!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new DivException())));
317 run("3 - #NUM!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new NumException())));
318 run("3 - #NAME?", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new NameException())));
319 run("3 - #NULL!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new NullException())));
320 run("3 - #N/A", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new NAException())));
321 run("3 - #REF!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new RefException())));
322 run("3 - #ERROR!", new BinaryOperationNode(new NumberNode(3.0), "-", new ErrorNode(new ParseException())));
323 }
324
325 @Test
326 public void testMultiplication() {
327 run("3 * 4", new BinaryOperationNode(new NumberNode(3.0), "*", new NumberNode(4.0)));
328 run("3 * 1", new BinaryOperationNode(new NumberNode(3.0), "*", new NumberNode(1.0)));
329 run("3.1e3 * 2", new BinaryOperationNode(new NumberNode(3.1e3), "*", new NumberNode(2.0)));
330 run("3.1e3 * 0", new BinaryOperationNode(new NumberNode(3.1e3), "*", new NumberNode(0.0)));
331 }
332
333 @Test
334 public void testMultiplication_withList() {
335 run("3 * {4}", new BinaryOperationNode(new NumberNode(3.0), "*", ListNode.builder()
336 .value(0, 0, new NumberNode(4.0))
337 .build()));
338 run("3 * {4, TRUE}", new BinaryOperationNode(new NumberNode(3.0), "*", ListNode.builder()
339 .value(0, 0, new NumberNode(4.0))
340 .value(1, 0, new VariableNode("TRUE"))
341 .build()));
342 }
343
344 @Test
345 public void testMultiplication_withErrors() {
346 run("3 * #VALUE!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new ValueException())));
347 run("3 * #DIV/0!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new DivException())));
348 run("3 * #NUM!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new NumException())));
349 run("3 * #NAME?", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new NameException())));
350 run("3 * #NULL!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new NullException())));
351 run("3 * #N/A", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new NAException())));
352 run("3 * #REF!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new RefException())));
353 run("3 * #ERROR!", new BinaryOperationNode(new NumberNode(3.0), "*", new ErrorNode(new ParseException())));
354 }
355
356 @Test
357 public void testDivision() {
358 run("3 / 4", new BinaryOperationNode(new NumberNode(3.0), "/", new NumberNode(4.0)));
359 run("4 / 3", new BinaryOperationNode(new NumberNode(4.0), "/", new NumberNode(3.0)));
360 run("3e3 / 2", new BinaryOperationNode(new NumberNode(3e3), "/", new NumberNode(2.0)));
361 run("10 / 0", new BinaryOperationNode(new NumberNode(10.0), "/", new NumberNode(0.0)));
362 }
363
364 @Test
365 public void testDivision_withList() {
366 run("3 / {4}", new BinaryOperationNode(new NumberNode(3.0), "/", ListNode.builder()
367 .value(0, 0, new NumberNode(4.0))
368 .build()));
369 run("3 / {4, TRUE}", new BinaryOperationNode(new NumberNode(3.0), "/", ListNode.builder()
370 .value(0, 0, new NumberNode(4.0))
371 .value(1, 0, new VariableNode("TRUE"))
372 .build()));
373 }
374
375 @Test
376 public void testDivision_withErrors() {
377 run("3 / #VALUE!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new ValueException())));
378 run("3 / #DIV/0!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new DivException())));
379 run("3 / #NUM!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new NumException())));
380 run("3 / #NAME?", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new NameException())));
381 run("3 / #NULL!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new NullException())));
382 run("3 / #N/A", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new NAException())));
383 run("3 / #REF!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new RefException())));
384 run("3 / #ERROR!", new BinaryOperationNode(new NumberNode(3.0), "/", new ErrorNode(new ParseException())));
385 }
386
387 @Test
388 public void testPower() {
389 run("-2^3", new BinaryOperationNode(new UnaryMinusOperationNode(new NumberNode(2.0)), "^", new NumberNode(3.0)));
390 run("(-2)^3", new BinaryOperationNode(new UnaryMinusOperationNode(new NumberNode(2.0)), "^", new NumberNode(3.0)));
391 run("-(2)^3", new BinaryOperationNode(new UnaryMinusOperationNode(new NumberNode(2.0)), "^", new NumberNode(3.0)));
392 run("--(-2)^3", new BinaryOperationNode(new UnaryMinusOperationNode(new UnaryMinusOperationNode(new UnaryMinusOperationNode(new NumberNode(2.0)))), "^", new NumberNode(3.0)));
393 run("11 -2^3", new BinaryOperationNode(new NumberNode(11.0), "-", new BinaryOperationNode(new NumberNode(2.0), "^", new NumberNode(3.0))));
394 run("(-2) ^ 3", new BinaryOperationNode(new UnaryMinusOperationNode(new NumberNode(2.0)), "^", new NumberNode(3.0)));
395 run("(-3) ^ 2", new BinaryOperationNode(new UnaryMinusOperationNode(new NumberNode(3.0)), "^", new NumberNode(2.0)));
396 }
397
398 @Test
399 public void testConcatOperation() {
400 run("1 & 1", new BinaryOperationNode(new NumberNode(1.0), "&", new NumberNode(1.0)));
401 run("\"One\" & 0", new BinaryOperationNode(new TextNode("One"), "&", new NumberNode(0.0)));
402 }
403
404
405 @Test
406 public void testConcatOperation_withErrors() {
407 run("1 & #DIV/0!", new BinaryOperationNode(new NumberNode(1.0), "&", new ErrorNode(new DivException())));
408 }
409
410 @Test
411 public void testUnaryMinusOperation() {
412 run("-22", new UnaryMinusOperationNode(new NumberNode(22.0)));
413 run("-\"Thing\"", new UnaryMinusOperationNode(new TextNode("Thing")));
414 run("--22", new UnaryMinusOperationNode(new UnaryMinusOperationNode(new NumberNode(22.0))));
415 run("---22", new UnaryMinusOperationNode(new UnaryMinusOperationNode(new UnaryMinusOperationNode(new NumberNode(22.0)))));
416 run("-(2 * 4)", new UnaryMinusOperationNode(new BinaryOperationNode(new NumberNode(2.0), "*", new NumberNode(4.0))));
417 }
418
419 @Test
420 public void testUnaryPercentOperation() {
421 run("88%", new UnaryPercentOperationNode(new NumberNode(88.0)));
422 run("(8 * 8)%", new UnaryPercentOperationNode(new BinaryOperationNode(new NumberNode(8.0), "*", new NumberNode(8.0))));
423 }
424
425 @Test
426 public void testUnaryPercentOperation_parseErrorBecauseOfRepetitivePercent() {
427 run("88%%", new ErrorNode(new ParseException()));
428 run("88%%%", new ErrorNode(new ParseException()));
429 run("88% % % %", new ErrorNode(new ParseException()));
430 }
431
432 @Test
433 public void testCellRange_singleCell() {
434 run("A4", new RangeNode(CellQuery.builder()
435 .columnsBetween(0, 0)
436 .rowsBetween(3, 3)
437 .build()));
438 }
439
440 @Test
441 public void testCellRange_biCell() {
442 run("A1:B2", new RangeNode(CellQuery.builder()
443 .columnsBetween(0, 1)
444 .rowsBetween(0, 1)
445 .build()));
446 run("B2:A1", new RangeNode(CellQuery.builder()
447 .columnsBetween(0, 1)
448 .rowsBetween(0, 1)
449 .build()));
450 run("B2:D4", new RangeNode(CellQuery.builder()
451 .columnsBetween(1, 3)
452 .rowsBetween(1, 3)
453 .build()));
454 run("B4:B4", new RangeNode(CellQuery.builder()
455 .columnsBetween(1, 1)
456 .rowsBetween(3, 3)
457 .build()));
458 run("B3:B4", new RangeNode(CellQuery.builder()
459 .columnsBetween(1, 1)
460 .rowsBetween(2, 3)
461 .build()));
462 run("B4:B3", new RangeNode(CellQuery.builder()
463 .columnsBetween(1, 1)
464 .rowsBetween(2, 3)
465 .build()));
466 }
467
468 @Test
469 public void testCellRange_multiColumn() {
470 run("A:C", new RangeNode(CellQuery.builder()
471 .columnsBetween(0, 2)
472 .openRowsStartingAtZero()
473 .build()));
474 run("C:A", new RangeNode(CellQuery.builder()
475 .columnsBetween(0, 2)
476 .openRowsStartingAtZero()
477 .build()));
478 run("B:M", new RangeNode(CellQuery.builder()
479 .columnsBetween(1, 12)
480 .openRowsStartingAtZero()
481 .build()));
482 run("M:B", new RangeNode(CellQuery.builder()
483 .columnsBetween(1, 12)
484 .openRowsStartingAtZero()
485 .build()));
486 run("M:M", new RangeNode(CellQuery.builder()
487 .columnsBetween(12, 12)
488 .openRowsStartingAtZero()
489 .build()));
490 }
491
492 @Test
493 public void testCellRange_multiRow() {
494 run("3:7", new RangeNode(CellQuery.builder()
495 .rowsBetween(2, 6)
496 .openColumnsStartingAtZero()
497 .build()));
498 run("1:100", new RangeNode(CellQuery.builder()
499 .rowsBetween(0, 99)
500 .openColumnsStartingAtZero()
501 .build()));
502 run("7:3", new RangeNode(CellQuery.builder()
503 .rowsBetween(2, 6)
504 .openColumnsStartingAtZero()
505 .build()));
506 run("100:1", new RangeNode(CellQuery.builder()
507 .rowsBetween(0, 99)
508 .openColumnsStartingAtZero()
509 .build()));
510 }
511
512 @Test
513 public void testCellRange_multiRowStartColumn() {
514 run("D3:7", new RangeNode(CellQuery.builder()
515 .rowsBetween(2, 6)
516 .openColumnsStartingAt("D")
517 .build()));
518 run("D7:3", new RangeNode(CellQuery.builder()
519 .rowsBetween(2, 6)
520 .openColumnsStartingAt("D")
521 .build()));
522 run("E5:10", new RangeNode(CellQuery.builder()
523 .rowsBetween(4, 9)
524 .openColumnsStartingAt(4)
525 .build()));
526 run("D7:7", new RangeNode(CellQuery.builder()
527 .rowsBetween(6, 6)
528 .openColumnsStartingAt("D")
529 .build()));
530 }
531
532 @Test
533 public void testCellRange_multiColumnStartRow() {
534 run("B3:D", new RangeNode(CellQuery.builder()
535 .columnsBetween(1, 3)
536 .openRowsStartingAt(2)
537 .build()));
538 run("D3:B", new RangeNode(CellQuery.builder()
539 .columnsBetween(1, 3)
540 .openRowsStartingAt(2)
541 .build()));
542 run("B33:B", new RangeNode(CellQuery.builder()
543 .columnsBetween(1, 1)
544 .openRowsStartingAt(32)
545 .build()));
546 }
547
548 @Test
549 public void testCellRange_multiCell() {
550 run("C5:B4:D2:G7:L11", new RangeQueryNode(ImmutableList.of(
551 new RangeNode(CellQuery.builder()
552 .columnsBetween(1, 2)
553 .rowsBetween(3, 4)
554 .build()),
555 new RangeNode(CellQuery.builder()
556 .columnsBetween(3, 6)
557 .rowsBetween(1, 6)
558 .build()),
559 new RangeNode(CellQuery.builder()
560 .columnsBetween(11, 11)
561 .rowsBetween(10, 10)
562 .build())
563 )));
564 run("A4:B5:C6:D7:E8:F9", new RangeQueryNode(ImmutableList.of(
565 new RangeNode(CellQuery.builder()
566 .columnsBetween(0, 1)
567 .rowsBetween(3, 4)
568 .build()),
569 new RangeNode(CellQuery.builder()
570 .columnsBetween(2, 3)
571 .rowsBetween(5, 6)
572 .build()),
573 new RangeNode(CellQuery.builder()
574 .columnsBetween(4, 5)
575 .rowsBetween(7, 8)
576 .build())
577 )));
578 run("SUM(A1:B2:C3:D4:E5:F6)", new FormulaNode(FormulaName.SUM.toString(), ImmutableList.of(new RangeQueryNode(ImmutableList.of(
579 new RangeNode(CellQuery.builder()
580 .columnsBetween(0, 1)
581 .rowsBetween(0, 1)
582 .build()),
583 new RangeNode(CellQuery.builder()
584 .columnsBetween(2, 3)
585 .rowsBetween(2, 3)
586 .build()),
587 new RangeNode(CellQuery.builder()
588 .columnsBetween(4, 5)
589 .rowsBetween(4, 5)
590 .build())
591 )))));
592 }
593
594 private Node transpile(String value) {
595 try {
596 CommonTokenStream tokens = new CommonTokenStream(new F7Lexer(CharStreams.fromStream(
597 new ByteArrayInputStream(value.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)));
598 try {
599 F7Parser parser = new F7Parser(tokens);
600 parser.removeErrorListeners();
601 parser.addErrorListener(new ParseErrorListener());
602 return visitor.visit(parser.start().block());
603 } catch (ParseCancellationException parseException) {
604 return new ErrorNode(new ParseException("Parse error"));
605 } catch (F7Exception f7Exception) {
606 return new ErrorNode(f7Exception);
607 }
608 } catch (IOException io) {
609 return new ErrorNode(new ParseException("Parse error"));
610 }
611 }
612
613 protected void run(String in, Node out) {
614 assertThat(transpile(in)).isEqualTo(out);
615 }
616}