commit
message
[TypeConverter] adding logic for converting Cells to primitives
author
Ben Vogt <[email protected]>
date
2017-07-09 15:41:29
stats
7 file(s) changed,
144 insertions(+),
4 deletions(-)
files
TODO.md
src/Cell.ts
src/Utilities/TypeConverter.ts
tests/CellTest.ts
tests/Formulas/EngineeringTest.ts
tests/Formulas/FinancialTest.ts
tests/Utilities/TypeConverterTest.ts
1diff --git a/TODO.md b/TODO.md
2index fb09647..c5bde3d 100644
3--- a/TODO.md
4+++ b/TODO.md
5@@ -24,6 +24,10 @@ For example 64 tbs to a qt.
6 For example `=#N/A` should force an error to be thrown inside the cell.
7
8
9+### Formula's use of type-conversion could be standardized
10+We could give each function a type-array that matches the arguments, and could be used to map to the TypeConverter functions. For example if a formula looks like `THING(a: number, b: string, c: array<numbers>)` it could have a property called `typeArray = ["number", "string", "array<numbers>"]` and then for each argument it uses a map to see which TypeConverter function it should use to ensure type on those arguments. This would allow us to test these type-converters more efficiently, rather than testing to be sure each formula converted the types properly.
11+
12+
13 ### Fix documentation regular expression, it is butchering URLs.
14
15
16diff --git a/src/Cell.ts b/src/Cell.ts
17index a5358a9..ff6af9a 100644
18--- a/src/Cell.ts
19+++ b/src/Cell.ts
20@@ -164,6 +164,19 @@ class Cell {
21 toString() : string {
22 return "id=" + this.id + ", value=" + this.typedValue + ", rawFormulaText=" + this.rawFormulaText + ", error=" + this.error;
23 }
24+
25+ /**
26+ * Build a cell with an id and value.
27+ * @param id - A1-notation id or key.
28+ * @param value - value of the cell.
29+ * @returns {Cell}
30+ * @constructor
31+ */
32+ static BuildFrom(id: string, value: any) : Cell {
33+ var cell = new Cell(id);
34+ cell.setValue(value);
35+ return cell;
36+ }
37 }
38
39 function toNum(chr) {
40diff --git a/src/Utilities/TypeConverter.ts b/src/Utilities/TypeConverter.ts
41index ea479ef..235b2b4 100644
42--- a/src/Utilities/TypeConverter.ts
43+++ b/src/Utilities/TypeConverter.ts
44@@ -434,9 +434,10 @@ class TypeConverter {
45 if (value.hasError()) {
46 throw value.getError();
47 }
48- return value.getValue();
49+ value = value.getValue();
50 }
51- } else if (typeof value === "number") {
52+ }
53+ if (typeof value === "number") {
54 return value;
55 } else if (typeof value === "string") {
56 if (value === "") {
57@@ -472,6 +473,16 @@ class TypeConverter {
58 * @returns {boolean} to return.
59 */
60 public static valueToBoolean(value: any) {
61+ if (value instanceof Cell) {
62+ if (value.isBlank()) {
63+ return false;
64+ } else {
65+ if (value.hasError()) {
66+ throw value.getError();
67+ }
68+ value = value.getValue();
69+ }
70+ }
71 if (typeof value === "number") {
72 return value !== 0;
73 } else if (typeof value === "string") {
74@@ -486,7 +497,16 @@ class TypeConverter {
75 * @returns {string} string representation of value
76 */
77 public static valueToString(value: any) : string {
78- if (typeof value === "number") {
79+ if (value instanceof Cell) {
80+ if (value.isBlank()) {
81+ return "";
82+ } else {
83+ if (value.hasError()) {
84+ throw value.getError();
85+ }
86+ return value.getValue().toString();
87+ }
88+ } else if (typeof value === "number") {
89 return value.toString();
90 } else if (typeof value === "string") {
91 return value;
92@@ -501,7 +521,16 @@ class TypeConverter {
93 * @returns {number} representing a time value
94 */
95 public static valueToTimestampNumber(value: any) : number {
96- if (typeof value === "number") {
97+ if (value instanceof Cell) {
98+ if (value.isBlank()) {
99+ return 0;
100+ } else {
101+ if (value.hasError()) {
102+ throw value.getError();
103+ }
104+ return value.getValue();
105+ }
106+ } else if (typeof value === "number") {
107 return value;
108 } else if (typeof value === "string") {
109 if (value == "") {
110@@ -536,7 +565,7 @@ class TypeConverter {
111 * @returns {boolean} if could be coerced to a number
112 */
113 public static canCoerceToNumber(value: any) : boolean {
114- if (typeof value === "number" || typeof value === "boolean") {
115+ if (typeof value === "number" || typeof value === "boolean" || value instanceof Cell) {
116 return true;
117 } else if (typeof value === "string") {
118 return TypeConverter.isNumber(value);
119@@ -643,7 +672,16 @@ class TypeConverter {
120 * @returns {number} date
121 */
122 public static valueToDateNumber(value: any, coerceBoolean?: boolean) : number {
123- if (typeof value === "number") {
124+ if (value instanceof Cell) {
125+ if (value.isBlank()) {
126+ return 0;
127+ } else {
128+ if (value.hasError()) {
129+ throw value.getError();
130+ }
131+ return value.getValue();
132+ }
133+ } else if (typeof value === "number") {
134 return value;
135 } else if (typeof value === "string") {
136 try {
137diff --git a/tests/CellTest.ts b/tests/CellTest.ts
138index 5f0a2a5..a8bab0a 100644
139--- a/tests/CellTest.ts
140+++ b/tests/CellTest.ts
141@@ -37,3 +37,10 @@ test("Cell.isBlank", function(){
142 assertIsNull(v.getError());
143 assertEquals(v.isBlank(), true);
144 });
145+
146+test("Cell.BuildFrom", function(){
147+ var v = Cell.BuildFrom("A1", 10);
148+ assertEquals(v.getValue(), 10);
149+ assertIsNull(v.getError());
150+ assertEquals(v.isBlank(), false);
151+});
152diff --git a/tests/Formulas/EngineeringTest.ts b/tests/Formulas/EngineeringTest.ts
153index b425b07..4cc7dac 100644
154--- a/tests/Formulas/EngineeringTest.ts
155+++ b/tests/Formulas/EngineeringTest.ts
156@@ -13,9 +13,13 @@ import {
157 catchAndAssertEquals,
158 test
159 } from "../Utils/Asserts";
160+import {
161+ Cell
162+} from "../../src/Cell";
163
164
165 test("BIN2DEC", function(){
166+ assertEquals(BIN2DEC(Cell.BuildFrom("A1", "1010101010")), -342);
167 assertEquals(BIN2DEC("1010101010"), -342);
168 assertEquals(BIN2DEC("10"), 2);
169 assertEquals(BIN2DEC(["10", "str"]), 2);
170@@ -35,6 +39,7 @@ test("BIN2DEC", function(){
171
172
173 test("BIN2HEX", function(){
174+ assertEquals(BIN2HEX(Cell.BuildFrom("A1", "1010101010")), "FFFFFFFEAA");
175 assertEquals(BIN2HEX("1010101010"), "FFFFFFFEAA");
176 assertEquals(BIN2HEX("10"), "2");
177 assertEquals(BIN2HEX("10101010"), "AA");
178@@ -63,6 +68,7 @@ test("BIN2HEX", function(){
179
180
181 test("BIN2OCT", function(){
182+ assertEquals(BIN2OCT(Cell.BuildFrom("A1", "1010101010")), "7777777252");
183 assertEquals(BIN2OCT("1010101010"), "7777777252");
184 assertEquals(BIN2OCT("10"), "2");
185 assertEquals(BIN2OCT("100"), "4");
186@@ -91,6 +97,7 @@ test("BIN2OCT", function(){
187
188
189 test("DEC2BIN", function(){
190+ assertEquals(DEC2BIN(Cell.BuildFrom("A1", 100)), "1100100");
191 assertEquals(DEC2BIN([100]), "1100100");
192 assertEquals(DEC2BIN(100), "1100100");
193 assertEquals(DEC2BIN(22), "10110");
194@@ -126,6 +133,7 @@ test("DEC2BIN", function(){
195
196
197 test("DEC2HEX", function(){
198+ assertEquals(DEC2HEX(Cell.BuildFrom("A1", 100)), "64");
199 assertEquals(DEC2HEX([100]), "64");
200 assertEquals(DEC2HEX(100), "64");
201 assertEquals(DEC2HEX(22), "16");
202@@ -164,6 +172,7 @@ test("DEC2HEX", function(){
203
204
205 test("DEC2OCT", function(){
206+ assertEquals(DEC2OCT(Cell.BuildFrom("A1", 100)), "144");
207 assertEquals(DEC2OCT([100]), "144");
208 assertEquals(DEC2OCT(100), "144");
209 assertEquals(DEC2OCT(22), "26");
210@@ -202,6 +211,7 @@ test("DEC2OCT", function(){
211
212
213 test("DELTA", function(){
214+ assertEquals(DELTA(Cell.BuildFrom("A1", 2), 2), 1);
215 assertEquals(DELTA(2, 2), 1);
216 assertEquals(DELTA(2, 1), 0);
217 assertEquals(DELTA(2), 0);
218diff --git a/tests/Formulas/FinancialTest.ts b/tests/Formulas/FinancialTest.ts
219index 6153da6..9ca7207 100644
220--- a/tests/Formulas/FinancialTest.ts
221+++ b/tests/Formulas/FinancialTest.ts
222@@ -31,9 +31,13 @@ import {
223 catchAndAssertEquals,
224 test
225 } from "../Utils/Asserts";
226+import {
227+ Cell
228+} from "../../src/Cell";
229
230
231 test("ACCRINT", function(){
232+ assertEquals(ACCRINT(DATE(2000, 1, 1), DATE(2000, 2, 1), DATE(2002, 12, 31), 0.05, Cell.BuildFrom("A1", 100), 4), 14.98631386861314);
233 assertEquals(ACCRINT(DATE(2000, 1, 1), DATE(2000, 2, 1), DATE(2002, 12, 31), 0.05, 100, 4), 14.98631386861314);
234 assertEquals(ACCRINT(DATE(2011, 1, 1), DATE(2011, 2, 1), DATE(2014, 7, 1), 0.1, 1000, 1, 0), 350);
235 assertEquals(ACCRINT(DATE(2001, 1, 1), DATE(2011, 2, 1), DATE(2014, 7, 1), 0.1, 1000, 2, 1), 1349.6186192059456);
236@@ -66,6 +70,7 @@ test("ACCRINT", function(){
237
238
239 test("CUMPRINC", function(){
240+ assertEquals(CUMPRINC(0.12, 12, 100, 1, Cell.BuildFrom("A1", 5), false), -26.324171373034403);
241 assertEquals(CUMPRINC(0.12, 12, 100, 1, 5, false), -26.324171373034403);
242 assertEquals(CUMPRINC(0.12, 12, 100, 1, 5, 0), -26.324171373034403);
243 assertEquals(CUMPRINC(0.12, 12, 100, 1, 5, true), -34.21801015449499);
244@@ -92,6 +97,7 @@ test("CUMPRINC", function(){
245
246
247 test("CUMIPMT", function(){
248+ assertEquals(CUMIPMT(0.12, 12, 100, 1, Cell.BuildFrom("A1", 5), 0), -54.39423242396348);
249 assertEquals(CUMIPMT(0.12, 12, 100, 1, 5, 0), -54.39423242396348);
250 assertEquals(CUMIPMT(0.12, 12, 100, 1, 5, false), -54.39423242396348);
251 assertEquals(CUMIPMT(0.12, 12, 100, 1, 5, true), -37.851993235681675);
252@@ -121,6 +127,7 @@ test("CUMIPMT", function(){
253
254
255 test("DB", function(){
256+ assertEquals(DB(100, 50, 10, 2, Cell.BuildFrom("A1", 12)), 6.2482428240683285);
257 assertEquals(DB(100, 50, 10, 2, 12), 6.2482428240683285);
258 assertEquals(DB("100", "50", "10", "2", "12"), 6.2482428240683285);
259 assertEquals(DB(100, 50, 10, 2, 12.9999999), 6.2482428240683285);
260@@ -137,6 +144,7 @@ test("DB", function(){
261
262
263 test("DDB", function(){
264+ assertEquals(DDB(100, 50, 10, 2, Cell.BuildFrom("A1", 2.25)), 17.4375);
265 assertEquals(DDB(100, 50, 10, 2, 2.25), 17.4375);
266 assertEquals(DDB(100, [50], 10, 2, "2.25"), 17.4375);
267 catchAndAssertEquals(function() {
268@@ -149,6 +157,7 @@ test("DDB", function(){
269
270
271 test("DOLLAR", function(){
272+ assertEquals(DOLLAR(1.2351, Cell.BuildFrom("A1", 4)), 1.2351);
273 assertEquals(DOLLAR(1.2351, 4), 1.2351);
274 assertEquals(DOLLAR(1.2351, 2), 1.23);
275 assertEquals(DOLLAR("$3.141592653589793", "2"), 3.14);
276@@ -172,6 +181,7 @@ test("DOLLAR", function(){
277
278
279 test("DOLLARDE", function(){
280+ assertEquals(DOLLARDE(0, Cell.BuildFrom("A1", 32)), 0);
281 assertEquals(DOLLARDE(0, 32), 0);
282 assertEquals(DOLLARDE(100.1, 32), 100.3125);
283 assertEquals(DOLLARDE(100.1, 32.9999), 100.3125);
284@@ -201,6 +211,7 @@ test("DOLLARDE", function(){
285
286
287 test("DOLLARFR", function(){
288+ assertEquals(DOLLARFR(100.1, Cell.BuildFrom("A1", 32)), 100.032);
289 assertEquals(DOLLARFR(100.1, 32), 100.032);
290 assertEquals(DOLLARFR(100.1, 32), 100.032);
291 assertEquals(DOLLARFR(100.1, 32.9999), 100.032);
292@@ -230,6 +241,7 @@ test("DOLLARFR", function(){
293
294
295 test("EFFECT", function(){
296+ assertEquals(EFFECT(0.99, Cell.BuildFrom("A1", 12)), 1.5890167507927795);
297 assertEquals(EFFECT(0.99, 12), 1.5890167507927795);
298 assertEquals(EFFECT(0.99, 12.111), 1.5890167507927795);
299 assertEquals(EFFECT(0.99, 12.999), 1.5890167507927795);
300diff --git a/tests/Utilities/TypeConverterTest.ts b/tests/Utilities/TypeConverterTest.ts
301index c133ce4..c39d10e 100644
302--- a/tests/Utilities/TypeConverterTest.ts
303+++ b/tests/Utilities/TypeConverterTest.ts
304@@ -2,12 +2,23 @@
305 import * as moment from "moment";
306 import {
307 assertEquals,
308- test, catchAndAssertEquals
309+ test,
310+ catchAndAssertEquals
311 } from "../Utils/Asserts";
312 import {
313 TypeConverter
314 } from "../../src/Utilities/TypeConverter";
315-import {VALUE_ERROR, REF_ERROR} from "../../src/Errors";
316+import {
317+ VALUE_ERROR,
318+ REF_ERROR, ValueError
319+} from "../../src/Errors";
320+import {
321+ Cell
322+} from "../../src/Cell";
323+
324+var ERROR_CELL = new Cell("A1");
325+ERROR_CELL.setError(new ValueError("Whooops!"));
326+
327
328 test("TypeConverter.unitsToTimeNumber", function () {
329 assertEquals(TypeConverter.unitsToTimeNumber(10, 10, 10), 0.4237268518518518);
330@@ -62,6 +73,7 @@ test("TypeConverter.momentToNumber", function () {
331
332
333 test("TypeConverter.valueToDateNumber", function () {
334+ assertEquals(TypeConverter.valueToDateNumber(Cell.BuildFrom("A1", 10)), 10);
335 assertEquals(TypeConverter.valueToDateNumber(10), 10);
336 assertEquals(TypeConverter.valueToDateNumber("10"), 10);
337 assertEquals(TypeConverter.valueToDateNumber("10.0"), 10);
338@@ -72,6 +84,9 @@ test("TypeConverter.valueToDateNumber", function () {
339 catchAndAssertEquals(function () {
340 TypeConverter.valueToDateNumber(false); // Do not convert boolean
341 }, VALUE_ERROR);
342+ catchAndAssertEquals(function () {
343+ TypeConverter.valueToDateNumber(ERROR_CELL);
344+ }, VALUE_ERROR);
345 catchAndAssertEquals(function () {
346 console.log(TypeConverter.valueToDateNumber("str"));
347 }, VALUE_ERROR);
348@@ -79,6 +94,7 @@ test("TypeConverter.valueToDateNumber", function () {
349
350
351 test("TypeConverter.firstValueAsDateNumber", function () {
352+ assertEquals(TypeConverter.firstValueAsDateNumber([Cell.BuildFrom("A1", 10)]), 10);
353 assertEquals(TypeConverter.firstValueAsDateNumber([10]), 10);
354 assertEquals(TypeConverter.firstValueAsDateNumber([[10]]), 10);
355 assertEquals(TypeConverter.firstValueAsDateNumber([[[[[10]]]]]), 10);
356@@ -88,6 +104,9 @@ test("TypeConverter.firstValueAsDateNumber", function () {
357 assertEquals(TypeConverter.firstValueAsDateNumber(["1992-1-2"]), 33605);
358 assertEquals(TypeConverter.firstValueAsDateNumber([false], true), 0);
359 assertEquals(TypeConverter.firstValueAsDateNumber([true], true), 1);
360+ catchAndAssertEquals(function () {
361+ TypeConverter.firstValueAsDateNumber([ERROR_CELL]);
362+ }, VALUE_ERROR);
363 catchAndAssertEquals(function () {
364 TypeConverter.firstValueAsDateNumber([false]); // Do not convert boolean
365 }, VALUE_ERROR);
366@@ -112,6 +131,7 @@ test("TypeConverter.firstValue", function () {
367
368
369 test("TypeConverter.valueToTimestampNumber", function () {
370+ assertEquals(TypeConverter.valueToTimestampNumber(Cell.BuildFrom("A1", 10)), 10);
371 assertEquals(TypeConverter.valueToTimestampNumber(10), 10);
372 assertEquals(TypeConverter.valueToTimestampNumber(""), 0);
373 assertEquals(TypeConverter.valueToTimestampNumber("12:00pm"), 0.5);
374@@ -127,10 +147,15 @@ test("TypeConverter.valueToTimestampNumber", function () {
375 catchAndAssertEquals(function () {
376 TypeConverter.valueToTimestampNumber("str");
377 }, VALUE_ERROR);
378+ catchAndAssertEquals(function () {
379+ TypeConverter.valueToTimestampNumber(ERROR_CELL);
380+ }, VALUE_ERROR);
381 });
382
383
384 test("TypeConverter.valueToString", function () {
385+ assertEquals(TypeConverter.valueToString(Cell.BuildFrom("A1", 10)), "10");
386+ assertEquals(TypeConverter.valueToString(new Cell("A1")), "");
387 assertEquals(TypeConverter.valueToString(10), "10");
388 assertEquals(TypeConverter.valueToString("10"), "10");
389 assertEquals(TypeConverter.valueToString("This is a string"), "This is a string");
390@@ -138,10 +163,16 @@ test("TypeConverter.valueToString", function () {
391 assertEquals(TypeConverter.valueToString(-0.33824284782334), "-0.33824284782334");
392 assertEquals(TypeConverter.valueToString(false), "FALSE");
393 assertEquals(TypeConverter.valueToString(true), "TRUE");
394+ catchAndAssertEquals(function () {
395+ TypeConverter.valueToString(ERROR_CELL);
396+ }, VALUE_ERROR);
397 });
398
399
400 test("TypeConverter.valueToBoolean", function () {
401+ assertEquals(TypeConverter.valueToBoolean(Cell.BuildFrom("A1", 10)), true);
402+ assertEquals(TypeConverter.valueToBoolean(Cell.BuildFrom("A1", 0)), false);
403+ assertEquals(TypeConverter.valueToBoolean(new Cell("A1")), false);
404 assertEquals(TypeConverter.valueToBoolean(10), true);
405 assertEquals(TypeConverter.valueToBoolean(-10), true);
406 assertEquals(TypeConverter.valueToBoolean(1.11111), true);
407@@ -151,10 +182,15 @@ test("TypeConverter.valueToBoolean", function () {
408 catchAndAssertEquals(function () {
409 TypeConverter.valueToBoolean("str");
410 }, VALUE_ERROR);
411+ catchAndAssertEquals(function () {
412+ TypeConverter.valueToBoolean(ERROR_CELL);
413+ }, VALUE_ERROR);
414 });
415
416
417 test("TypeConverter.valueToNumber", function () {
418+ assertEquals(TypeConverter.valueToNumber(Cell.BuildFrom("A1", 10)), 10);
419+ assertEquals(TypeConverter.valueToNumber(Cell.BuildFrom("A1", "10")), 10);
420 assertEquals(TypeConverter.valueToNumber(10), 10);
421 assertEquals(TypeConverter.valueToNumber(-10), -10);
422 assertEquals(TypeConverter.valueToNumber(1.11111), 1.11111);
423@@ -171,6 +207,9 @@ test("TypeConverter.valueToNumber", function () {
424 catchAndAssertEquals(function () {
425 TypeConverter.valueToNumber("str");
426 }, VALUE_ERROR);
427+ catchAndAssertEquals(function () {
428+ TypeConverter.valueToNumber(ERROR_CELL);
429+ }, VALUE_ERROR);
430 });
431
432
433@@ -241,6 +280,9 @@ test("TypeConverter.stringToNumber", function () {
434
435
436 test("TypeConverter.valueToNumberGracefully", function () {
437+ assertEquals(TypeConverter.valueToNumberGracefully(Cell.BuildFrom("A1", "10")), 10);
438+ assertEquals(TypeConverter.valueToNumberGracefully(Cell.BuildFrom("A1", "not-graceful")), 0);
439+ assertEquals(TypeConverter.valueToNumberGracefully(new Cell("A1")), 0);
440 assertEquals(TypeConverter.valueToNumberGracefully(10), 10);
441 assertEquals(TypeConverter.valueToNumberGracefully(-10), -10);
442 assertEquals(TypeConverter.valueToNumberGracefully(1.11111), 1.11111);