spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[ISERR, ERROR.TYPE, ISERROR, ISNA] testing try-catch formulas
author
Ben Vogt <[email protected]>
date
2017-09-04 23:12:05
stats
5 file(s) changed, 46 insertions(+), 8 deletions(-)
files
TODO.md
src/Formulas/AllFormulas.ts
src/Formulas/Info.ts
tests/Formulas/InfoTest.ts
tests/SheetFormulaTest.ts
  1diff --git a/TODO.md b/TODO.md
  2index 304c36d..cdf5d6b 100644
  3--- a/TODO.md
  4+++ b/TODO.md
  5@@ -20,13 +20,16 @@ We could give each function a type-array that matches the arguments, and could b
  6 ### Fix documentation regular expression, it is butchering URLs.
  7 
  8 
  9-### ISERR, ISERROR, ISNA need to be called inside a try-catch-block inside the Parser or Sheet.
 10+### ISERROR, ISNA need to be called inside a try-catch-block inside the Parser or Sheet.
 11 
 12 
 13 ### Cells/Sheet/Parser should be able to parse raw errors in the format `#N/A`
 14 All errors should be able to be input/thrown in this way.
 15 
 16 
 17+### Parser/Sheet should be able to be initialized with js range notation (`[]`) or regular range notation (`{}`)
 18+
 19+
 20 ### Meta-Formulas to write
 21 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.
 22 
 23diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
 24index 017f049..0930dae 100644
 25--- a/src/Formulas/AllFormulas.ts
 26+++ b/src/Formulas/AllFormulas.ts
 27@@ -266,6 +266,9 @@ const __COMPLEX = {
 28 const __TRY_CATCH_FORMULAS : Object = {
 29   "ERROR.TYPE": ERRORTYPE,
 30   "ERRORTYPE": ERRORTYPE,
 31+  "ISERR": ISERR,
 32+  "ISERROR": ISERROR,
 33+  "ISNA": ISNA
 34 };
 35 
 36 export {
 37diff --git a/src/Formulas/Info.ts b/src/Formulas/Info.ts
 38index 21752cc..747c08a 100644
 39--- a/src/Formulas/Info.ts
 40+++ b/src/Formulas/Info.ts
 41@@ -159,7 +159,11 @@ let ISREF = function (value) {
 42  */
 43 let ERRORTYPE = function (value) {
 44   ArgsChecker.checkLength(arguments, 1, "ERRORTYPE");
 45-  value = TypeConverter.firstValue(value);
 46+  try {
 47+    value = TypeConverter.firstValue(value);
 48+  } catch (e) {
 49+    value = e;
 50+  }
 51   if (value instanceof Cell) {
 52     if (value.hasError()) {
 53       value = value.getError();
 54@@ -216,10 +220,14 @@ let ISBLANK = function (value) {
 55  * #N/A is present.
 56  * @returns {boolean}
 57  * @constructor
 58- * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
 59  */
 60 let ISERR = function (value) {
 61   ArgsChecker.checkLength(arguments, 1, "ISERR");
 62+  try {
 63+    value = TypeConverter.firstValue(value);
 64+  } catch (e) {
 65+    return true;
 66+  }
 67   if (value instanceof Cell) {
 68     if (value.hasError()) {
 69       return value.getError().name !== NA_ERROR;
 70@@ -238,7 +246,6 @@ let ISERR = function (value) {
 71  * @param value - is any value where a test is performed to determine whether it is an error value.
 72  * @returns {boolean}
 73  * @constructor
 74- * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
 75  */
 76 let ISERROR = function (value) {
 77   ArgsChecker.checkLength(arguments, 1, "ISERROR");
 78@@ -260,7 +267,6 @@ let ISERROR = function (value) {
 79  * @param value - The value or expression to be tested.
 80  * @returns {boolean}
 81  * @constructor
 82- * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
 83  */
 84 let ISNA = function (value) {
 85   ArgsChecker.checkLength(arguments, 1, "ISNA");
 86diff --git a/tests/Formulas/InfoTest.ts b/tests/Formulas/InfoTest.ts
 87index b0e5c41..9ba556d 100644
 88--- a/tests/Formulas/InfoTest.ts
 89+++ b/tests/Formulas/InfoTest.ts
 90@@ -178,7 +178,7 @@ test("ISERR", function(){
 91   assertEquals(ISERR(errorCell), true);
 92   assertEquals(ISERR(Cell.BuildFrom("A1", 10)), false);
 93   assertEquals(ISERR(10), false);
 94-  assertEquals(ISERR([]), false);
 95+  assertEquals(ISERR([]), true);
 96   assertEquals(ISERR(new NAError("error")), false);
 97   assertEquals(ISERR(new DivZeroError("error")), true);
 98   assertEquals(ISERR(new NameError("error")), true);
 99diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
100index 7d9178d..c3cd7aa 100644
101--- a/tests/SheetFormulaTest.ts
102+++ b/tests/SheetFormulaTest.ts
103@@ -852,15 +852,35 @@ test("Sheet ISBLANK", function(){
104 
105 test("Sheet ISERR", function(){
106   assertFormulaEquals('=ISERR(10)', false);
107+  assertFormulaEquals('=ISERR(1/0)', true);
108+  assertFormulaEquals('=ISERR(NA())', false);
109+  assertFormulaEquals('=ISERR(M7)', false);
110+  assertFormulaEquals('=ISERR([])', true);
111+  assertFormulaEquals('=ISERR(NOTAFUNCTION())', true);
112+  assertFormulaEquals('=ISERR(ACOS(44))', true);
113+  assertFormulaEqualsError('=ISERR(10e)', PARSE_ERROR);
114 });
115 
116 test("Sheet ISERROR", function(){
117   assertFormulaEquals('=ISERROR(10)', false);
118+  assertFormulaEquals('=ISERROR(1/0)', true);
119+  assertFormulaEquals('=ISERROR(NA())', true);
120+  assertFormulaEquals('=ISERROR(M7)', false);
121+  assertFormulaEquals('=ISERROR([])', true);
122+  assertFormulaEquals('=ISERROR(NOTAFUNCTION())', true);
123+  assertFormulaEquals('=ISERROR(ACOS(44))', true);
124+  assertFormulaEqualsError('=ISERROR(10e)', PARSE_ERROR);
125 });
126 
127 test("Sheet ISNA", function(){
128   assertFormulaEquals('=ISNA(10)', false);
129-});
130+  assertFormulaEquals('=ISNA(1/0)', false);
131+  assertFormulaEquals('=ISNA(NA())', true);
132+  assertFormulaEquals('=ISNA(M7)', false);
133+  assertFormulaEquals('=ISNA([])', false);
134+  assertFormulaEquals('=ISNA(NOTAFUNCTION())', false);
135+  assertFormulaEquals('=ISNA(ACOS(44))', false);
136+  assertFormulaEqualsError('=ISNA(10e)', PARSE_ERROR);});
137 
138 test("Sheet IFERROR", function(){
139   assertFormulaEquals('=IFERROR(10)', 10);
140@@ -972,6 +992,8 @@ test("Sheet ERROR.TYPE", function(){
141   sheet.setCell("M1", "= 1/0");
142   sheet.setCell("A1", "=ERROR.TYPE(M1)");
143   assertEquals(sheet.getCell("A1").getValue(), 2);
144+  // Empty range is a ref error, and should be caught by formula
145+  assertFormulaEquals('=ERROR.TYPE([])', 4);
146   // Divide by zero error should be caught by formula
147   assertFormulaEquals('=ERROR.TYPE(1/0)', 2);
148   // NA error should also be caught by formula