commit
message
[EOMONTH, README.md] formula written and tested, adding testing best-practices for readme
author
Ben Vogt <[email protected]>
date
2017-04-02 18:56:53
stats
4 file(s) changed,
85 insertions(+),
10 deletions(-)
files
README.md
src/RawFormulas/Date.ts
tests/DateFormulasTest.ts
tests/FormulasTest.ts
1diff --git a/README.md b/README.md
2index 8b7774b..f3512bf 100644
3--- a/README.md
4+++ b/README.md
5@@ -64,3 +64,13 @@ Right now we're just using the number of days since 1900, but we should check th
6 * Verify that all white-space wild cards are implemented properly
7
8 * Verify that all N-times ({2,9}) are correct, and we're not parsing numbers too big.
9+
10+
11+# Testing Guidelines
12+
13+All formulas should test for:
14+1) One *less* argument than the formula expects, and one *more* argument than the formula expects.
15+2) If it accepts a number, test with false as 0, and true as 1.
16+3) If it accepts a number, test with string parsing to number.
17+4) If it accepts a date, test with number, number as string, date as string.
18+5) Individual arguments as ranges with single values (eg: `[1]`), and ranges as multiple values (eg: `[1, "str"]`).
19diff --git a/src/RawFormulas/Date.ts b/src/RawFormulas/Date.ts
20index 137b65d..a782a89 100644
21--- a/src/RawFormulas/Date.ts
22+++ b/src/RawFormulas/Date.ts
23@@ -83,13 +83,29 @@ var EDATE = function (...values) : ExcelDate {
24 };
25
26
27+/**
28+ * Returns a date representing the last day of a month which falls a specified number of months before or after another
29+ * date.
30+ * @param values[0] start_date - The date from which to calculate the the result.
31+ * @param values[1] months - The number of months before (negative) or after (positive) start_date to consider. The last
32+ * calendar day of the calculated month is returned.
33+ * @returns {ExcelDate} the last day of a month
34+ * @constructor
35+ */
36+var EOMONTH = function (...values) : ExcelDate {
37+ ArgsChecker.checkLength(values, 2);
38+ var startDate = TypeCaster.firstValueAsExcelDate(values[0]);
39+ var months = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
40+ // While ExcelDate.toNumber() will return an inclusive count of days since 1900/1/1, moment.Moment.add assumes
41+ // exclusive count of days.
42+ return new ExcelDate(moment.utc(ORIGIN_MOMENT).add(startDate.toNumber() - 2, "days").add(months, "months").endOf("month"));
43+};
44+
45+
46 var DAY = Formula["DAY"];
47 var DAYS = Formula["DAYS"];
48 var DAYS360 = Formula["DAYS360"];
49-var EOMONTH = function (start_date, months) {
50- var edate = moment(start_date).add(months, 'months');
51- return new Date(edate.year(), edate.month(), edate.daysInMonth());
52-};
53+
54 var YEARFRAC = Formula["YEARFRAC"];
55
56 // Functions unimplemented.
57diff --git a/tests/DateFormulasTest.ts b/tests/DateFormulasTest.ts
58index 6b6ba10..be9d600 100644
59--- a/tests/DateFormulasTest.ts
60+++ b/tests/DateFormulasTest.ts
61@@ -1,5 +1,5 @@
62
63-import { DATE, DATEVALUE, EDATE } from "../src/RawFormulas/RawFormulas"
64+import { DATE, DATEVALUE, EDATE, EOMONTH } from "../src/RawFormulas/RawFormulas"
65 import * as ERRORS from "../src/Errors"
66 import {assertEquals} from "./utils/Asserts"
67 import moment = require("moment");
68@@ -19,25 +19,61 @@ function catchAndAssertEquals(toExecute, expected) {
69 }
70 }
71
72-// // Test EDATE
73+// Test EDATE
74 assertEquals(EDATE(DATE(1992, 6, 24), 1), DATE(1992, 7, 24));
75 assertEquals(EDATE(DATE(1992, 5, 24), 2), DATE(1992, 7, 24));
76 assertEquals(EDATE(DATE(1992, 5, 24), 2.2), DATE(1992, 7, 24));
77+assertEquals(EDATE(DATE(1992, 6, 24), 0), DATE(1992, 6, 24));
78+assertEquals(EDATE(DATE(1992, 6, 24), false), DATE(1992, 6, 24));
79 assertEquals(EDATE("1992, 5, 24", 2), DATE(1992, 7, 24));
80 assertEquals(EDATE("6/24/92", 1), DATE(1992, 7, 24));
81+assertEquals(EDATE([DATE(1992, 6, 24), "str"], [1, "str"]), DATE(1992, 7, 24));
82 catchAndAssertEquals(function() {
83 EDATE("str", 2);
84 }, ERRORS.VALUE_ERROR);
85+catchAndAssertEquals(function() {
86+ EDATE(DATE(1992, 6, 24));
87+}, ERRORS.NA_ERROR);
88+catchAndAssertEquals(function() {
89+ EDATE(DATE(1992, 6, 24), 4, 4);
90+}, ERRORS.NA_ERROR);
91+
92+
93+// Test EOMONTH
94+assertEquals(EOMONTH(DATE(1992, 6, 24), 0), DATE(1992, 6, 30));
95+assertEquals(EOMONTH(DATE(1992, 6, 24), false), DATE(1992, 6, 30));
96+assertEquals(EOMONTH(DATE(1992, 6, 24), 1), DATE(1992, 7, 31));
97+assertEquals(EOMONTH(DATE(1992, 6, 24), 2), DATE(1992, 8, 31));
98+assertEquals(EOMONTH(DATE(2012, 6, 24), 2), DATE(2012, 8, 31));
99+assertEquals(EOMONTH(DATE(2049, 1, 1), 2), DATE(2049, 3, 31));
100+assertEquals(EOMONTH(DATE(1990, 2, 24), 400), DATE(2023, 6, 30));
101+assertEquals(EOMONTH("1992, 6, 24", 2), DATE(1992, 8, 31));
102+//leap years
103+assertEquals(EOMONTH(DATE(2004, 2, 24), 0), DATE(2004, 2, 29));
104+assertEquals(EOMONTH(DATE(2008, 2, 24), 0), DATE(2008, 2, 29));
105+// misc.
106+assertEquals(EOMONTH([DATE(1992, 6, 24), "str"], [2, "str"]), DATE(1992, 8, 31));
107+catchAndAssertEquals(function() {
108+ EOMONTH("str", 2);
109+}, ERRORS.VALUE_ERROR);
110+catchAndAssertEquals(function() {
111+ EOMONTH(false, 2);
112+}, ERRORS.VALUE_ERROR);
113
114
115 // Test DATE
116 assertEquals(DATE(1900, 1, 2).toNumber(), 3);
117 assertEquals(DATE(1900, 1, 1).toNumber(), 2);
118 assertEquals(DATE(1900, 1, 4).toNumber(), 5);
119-
120 catchAndAssertEquals(function() {
121 DATE(1900, 0, 5);
122 }, ERRORS.NUM_ERROR);
123+catchAndAssertEquals(function() {
124+ DATE(1900, 0, 5, 22);
125+}, ERRORS.NA_ERROR);
126+catchAndAssertEquals(function() {
127+ DATE(1900, 0);
128+}, ERRORS.NA_ERROR);
129 assertEquals(DATE(1992, 6, 24).toNumber(), 33779);
130 assertEquals(DATE(2017, 2, 26).toNumber(), 42792);
131 assertEquals(DATE(1999, 1, 13).toNumber(), 36173);
132diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
133index 8acbc14..d49c1d6 100644
134--- a/tests/FormulasTest.ts
135+++ b/tests/FormulasTest.ts
136@@ -2,12 +2,12 @@ import { ABS, ACCRINT, ACOS, ACOSH, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN, ATAN2
137 AVERAGEA, AVERAGEIF, BIN2DEC, BIN2HEX, BIN2OCT, CEILING,
138 CHAR, CODE, COMBIN, CONCATENATE, CONVERT, PEARSON,
139 CORREL, COS, PI, COSH, COT, COTH, COUNT, COUNTA, COUNTIF, COUNTIFS, COUNTUNIQUE,
140- CUMIPMT, CUMPRINC, DATE, DATEVALUE, DAY, DAYS, DAYS360,
141- DB, DDB, DEC2BIN, DEC2HEX, DEC2OCT, DEGREES, DELTA, DEVSQ, DOLLAR, DOLLARDE, DOLLARFR, EDATE,
142- EFFECT, EOMONTH, ERF, ERFC, EVEN, EXACT, EXPONDIST, FINV, FALSE, FLOOR, __COMPLEX, FISHER, FISHERINV, IF,
143+ CUMIPMT, CUMPRINC,
144+ DB, DDB, DEC2BIN, DEC2HEX, DEC2OCT, DEGREES, DELTA, DEVSQ, DOLLAR, DOLLARDE, DOLLARFR,
145+ EFFECT, ERF, ERFC, EVEN, EXACT, EXPONDIST, FINV, FALSE, FLOOR, __COMPLEX, FISHER, FISHERINV, IF,
146 INT, ISEVEN, ISODD, LN, LOG, LOG10, MAX, MAXA, MEDIAN, MIN, MINA, MOD, NOT, TRUE, ODD, OR,
147 POWER, ROUND, ROUNDDOWN, ROUNDUP, SIN, SINH, SPLIT, SQRT, SQRTPI, SUM, SUMIF, SUMPRODUCT, RADIANS,
148- SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas/RawFormulas"
149+ SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR } from "../src/RawFormulas/RawFormulas"
150 import * as ERRORS from "../src/Errors"
151 import {assertEquals, assertArrayEquals} from "./utils/Asserts"
152