spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Tests, TODOS] adding tests for expression operator tests, marking TODOs with numbers
author
Ben Vogt <[email protected]>
date
2018-02-10 04:43:09
stats
4 file(s) changed, 243 insertions(+), 53 deletions(-)
files
TODO.md
tests/ParsingTest.ts
tests/SheetBasicTests.ts
tests/SheetFormulaTest.ts
  1diff --git a/TODO.md b/TODO.md
  2index a947b8f..86ed4d2 100644
  3--- a/TODO.md
  4+++ b/TODO.md
  5@@ -1,33 +1,61 @@
  6 # TODO
  7 
  8 
  9-### Cells should have `formatAs` fields.
 10+### [ISSUE-001] Cells should have `formatAs` fields.
 11 Instead of having non-primitives, (i.e. Date, DateTime, Time, Dollar), cells should have formats based on the highest-order type that was used during the compilation and execution of a cell's dependency. For example, `DATE` might return a number, but the cell that called `DATE` would be aware of it calling a formula that returns an non-primitive type, and would display the returned number as a Date. If you're using `DATE` in conjunction with `DOLLAR` it would still display the returned value as a Date. The hierarchy would look like: [Date, DateTime, Time, Dollar, number, boolean, string]. Advantages to this would include not having to cast down when using primitive operators, and flexibility in display. It would also simplify the types themselves, by having types be constants and just having helpers to convert, display, and do normal operations with them. Requires changes to `TO_DATE`, `TO_PERCENT`, `TO_DOLLAR`, and `TO_TEXT`.
 12 
 13 
 14-### CONVERT could offer more accurate conversions for units in the same system
 15+### [ISSUE-002] CONVERT could offer more accurate conversions for units in the same system
 16 For example 64 tbs to a qt.
 17 
 18 
 19-### Range literals should be allow to follow commas
 20+### [ISSUE-003] Range literals should be allow to follow commas
 21 Currently, this `=SERIESSUM([1], [0], [1], [4, 5, 6])` parses, but this `=SERIESSUM(1, 0, 1, [4, 5, 6])` does not.
 22 
 23 
 24-### Parser/Sheet should be able to be initialized with js range notation (`[]`) or regular range notation (`{}`)
 25+### [ISSUE-004] Parser/Sheet should be able to be initialized with js range notation (`[]`) or regular range notation (`{}`)
 26 
 27 
 28-### TypeConverter.stringToDateNumber should handle fractions of a second.
 29+### [ISSUE-005] TypeConverter.stringToDateNumber should handle fractions of a second.
 30 E.g. `01/09/2012 10:04:33.123`
 31 
 32 
 33-### TypeConverter should be able to convert timestamps to numbers.
 34+### [ISSUE-006] TypeConverter should be able to convert timestamps to numbers.
 35 E.g. `12:00:00` should result in `0.5`.
 36 
 37 
 38-### Parser should be able to parse arrays without `eval`
 39+### [ISSUE-007] Parser should be able to parse arrays without 'eval'
 40 Right now, arrays and reference literals in a formula are parsed using JS `eval`. This means, if we have references inside, or non-JS parsing values like TRUE or FALSE, they will cause ReferenceErrors. For example, `=SUM([M1, 10])` would throw `[ReferenceError: M1 is not defined]` because M1 is not a variable. Instead of using `eval`, we should parse the opening of an array, and the closeing of an array, and use recursion to see how deep we are, evaluating the tokens inside in the sam way we parse formulas and functions.
 41 
 42 
 43+### [ISSUE-008] Error literals should be thrown
 44+Error literals in valid locations should throw themselves. For example "=10 + #DIV?/0!" should throw a Divide-By-Zero error.
 45+
 46+
 47+### [ISSUE-009] Equality checking should check for type and value
 48+Currently '=10 = "10"' is true, when it should be false.
 49+
 50+
 51+### [ISSUE-010] Input should be able to start with a decimal.
 52+Currently '=.1' should parse properly. Could be solved by going back from handling number input in reg-ex to handling it with the parser logic. See [ISSUE-011].
 53+
 54+
 55+### [ISSUE-011] Input should be able to parse short-cut sci-notation
 56+Currently '=0.e1' should parse properly.  Could be solved by going back from handling number input in reg-ex to handling it with the parser logic. See [ISSUE-010].
 57+
 58+
 59+### [ISSUE-012] Strings should only start with double quotes.
 60+Single quotes are reserved for variables, like sheet names.
 61+
 62+
 63+### [ISSUE-013] Equality checking inside parentheses should return boolean values
 64+For example '=(1=1)' should return true.
 65+
 66+
 67+### [ISSUE-014] Cell reference ranges should not return nested values
 68+For example '=(E1:E4)' should return an array of values, not a nested array of values.
 69+
 70+
 71 ### Meta-Formulas to write
 72 Many of these formulas can be written by allowing the Sheet and Parser to return Cell objects in addition to primitive types. There are some memory issues with doing this. If a user calls something like `ISNA(A1:A99999)` we really only need the first cell. So we should return cell objects in some cases, but it would be easier in most cases to have context aware formulas, so if they need a cell, or a reference, we simply skip looking up a reference, and instead return a reference, or just a single cell. One way to do this would be to have formula functions, and then on the side have formula args. So before we lookup a large range of cells, we can check to see if it needs all of them, or if it just cares about the first one. So for `ISNA` we could look at `FormulaArgs.ISNA[0]` to get `Value` so we know that it needs only a single argument that is not an array, so if we call it with `ISNA(A1:A99999)`, it would really only lookup `A1`. This might be premature optimization however.
 73 
 74diff --git a/tests/ParsingTest.ts b/tests/ParsingTest.ts
 75index f5c680b..73e273d 100644
 76--- a/tests/ParsingTest.ts
 77+++ b/tests/ParsingTest.ts
 78@@ -51,7 +51,7 @@ test("Parse equality operators", function(){
 79   assertFormulaEquals('= 1 < 2', true);
 80   assertFormulaEquals('= 1 < 0', false);
 81   assertFormulaEquals('= 1 <= 1', true);
 82-  // assertFormulaEquals('= 1 <= 2', true); // TODO: Fails.
 83+  assertFormulaEquals('= 1 <= 2', true);
 84   assertFormulaEquals('= 1 >= 1', true);
 85   assertFormulaEquals('= 2 >= 1', true);
 86   assertFormulaEquals('= 1 >= 0', true);
 87@@ -101,7 +101,7 @@ test("Parse and throw error literal", function () {
 88 
 89 test("Parse plain numbers", function() {
 90   assertFormulaEquals('=10', 10);
 91-  // assertFormulaEquals('=.1', 0.1); // TODO: Fails from parse error, but should pass
 92+  // assertFormulaEquals('=.1', 0.1); // TODO: [ISSUE-010]
 93   assertFormulaEquals('=0.1', 0.1);
 94   assertFormulaEquals('=+1', 1);
 95   assertFormulaEquals('=-1', -1);
 96@@ -109,7 +109,7 @@ test("Parse plain numbers", function() {
 97   assertFormulaEquals('=--1', 1);
 98   assertFormulaEquals('=10e1', 100);
 99   assertFormulaEquals('=0e1', 0);
100-  // assertFormulaEquals('=0.e1', 0); // TODO: Fails from parse error, but should pass
101+  // assertFormulaEquals('=0.e1', 0); // TODO: [ISSUE-010]
102   assertFormulaEquals('=-10e1', -100);
103   assertFormulaEquals('=+10e1', 100);
104   assertFormulaEquals('=++10e1', 100);
105@@ -157,7 +157,8 @@ test("Parse strings", function(){
106   assertFormulaEquals('="str"', "str");
107   assertFormulaEquals('="str"&"str"', "strstr");
108   assertFormulaEqualsError('="str"+"str"', VALUE_ERROR);
109-  // assertFormulaEqualsError("='str'", PARSE_ERROR); // TODO: Parses, but it shouldn't.
110+  // assertFormulaEqualsError("='str'", PARSE_ERROR); // TODO: [ISSUE-011]
111+
112 });
113 
114 test("Parse boolean literals", function(){
115@@ -168,23 +169,23 @@ test("Parse boolean literals", function(){
116 });
117 
118 test("Parse boolean logic", function(){
119-  // assertFormulaEquals('=(1=1)', true); // TODO: Fails because we compute the value, rather than checking equality
120-  // assertFormulaEquals('=(1=2)', false); // TODO: Fails because we compute the value, rather than checking equality
121+  // assertFormulaEquals('=(1=1)', true); // TODO: [ISSUE-013]
122+  // assertFormulaEquals('=(1=2)', false); // TODO: [ISSUE-013]
123   assertFormulaEquals('=(1=1)+2', 3);
124 
125 });
126 
127 
128 test("Parse range literal", function(){
129-  // assertFormulaEqualsArray('=[1, 2, 3]', [1, 2, 3]); // TODO: Fails because of low-level parser error
130-  // assertFormulaEqualsArray('=[]', []); // TODO: Fails because of low-level parser error
131-  // assertFormulaEqualsArray('=["str", "str"]', ["str", "str"]); // TODO: Fails because of low-level parser error
132-  // assertFormulaEqualsArray('=["str", [1, 2, 3], [1]]', ["str", [1, 2, 3], [1]]); // TODO: Fails because of low-level parser error
133+  // assertFormulaEqualsArray('=[1, 2, 3]', [1, 2, 3]); // TODO: [ISSUE-007]
134+  // assertFormulaEqualsArray('=[]', []); // TODO: [ISSUE-007]
135+  // assertFormulaEqualsArray('=["str", "str"]', ["str", "str"]); // TODO: [ISSUE-007]
136+  // assertFormulaEqualsArray('=["str", [1, 2, 3], [1]]', ["str", [1, 2, 3], [1]]); // TODO: [ISSUE-007]
137 });
138 
139 test("Parse cell references", function(){
140   assertFormulaEqualsDependsOnReference("E1", "str", '=E1', Cell.BuildFrom("E1", "str"));
141-  // assertFormulaEqualsArray('=E1:E2', [new Cell("E1"), new Cell("E2")]); // TODO: Fails because the returned result is nested. Shouldn't be.
142+  // assertFormulaEqualsArray('=E1:E2', [new Cell("E1"), new Cell("E2")]); // TODO: [ISSUE-014]
143 });
144 
145 test("Parse range following comma", function(){
146@@ -192,4 +193,133 @@ test("Parse range following comma", function(){
147   // assertFormulaEquals('=SERIESSUM([1], [0], [1], [4, 5, 6])', 15);
148 });
149 
150-
151+test("Combinations of expressions and operators", function(){
152+  test("Combinations of expressions and operators, ", function(){
153+    assertFormulaEquals('=10 + 10', 20);
154+    assertFormulaEquals('=10 + TRUE', 11);
155+    assertFormulaEquals('=10 + "10"', 20);
156+    assertFormulaEquals('=10 + (2*2)', 14);
157+    assertFormulaEquals('=10 + SUM(1, 2)', 13);
158+    // assertFormulaEquals('=10 + [10]', 20); // TODO: [ISSUE-007]
159+    // assertFormulaEqualsError('=10 + #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
160+  });
161+  test("Combinations of expressions and operators, plus operator", function(){
162+    assertFormulaEquals('=10 + 10', 20);
163+    assertFormulaEquals('=10 + TRUE', 11);
164+    assertFormulaEquals('=10 + "10"', 20);
165+    assertFormulaEquals('=10 + (2*2)', 14);
166+    assertFormulaEquals('=10 + SUM(1, 2)', 13);
167+    // assertFormulaEquals('=10 + [10]', 20); // TODO: [ISSUE-007]
168+    // assertFormulaEqualsError('=10 + #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
169+  });
170+  test("Combinations of expressions and operators, minus operator", function(){
171+    assertFormulaEquals('=10 - 10', 0);
172+    assertFormulaEquals('=10 - TRUE', 9);
173+    assertFormulaEquals('=10 - "10"', 0);
174+    assertFormulaEquals('=10 - (2*2)', 6);
175+    assertFormulaEquals('=10 - SUM(1, 2)', 7);
176+    // assertFormulaEquals('=10 - [10]', 10); // TODO: [ISSUE-007]
177+    // assertFormulaEqualsError('=10 - #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
178+  });
179+  test("Combinations of expressions and operators, division operator", function(){
180+    assertFormulaEquals('=10 / 10', 1);
181+    assertFormulaEquals('=10 / TRUE', 10);
182+    assertFormulaEquals('=10 / "10"', 1);
183+    assertFormulaEquals('=10 / (2*2)', 2.5);
184+    assertFormulaEquals('=10 / SUM(1, 2)', 3.3333333333333335);
185+    // assertFormulaEquals('=10 / [10]', 10); // TODO: [ISSUE-007]
186+    // assertFormulaEqualsError('=10 / #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
187+  });
188+  test("Combinations of expressions and operators, multiplication operator", function(){
189+    assertFormulaEquals('=10 * 10', 100);
190+    assertFormulaEquals('=10 * TRUE', 10);
191+    assertFormulaEquals('=10 * "10"', 100);
192+    assertFormulaEquals('=10 * (2*2)', 40);
193+    assertFormulaEquals('=10 * SUM(1, 2)', 30);
194+    // assertFormulaEquals('=10 * [10]', 10); // TODO: [ISSUE-007]
195+    // assertFormulaEqualsError('=10 * #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
196+  });
197+  test("Combinations of expressions and operators, power operator", function(){
198+    assertFormulaEquals('=10 ^ 2', 100);
199+    assertFormulaEquals('=10 ^ TRUE', 10);
200+    assertFormulaEquals('=10 ^ "2"', 100);
201+    assertFormulaEquals('=10 ^ (2*2)', 10000);
202+    assertFormulaEquals('=10 ^ SUM(2, 2)', 10000);
203+    // assertFormulaEquals('=10 ^ 1', 10); // TODO: [ISSUE-007]
204+    // assertFormulaEqualsError('=10 & #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
205+  });
206+  test("Combinations of expressions and operators, concat operator", function(){
207+    assertFormulaEquals('=10 & 10', "1010");
208+    assertFormulaEquals('=10 & TRUE', "10TRUE");
209+    assertFormulaEquals('=10 & "10"', "1010");
210+    assertFormulaEquals('=10 & (2*2)', "104");
211+    assertFormulaEquals('=10 & SUM(1, 2)', "103");
212+    // assertFormulaEquals('=10 & [10]', 10); // TODO: [ISSUE-007]
213+    // assertFormulaEqualsError('=10 & #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
214+  });
215+  test("Combinations of expressions and operators, LT operator", function(){
216+    assertFormulaEquals('=10 < 10', false);
217+    assertFormulaEquals('=10 < TRUE', false);
218+    assertFormulaEquals('=10 < "10"', false);
219+    assertFormulaEquals('=10 < (2*2)', false);
220+    assertFormulaEquals('=10 < SUM(1, 2)', false);
221+    // assertFormulaEquals('=10 < [10]', 10); // TODO: [ISSUE-007]
222+    // assertFormulaEqualsError('=10 < #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
223+  });
224+  test("Combinations of expressions and operators, LTE operator", function(){
225+    assertFormulaEquals('=10 <= 10', true);
226+    assertFormulaEquals('=10 <= TRUE', false);
227+    assertFormulaEquals('=10 <= "10"', true);
228+    assertFormulaEquals('=10 <= (2*2)', false);
229+    assertFormulaEquals('=10 <= SUM(1, 2)', false);
230+    // assertFormulaEquals('=10 <= [10]', 10); // TODO: [ISSUE-007]
231+    // assertFormulaEqualsError('=10 <= #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
232+  });
233+  test("Combinations of expressions and operators, GT operator", function(){
234+    assertFormulaEquals('=10 > 10', false);
235+    assertFormulaEquals('=10 > TRUE', true);
236+    assertFormulaEquals('=10 > "10"', false);
237+    assertFormulaEquals('=10 > (2*2)', true);
238+    assertFormulaEquals('=10 > SUM(1, 2)', true);
239+    // assertFormulaEquals('=10 > [10]', 10); // TODO: [ISSUE-007]
240+    // assertFormulaEqualsError('=10 > #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
241+  });
242+  test("Combinations of expressions and operators, GTE operator", function(){
243+    assertFormulaEquals('=10 >= 10', true);
244+    assertFormulaEquals('=10 >= TRUE', true);
245+    assertFormulaEquals('=10 >= "10"', true);
246+    assertFormulaEquals('=10 >= (2*2)', true);
247+    assertFormulaEquals('=10 >= SUM(1, 2)', true);
248+    // assertFormulaEquals('=10 >= [10]', 10); // TODO: [ISSUE-007]
249+    // assertFormulaEqualsError('=10 >= #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
250+  });
251+  test("Combinations of expressions and operators, equality operator", function(){
252+    assertFormulaEquals('=10 = 10', true);
253+    assertFormulaEquals('=10 = TRUE', false);
254+    // assertFormulaEquals('=10 = "10"', true); // TODO: [ISSUE-009]
255+    assertFormulaEquals('=10 = (2*2)', false);
256+    assertFormulaEquals('=10 = SUM(1, 2)', false);
257+    // assertFormulaEquals('=10 >= [10]', 10); // TODO: [ISSUE-007]
258+    // assertFormulaEqualsError('=10 >= #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
259+  });
260+  test("Combinations of expressions and operators, not-equal operator", function(){
261+    assertFormulaEquals('=10 <> 10', false);
262+    assertFormulaEquals('=10 <> TRUE', true);
263+    assertFormulaEquals('=10 <> "10"', true);
264+    assertFormulaEquals('=10 <> (2*2)', true);
265+    assertFormulaEquals('=10 <> SUM(1, 2)', true);
266+    // assertFormulaEquals('=10 <> [10]', 10); // TODO: [ISSUE-007]
267+    // assertFormulaEqualsError('=10 <> #DIV/0!', DIV_ZERO_ERROR); // TODO: [ISSUE-008]
268+  });
269+  test("Combinations of expressions and operators, unary prefix operators", function(){
270+    assertFormulaEquals('=10 <> -10', true);
271+    assertFormulaEquals('=-10', -10);
272+    assertFormulaEquals('=-(-10)', 10);
273+    assertFormulaEquals('=-(-(-1*2))', -2);
274+    assertFormulaEquals('=-TRUE', -1);
275+    assertFormulaEquals('=-"1"', -1);
276+    assertFormulaEquals('=-+"1"', -1);
277+    assertFormulaEquals('=-+-"1"', 1);
278+    assertFormulaEquals('=-(1=1)', -1);
279+  });
280+});
281diff --git a/tests/SheetBasicTests.ts b/tests/SheetBasicTests.ts
282index df39965..25d6686 100644
283--- a/tests/SheetBasicTests.ts
284+++ b/tests/SheetBasicTests.ts
285@@ -138,14 +138,14 @@ test("Sheet, parse and throw error literal", function () {
286 
287 test("Sheet, parse plain numbers", function() {
288   assertFormulaEquals('=10', 10);
289-  // assertFormulaEquals('=.1', 0.1); // TODO: Fails because our parser doesn't expect a decimal right away.
290+  // assertFormulaEquals('=.1', 0.1); // TODO: [ISSUE-010]
291   assertFormulaEquals('=+1', 1);
292   assertFormulaEquals('=-1', -1);
293   assertFormulaEquals('=++1', 1);
294   assertFormulaEquals('=--1', 1);
295   assertFormulaEquals('=10e1', 100);
296   assertFormulaEquals('=0e1', 0);
297-  // assertFormulaEquals('=0.e1', 0); // TODO: Fails. After decimal, finds 'e' and thinks it's a variable.
298+  // assertFormulaEquals('=0.e1', 0); // TODO: [ISSUE-011]
299   assertFormulaEquals('=-10e1', -100);
300   assertFormulaEquals('=+10e1', 100);
301   assertFormulaEquals('=++10e1', 100);
302@@ -192,7 +192,7 @@ test("Sheet, parse strings", function(){
303   assertFormulaEquals('="str"', "str");
304   assertFormulaEquals('="str"&"str"', "strstr");
305   assertFormulaEqualsError('="str"+"str"', VALUE_ERROR);
306-  // assertFormulaEqualsError("='str'", PARSE_ERROR); // TODO: Parses, but we should not allow single-quote strings.
307+  // assertFormulaEqualsError("='str'", PARSE_ERROR); // TODO: [ISSUE-012]
308 });
309 
310 test("Sheet, parse boolean literals", function(){
311@@ -203,13 +203,13 @@ test("Sheet, parse boolean literals", function(){
312 });
313 
314 test("Sheet, parse comparison logic inside parentheses", function(){
315-  // assertEquals(parser.parse('(1=1)'), true); // TODO: Fails because we compute the value, rather than checking equality
316-  // assertEquals(parser.parse('(1=2)'), false); // TODO: Fails because we compute the value, rather than checking equality
317+  // assertEquals(parser.parse('(1=1)'), true); // TODO: [ISSUE-013]
318+  // assertEquals(parser.parse('(1=2)'), false); // TODO: [ISSUE-013]
319   assertFormulaEquals('=(1=1)+2', 3);
320 });
321 
322 test("Sheet, parse range literal", function(){
323-  // assertEqualsArray('=[1, 2, 3]', [1, 2, 3]); // TODO: Fails because we've not implemented array-level parsing.
324+  // assertEqualsArray('=[1, 2, 3]', [1, 2, 3]); // TODO: [ISSUE-007]
325   // assertEqualsArray('=[]', []);
326   // assertEqualsArray('=["str", "str"]', ["str", "str"]);
327   // assertEqualsArray('=["str", [1, 2, 3], [1]]', ["str", [1, 2, 3], [1]]);
328diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
329index ebb210d..051eaf6 100644
330--- a/tests/SheetFormulaTest.ts
331+++ b/tests/SheetFormulaTest.ts
332@@ -124,8 +124,7 @@ test("Sheet CONVERT", function(){
333 });
334 
335 test("Sheet CORREL", function(){
336-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
337-  // assertFormulaEquals('=CORREL([9, 5], [10, 4])', 1);
338+  // assertFormulaEquals('=CORREL([9, 5], [10, 4])', 1); // TODO: [ISSUE-003]
339 });
340 
341 test("Sheet CHOOSE", function(){
342@@ -168,8 +167,7 @@ test("Sheet COUNTIF", function(){
343 });
344 
345 test("Sheet COUNTIFS", function(){
346-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
347-  // assertFormulaEquals('=COUNTIFS([1, 5, 10], ">4", [1, 5, 10], ">4")', 2);
348+  // assertFormulaEquals('=COUNTIFS([1, 5, 10], ">4", [1, 5, 10], ">4")', 2);  // TODO: [ISSUE-003]
349 });
350 
351 test("Sheet COUNTUNIQUE", function(){
352@@ -526,23 +524,19 @@ test("Sheet SUMIF", function(){
353 });
354 
355 test("Sheet SUMPRODUCT", function(){
356-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
357-  // assertFormulaEquals('=SUMPRODUCT([1, 5, 10], [2, 2, 2])', 32);
358+  // assertFormulaEquals('=SUMPRODUCT([1, 5, 10], [2, 2, 2])', 32); // TODO: [ISSUE-003]
359 });
360 
361 test("Sheet SUMSQ", function(){
362-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
363-  // assertFormulaEquals('=SUMSQ([1, 5, 10], 10)', 226);
364+  // assertFormulaEquals('=SUMSQ([1, 5, 10], 10)', 226); // TODO: [ISSUE-003]
365 });
366 
367 test("Sheet SUMX2MY2", function(){
368-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
369-  // assertFormulaEquals('=SUMX2MY2([1,2,3],[4,5,6])', -63);
370+  // assertFormulaEquals('=SUMX2MY2([1,2,3],[4,5,6])', -63); // TODO: [ISSUE-003]
371 });
372 
373 test("Sheet SUMX2PY2", function(){
374-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
375-  // assertFormulaEquals('=SUMX2PY2([1, 2, 3], [4, 5, 6])', 91);
376+  // assertFormulaEquals('=SUMX2PY2([1, 2, 3], [4, 5, 6])', 91); // TODO: [ISSUE-003]
377 });
378 
379 test("Sheet TAN", function(){
380@@ -665,8 +659,9 @@ test("Sheet FREQUENCY", function(){
381 });
382 
383 test("Sheet GROWTH", function(){
384-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
385-  // assertFormulaEqualsArray('=GROWTH([15.53, 19.99, 20.43, 21.18, 25.93, 30.00, 30.00, 34.01, 36.47],[1, 2, 3, 4, 5, 6, 7, 8, 9],[10, 11, 12])', [41.740521723275876, 46.22712349335047, 51.19598074591973]);
386+  // TODO: [ISSUE-003]
387+  // assertFormulaEqualsArray('=GROWTH([15.53, 19.99, 20.43, 21.18, 25.93, 30.00, 30.00, 34.01, 36.47],
388+  // [1, 2, 3, 4, 5, 6, 7, 8, 9],[10, 11, 12])', [41.740521723275876, 46.22712349335047, 51.19598074591973]);
389 });
390 
391 test("Sheet TRIMMEAN", function(){
392@@ -674,8 +669,7 @@ test("Sheet TRIMMEAN", function(){
393 });
394 
395 test("Sheet SLOPE", function(){
396-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
397-  // assertFormulaEquals('=SLOPE([600, 800], [44, 4.1])', -5.012531328320802);
398+  // assertFormulaEquals('=SLOPE([600, 800], [44, 4.1])', -5.012531328320802); // TODO: [ISSUE-003]
399 });
400 
401 test("Sheet LOWER", function(){
402@@ -699,13 +693,11 @@ test("Sheet LARGE", function(){
403 });
404 
405 test("Sheet INTERCEPT", function(){
406-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
407-  // assertFormulaEquals('=INTERCEPT([1, 2, 3, 4], [10, 20, 33, 44])', 0.1791776688042246);
408+  // assertFormulaEquals('=INTERCEPT([1, 2, 3, 4], [10, 20, 33, 44])', 0.1791776688042246); // TODO: [ISSUE-003]
409 });
410 
411 test("Sheet FORECAST", function(){
412-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
413-  // assertFormulaEquals('=FORECAST([0], [1, 2, 3, 4], [10, 20, 33, 44])', 0.1791776688042246);
414+  // assertFormulaEquals('=FORECAST([0], [1, 2, 3, 4], [10, 20, 33, 44])', 0.1791776688042246); // TODO: [ISSUE-003]
415 });
416 
417 test("Sheet SYD", function(){
418@@ -749,8 +741,9 @@ test("Sheet ISURL", function(){
419 });
420 
421 test("Sheet LINEST", function(){
422-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
423-  // assertFormulaEqualsArray('=LINEST([15.53, 19.99, 20.43, 21.18, 25.93, 30], [1, 2, 3, 4, 5, 6])', [2.5977142857142863,	13.08466666666666]);
424+  // TODO: [ISSUE-003]
425+  // assertFormulaEqualsArray('=LINEST([15.53, 19.99, 20.43, 21.18, 25.93, 30], [1, 2, 3, 4, 5, 6])',
426+  //     [2.5977142857142863,	13.08466666666666]);
427 });
428 
429 test("Sheet POISSON, POISSON.DIST", function(){
430@@ -812,7 +805,7 @@ test("Sheet BINOMDIST", function(){
431 });
432 
433 test("Sheet COVAR", function(){
434-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
435+  // TODO: [ISSUE-003]
436   // assertFormulaEquals('=COVAR([2, 4, 5, 1], [7, 3, 1, 3])', -2);
437 });
438 
439@@ -924,7 +917,7 @@ test("Sheet PERMUT", function(){
440 });
441 
442 test("Sheet RSQ", function(){
443-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
444+  // TODO: [ISSUE-003]
445   // assertFormulaEquals('=RSQ([10, 22, 4], [1, 3, 7])', 0.2500000000000001);
446 });
447 
448@@ -933,12 +926,12 @@ test("Sheet SKEW", function(){
449 });
450 
451 test("Sheet STEYX", function(){
452-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
453+  // TODO: [ISSUE-003]
454   // assertFormulaEquals('=STEYX([1, 2, 3, 4], [1, 3, 5, 2])', 1.4638501094227998);
455 });
456 
457 test("Sheet PROB", function(){
458-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
459+  // TODO: [ISSUE-003]
460   // assertFormulaEquals('=PROB([1, 2, 3, 4], [0.25, 0.25, 0.25, 0.25], 3)', 0.25);
461 });
462 
463@@ -947,17 +940,17 @@ test("Sheet MODE", function(){
464 });
465 
466 test("Sheet RANK", function(){
467-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
468+  // TODO: [ISSUE-003]
469   // assertFormulaEquals('=RANK([2], [1, 2, 3, 4, 5, 6, 7, 8, 9], true)', 2);
470 });
471 
472 test("Sheet RANK.AVG", function(){
473-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
474+  // TODO: [ISSUE-003]
475   // assertFormulaEquals('=RANK.AVG([2], [1, 2, 3, 4, 5, 6, 7, 8, 9], true)', 2);
476 });
477 
478 test("Sheet RANK.EQ", function(){
479-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
480+  // TODO: [ISSUE-003]
481   // assertFormulaEquals('=RANK.EQ([2], [1, 2, 3, 4, 5, 6, 7, 8, 9], true)', 2);
482 });
483 
484@@ -1027,7 +1020,7 @@ test("Sheet ROWS", function(){
485 });
486 
487 test("Sheet SERIESSUM", function() {
488-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
489+  // TODO: [ISSUE-003]
490   // assertFormulaEquals('=SERIESSUM([1], [0], [1], [4, 5, 6])', 15);
491 });
492 
493@@ -1040,7 +1033,7 @@ test("Sheet TEXT", function(){
494 });
495 
496 test("Sheet FVSCHEDULE", function(){
497-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
498+  // TODO: [ISSUE-003]
499   // assertFormulaEquals('=FVSCHEDULE([0.025], [1, 2, 3, 4])', 3.0000000000000004);
500 });
501 
502@@ -1053,7 +1046,7 @@ test("Sheet RATE", function(){
503 });
504 
505 test("Sheet SUBTOTAL", function(){
506-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
507+  // TODO: [ISSUE-003]
508   // assertFormulaEquals('=SUBTOTAL([1], [1, 2, 3, 4, 5, 6, 7])', 4);
509 });
510 
511@@ -1062,7 +1055,7 @@ test("Sheet HYPGEOMDIST", function(){
512 });
513 
514 test("Sheet ZTEST", function(){
515-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
516+  // TODO: [ISSUE-003]
517   // assertFormulaEquals('=ZTEST([1, 2, 3, 4, 5, 6, 7], 5.6, 1.1)', 0.9999405457342111);
518 });
519 
520@@ -1071,7 +1064,7 @@ test("Sheet FIND", function(){
521 });
522 
523 test("Sheet JOIN", function(){
524-  // TODO: Formulas with multiple arrays in them are temporarily disabled.
525+  // TODO: [ISSUE-003]
526   // assertFormulaEquals('=JOIN([","], [1, 2, 3])', "1,2,3");
527 });
528