fable 3.1.31 → 3.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fable.js +8 -5
- package/dist/fable.js.map +1 -1
- package/dist/fable.min.js +1 -1
- package/dist/fable.min.js.map +1 -1
- package/package.json +1 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js +5 -0
- package/source/services/Fable-Service-ExpressionParser/RNI_Randy.json +1 -0
- package/source/services/Fable-Service-ExpressionParser/RNI_Tool.json +1 -0
- package/test/ExpressionParser_tests.js +646 -638
|
@@ -18,683 +18,691 @@ function getExpressionParser()
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
suite
|
|
21
|
-
(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
(
|
|
27
|
-
'Math Expressions',
|
|
28
|
-
function()
|
|
29
|
-
{
|
|
30
|
-
test
|
|
21
|
+
(
|
|
22
|
+
'Expressions',
|
|
23
|
+
function ()
|
|
24
|
+
{
|
|
25
|
+
suite
|
|
31
26
|
(
|
|
32
|
-
'
|
|
33
|
-
(
|
|
27
|
+
'Math Expressions',
|
|
28
|
+
function ()
|
|
34
29
|
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
{
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
479
|
-
|
|
480
|
-
testFable.AppData.Value1 = "100"; // Comment
|
|
481
|
-
testFable.AppData.Value2 = "-80.5"; // Comment
|
|
482
|
-
testFable.AppData.Value3 = "10000"; // Comment
|
|
483
|
-
testFable.AppData.Value4 = "-333.333"; // Comment
|
|
484
|
-
testFable.AppData.Value5 = "0"; // Comment
|
|
485
|
-
|
|
486
|
-
let tmpResultsObject = {};
|
|
487
|
-
let tmpDestinationObject = {};
|
|
488
|
-
|
|
489
|
-
_Parser.solve('DistributionResult = distributionhistogram("AppData.Cities", "state")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
490
|
-
_Parser.solve('AggregationResult = aggregationHistogram("AppData.Cities", "state", "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
491
|
-
_Parser.solve('PopSum = sum(flatten(AppData.Cities[].population, AppData.Cities[].latitude))', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
492
|
-
|
|
493
|
-
//_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
494
|
-
//Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
|
|
495
|
-
_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
496
|
-
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('1937.23');
|
|
497
|
-
|
|
498
|
-
_Parser.solve('MadeUpValueArray = ROUND(AVG(cleanvaluearray(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5), 1)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
499
|
-
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('2421.54');
|
|
500
|
-
|
|
501
|
-
// _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, -80.5, 10000, -333.333, 0)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
502
|
-
// Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
|
|
30
|
+
test
|
|
31
|
+
(
|
|
32
|
+
'Exercise the Tokenizer',
|
|
33
|
+
(fDone) =>
|
|
34
|
+
{
|
|
35
|
+
let tmpResultObject = {};
|
|
36
|
+
let _Parser = getExpressionParser();
|
|
37
|
+
let tokenizedResults = _Parser.tokenize('5 + 2', tmpResultObject);
|
|
38
|
+
Expect(tokenizedResults.length).to.equal(3);
|
|
39
|
+
Expect(tokenizedResults).to.deep.equal(['5', '+', '2']);
|
|
40
|
+
Expect(tmpResultObject.RawExpression).to.equal('5 + 2');
|
|
41
|
+
Expect(tmpResultObject.RawTokens).to.deep.equal(tokenizedResults);
|
|
42
|
+
let complexTokenizedResults = _Parser.tokenize('5+3 - sqrt(75 / (3 + {Depth}) * Width)^ 3');
|
|
43
|
+
Expect(complexTokenizedResults.length).to.equal(18);
|
|
44
|
+
Expect(complexTokenizedResults).to.deep.equal(['5', '+', '3', '-', 'sqrt', '(', '75', '/', '(', '3', '+', '{Depth}', ')', '*', 'Width', ')', '^', '3']);
|
|
45
|
+
let complexTokenizedResultsDoubleWidthOperators = _Parser.tokenize('SpecialValue ?= 5+3 - sqrt(75 / (3 + {Depth}) * Width)^ 3');
|
|
46
|
+
Expect(complexTokenizedResultsDoubleWidthOperators.length).to.equal(20);
|
|
47
|
+
Expect(complexTokenizedResultsDoubleWidthOperators).to.deep.equal(['SpecialValue', '?=', '5', '+', '3', '-', 'sqrt', '(', '75', '/', '(', '3', '+', '{Depth}', ')', '*', 'Width', ')', '^', '3']);
|
|
48
|
+
|
|
49
|
+
let tokenizedWithSymbologyInQuotes = _Parser.tokenize('5 + 2 * "Hello World"');
|
|
50
|
+
Expect(tokenizedWithSymbologyInQuotes.length).to.equal(5);
|
|
51
|
+
Expect(tokenizedWithSymbologyInQuotes).to.deep.equal(['5', '+', '2', '*', '"Hello World"']);
|
|
52
|
+
// TODO: refresh on the tokenization process and see if this is a valid test
|
|
53
|
+
//Expect(tmpResultObject.RawExpression).to.equal('5 + 2');
|
|
54
|
+
let tokenizedNegativeParams = _Parser.tokenize('SUM(10, -10)');
|
|
55
|
+
//Expect(tokenizedNegativeParams.length).to.equal(6);
|
|
56
|
+
Expect(tokenizedNegativeParams).to.deep.equal(['SUM', '(', '10', ',', '-', '10', ')']);
|
|
57
|
+
let unbalancedParens = _Parser.tokenize('ROUND(5 + (2 * 10), 10))');
|
|
58
|
+
Expect(unbalancedParens).to.deep.equal(['ROUND', '(', '5', '+', '(', '2', '*', '10', ')', ',', '10', ')', ')']);
|
|
59
|
+
return fDone();
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
test
|
|
63
|
+
(
|
|
64
|
+
'Exercise the Linter',
|
|
65
|
+
(fDone) =>
|
|
66
|
+
{
|
|
67
|
+
let tmpResultObject = {};
|
|
68
|
+
let _Parser = getExpressionParser();
|
|
69
|
+
|
|
70
|
+
let tokenizedResults = _Parser.tokenize('5 + 2', tmpResultObject);
|
|
71
|
+
let lintedResults = _Parser.lintTokenizedExpression(tokenizedResults, tmpResultObject);
|
|
72
|
+
Expect(lintedResults.length).to.equal(1);
|
|
73
|
+
Expect(lintedResults[0]).to.contain('lintTokenizedExpression found no equality assignment in the tokenized')
|
|
74
|
+
|
|
75
|
+
let complexTokenizedResults = _Parser.tokenize('Value = 5+3 - sqrt(75 / (3 + -{Depth}) * Width)^ 3');
|
|
76
|
+
let complexLintedResults = _Parser.lintTokenizedExpression(complexTokenizedResults, tmpResultObject);
|
|
77
|
+
Expect(complexLintedResults.length).to.equal(0);
|
|
78
|
+
|
|
79
|
+
let brokenTokenizedResults = _Parser.tokenize('Value = 5+3 - sqrt(75 */ (3 + {Depth}) * Width)^ 3');
|
|
80
|
+
let brokenLintedResults = _Parser.lintTokenizedExpression(brokenTokenizedResults, tmpResultObject);
|
|
81
|
+
// The */ is invalid!!!!
|
|
82
|
+
Expect(brokenLintedResults.length).to.equal(1);
|
|
83
|
+
|
|
84
|
+
let unbalancedParensTokenizedResults = _Parser.tokenize('Value = ROUND(5 + (2 * 10), 10))');
|
|
85
|
+
let unbalancedParensLintedResults = _Parser.lintTokenizedExpression(unbalancedParensTokenizedResults, tmpResultObject);
|
|
86
|
+
// The unbalanced parens should be caught
|
|
87
|
+
Expect(unbalancedParensLintedResults.length).to.equal(1);
|
|
88
|
+
Expect(unbalancedParensLintedResults[0]).to.contain('unbalanced parenthesis');
|
|
89
|
+
return fDone();
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
test
|
|
93
|
+
(
|
|
94
|
+
'Exercise Postfix Notation Conversion',
|
|
95
|
+
(fDone) =>
|
|
96
|
+
{
|
|
97
|
+
let tmpResultObject = {};
|
|
98
|
+
|
|
99
|
+
let _Parser = getExpressionParser();
|
|
100
|
+
|
|
101
|
+
let tokenizedResults = _Parser.tokenize('= 5 + 2', tmpResultObject);
|
|
102
|
+
let lintedResults = _Parser.lintTokenizedExpression(tokenizedResults, tmpResultObject);
|
|
103
|
+
let postfixResults = _Parser.buildPostfixedSolveList(tokenizedResults, tmpResultObject);
|
|
104
|
+
Expect(postfixResults.length).to.equal(2);
|
|
105
|
+
|
|
106
|
+
let negativeConstantResults = _Parser.tokenize('Value = (-5 + 3)');
|
|
107
|
+
let negativeConstantValueLintedResults = _Parser.lintTokenizedExpression(negativeConstantResults);
|
|
108
|
+
let negativeConstantValueResults = _Parser.buildPostfixedSolveList(negativeConstantResults);
|
|
109
|
+
Expect(negativeConstantValueResults.length).to.equal(3);
|
|
110
|
+
|
|
111
|
+
let complexTokenizedResults = _Parser.tokenize('Value = 5+3 - sqrt(75 / (3 + -{Depth}) * Width)^ 3');
|
|
112
|
+
let complexLintedResults = _Parser.lintTokenizedExpression(complexTokenizedResults);
|
|
113
|
+
let complexPostfixResults = _Parser.buildPostfixedSolveList(complexTokenizedResults);
|
|
114
|
+
Expect(complexPostfixResults.length).to.equal(9);
|
|
115
|
+
|
|
116
|
+
return fDone();
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
test
|
|
120
|
+
(
|
|
121
|
+
'Exercise Variable Lookup and Substitution',
|
|
122
|
+
(fDone) =>
|
|
123
|
+
{
|
|
124
|
+
let _Parser = getExpressionParser();
|
|
125
|
+
|
|
126
|
+
let tmpResultObject = {};
|
|
127
|
+
let tmpDataObject = { X: 5, Y: 3, Z: 75, Depth: 3, Width: 2 };
|
|
128
|
+
let tmpDestinationObject = {};
|
|
129
|
+
|
|
130
|
+
let tmpArea = _Parser.solve('Area = X * Y * Z', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
131
|
+
|
|
132
|
+
Expect(tmpArea).to.equal("1125");
|
|
133
|
+
Expect(tmpDestinationObject.Area).to.equal("1125");
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
let tmpVariableAssignment = _Parser.solve('NewX = X', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
137
|
+
let tmpConstantAssignment = _Parser.solve('NewConst = 8.675309', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
138
|
+
let tmpStringAssignment = _Parser.solve('NewString = "Hello World!"', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
139
|
+
|
|
140
|
+
Expect(tmpDestinationObject.NewX).to.equal("5");
|
|
141
|
+
Expect(tmpDestinationObject.NewConst).to.equal("8.675309");
|
|
142
|
+
Expect(tmpDestinationObject.NewString).to.equal("Hello World!");
|
|
143
|
+
|
|
144
|
+
return fDone();
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
test
|
|
148
|
+
(
|
|
149
|
+
'Exercise Marshaling to Value at a Hashed Address',
|
|
150
|
+
(fDone) =>
|
|
151
|
+
{
|
|
152
|
+
|
|
153
|
+
let testFable = new libFable();
|
|
154
|
+
testFable.AppData = { Pit: "Bottomless" };
|
|
155
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
156
|
+
|
|
157
|
+
let tmpDataObject = { X: 5.867, Y: 3.1, Z: 75, Depth: 3, Width: 2 };
|
|
158
|
+
let tmpResultObject = {};
|
|
159
|
+
let tmpDestinationObject = {};
|
|
160
|
+
|
|
161
|
+
_Parser.solve('Area = X * Y * Z', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
162
|
+
Expect(tmpDestinationObject.Area).to.equal("1364.0775");
|
|
163
|
+
|
|
164
|
+
_Parser.solve('PitSize = getvalue("AppData.Pit")', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
165
|
+
Expect(tmpDestinationObject.PitSize).to.equal("Bottomless");
|
|
166
|
+
|
|
167
|
+
_Parser.solve('Value = -3', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
168
|
+
Expect(tmpDestinationObject.Value).to.equal("-3");
|
|
169
|
+
|
|
170
|
+
_Parser.solve('Value2 = (4 + -3)', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
171
|
+
Expect(tmpDestinationObject.Value2).to.equal("1");
|
|
172
|
+
|
|
173
|
+
_Parser.solve('ValueN = 5+3 - sqrt(75 / (3 + -1) * 2)^ 3', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
174
|
+
Expect(testFable.Math.ltPrecise(
|
|
175
|
+
testFable.Math.absPrecise(
|
|
176
|
+
testFable.Math.subtractPrecise(tmpDestinationObject.ValueN, "-641.5190528383289850727923780647")),
|
|
177
|
+
'0.00000000000000001'))
|
|
178
|
+
.to.equal(true, 'Expected complex expression to be with a small epsilon of the computed value');
|
|
179
|
+
|
|
180
|
+
tmpDataObject.Temp = '24';
|
|
181
|
+
tmpDataObject.HR = '20.5';
|
|
182
|
+
_Parser.solve('2.71828182845905 ^ -0.282444', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
183
|
+
testFable.ExpressionParser.Messaging.logFunctionSolve(tmpResultObject);
|
|
184
|
+
_Parser.solve('EGS=ROUND(ROUND(0.0172834*2.71828182845905^(-0.0117685*Temp),5)*SQRT(ROUND(16.294-0.163*HR,1)/60),4)',
|
|
185
|
+
tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
186
|
+
_Parser.solve('EGSR=ROUND(ROUND(0.0172834*2.71828182845905^(((1-2)*0.0117685)*Temp),5)*SQRT(ROUND(16.294-0.163*HR,1)/60),4)',
|
|
187
|
+
tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
188
|
+
Expect(tmpDestinationObject.EGS).to.equal(tmpDestinationObject.EGSR);
|
|
189
|
+
testFable.ExpressionParser.Messaging.logFunctionSolve(tmpResultObject);
|
|
190
|
+
Expect(tmpDestinationObject.EGS).to.equal("0.0061");
|
|
191
|
+
|
|
192
|
+
tmpDataObject.EJBinderGb1 = '15.5';
|
|
193
|
+
tmpDataObject.EKPctBinderPb2 = '2.55555';
|
|
194
|
+
_Parser.solve('EGse1 = Round((100 - EJBinderGb1) / EKPctBinderPb2), 2)', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
195
|
+
//TODO: we can consider solving and ignoring this paren, but for now, the error is fatal
|
|
196
|
+
Expect(tmpDestinationObject.EGse1).to.not.exist;
|
|
197
|
+
testFable.ExpressionParser.Messaging.logFunctionSolve(tmpResultObject);
|
|
198
|
+
|
|
199
|
+
_Parser.solve('EGse1 = Round((100 - EJBinderGb1) / EKPctBinderPb2, 2)', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
200
|
+
Expect(tmpDestinationObject.EGse1).to.equal('33.07');
|
|
201
|
+
|
|
202
|
+
_Parser.solve('EGse1 = Round((100 - EJBinderGb1) / EKPctBinderPb2), 2)', tmpDataObject, tmpResultObject, false, tmpDestinationObject);
|
|
203
|
+
// ensure that this does mutate the output on error
|
|
204
|
+
Expect(tmpDestinationObject.EGse1).to.not.exist;
|
|
205
|
+
|
|
206
|
+
return fDone();
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
test
|
|
210
|
+
(
|
|
211
|
+
'Test iterative series',
|
|
212
|
+
(fDone) =>
|
|
213
|
+
{
|
|
214
|
+
let testFable = new libFable();
|
|
215
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
216
|
+
|
|
217
|
+
let tmpResult = _Parser.solve('Result = ITERATIVESERIES(Values, "Value", "Resultant", 1, "add")',
|
|
218
|
+
{
|
|
219
|
+
Values: [
|
|
220
|
+
{ Value: 10 },
|
|
221
|
+
{ Value: 20 },
|
|
222
|
+
{ Value: 5 }
|
|
223
|
+
]
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
Expect(tmpResult[0].Resultant).to.equal("10");
|
|
227
|
+
Expect(tmpResult[1].Resultant).to.equal("30");
|
|
228
|
+
Expect(tmpResult[2].Resultant).to.equal("35");
|
|
229
|
+
|
|
230
|
+
return fDone();
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
test
|
|
234
|
+
(
|
|
235
|
+
'Exercise End-to-End Expression Parsing',
|
|
236
|
+
(fDone) =>
|
|
237
|
+
{
|
|
238
|
+
let _Parser = getExpressionParser();
|
|
239
|
+
|
|
240
|
+
Expect(_Parser.solve('1 + 1')).to.equal("2");
|
|
241
|
+
Expect(_Parser.solve('1 * 1')).to.equal("1");
|
|
242
|
+
Expect(_Parser.solve('1 / 1')).to.equal("1");
|
|
243
|
+
Expect(_Parser.solve('1 - 1')).to.equal("0");
|
|
244
|
+
Expect(_Parser.solve('10 * 2')).to.equal("20");
|
|
245
|
+
|
|
246
|
+
Expect(_Parser.solve('200 * 1.5')).to.equal("300");
|
|
247
|
+
Expect(_Parser.solve('7 +13')).to.equal("20");
|
|
248
|
+
Expect(_Parser.solve('7+14')).to.equal("21");
|
|
249
|
+
|
|
250
|
+
Expect(_Parser.solve('Result = datemilliseconddifference("2023-08-10T05:00:00.000Z", "2023-08-11T05:00:00.000Z")')).to.equal("86400000");
|
|
251
|
+
Expect(_Parser.solve('Result = datemilliseconddifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("86400000");
|
|
252
|
+
Expect(_Parser.solve('Result = datemilliseconddifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:11:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("85740000");
|
|
253
|
+
Expect(_Parser.solve('Result = datemilliseconddifference(StartDate, EndDate, 1)', { StartDate: "2023-08-10T05:11:00.000Z" })).to.equal('NaN');
|
|
254
|
+
Expect(_Parser.solve('Result = dateseconddifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("86400");
|
|
255
|
+
Expect(_Parser.solve('Result = datehourdifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("24");
|
|
256
|
+
Expect(_Parser.solve('Result = dateminutedifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("1440");
|
|
257
|
+
Expect(_Parser.solve('Result = datehourdifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("24");
|
|
258
|
+
Expect(_Parser.solve('Result = datedaydifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("1");
|
|
259
|
+
Expect(_Parser.solve('Result = dateweekdifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2023-05-22T05:00:00.000Z" })).to.equal("-11");
|
|
260
|
+
Expect(_Parser.solve('Result = datemonthdifference(StartDate, EndDate)', { StartDate: "2023-08-10T05:00:00.000Z", EndDate: "2021-01-11T05:00:00.000Z" })).to.equal("-30");
|
|
261
|
+
Expect(_Parser.solve('Result = dateyeardifference(StartDate, EndDate)', { StartDate: "1986-08-10T05:00:00.000Z", EndDate: "2023-08-11T05:00:00.000Z" })).to.equal("37");
|
|
262
|
+
|
|
263
|
+
Expect(_Parser.solve('5 + 2 * 10')).to.equal("25");
|
|
264
|
+
Expect(_Parser.solve('3.5 + 5 + 10 * 10 / 5')).to.equal("28.5");
|
|
265
|
+
|
|
266
|
+
Expect(_Parser.solve('3.5 + 5 + 10 * 10 / 5 - 1.5')).to.equal("27");
|
|
267
|
+
|
|
268
|
+
Expect(_Parser.solve('(100 - 10)')).to.equal("90");
|
|
269
|
+
|
|
270
|
+
Expect(_Parser.solve('100.55 - 1.55')).to.equal("99");
|
|
271
|
+
|
|
272
|
+
Expect(_Parser.solve('5 + 2')).to.equal('7');
|
|
273
|
+
|
|
274
|
+
Expect(_Parser.solve('50.22 + 2')).to.equal('52.22');
|
|
275
|
+
|
|
276
|
+
Expect(_Parser.solve('5 ^ 2')).to.equal('25');
|
|
277
|
+
|
|
278
|
+
Expect(_Parser.solve('Result = sqrt(100 * (C + 30)) + sin(Depth - Width) / 10', { "PR": 1.5, "Z": "20.036237", "C": -13, Depth: 100.203, Width: 10.5 })).to.equal('41.32965489638783839821');
|
|
279
|
+
|
|
280
|
+
Expect(_Parser.solve('((15000 * 2) / 4)^2 + 100 - 10 * (35 + 5)')).to.equal("56249700");
|
|
281
|
+
|
|
282
|
+
Expect(_Parser.solve('1.5 * sqrt(8 * 2.423782342^2) / 10')).to.equal('1.02832375808904701855')
|
|
283
|
+
Expect(_Parser.solve('1 * sqrt(16)')).to.equal('4');
|
|
284
|
+
|
|
285
|
+
Expect(_Parser.solve('sin(rad(60))')).to.equal('0.8660254037844386');
|
|
286
|
+
|
|
287
|
+
Expect(_Parser.solve('Result = 5+3 - sqrt(75 / (3 + Depth) * Width)^ 3', { "PR": 1.5, "Z": "20.036237", "C": -13, Depth: 100.203, Width: 10.5 }))
|
|
288
|
+
.to.equal('-13.078386362213538715906797395732300153182132216343566001917247')
|
|
289
|
+
|
|
290
|
+
let tmpResult = _Parser.solve('Result = (160 * PR * Z) / (C / 100) * PR * Z + (160 * (1 - C / 100))', { C: -13, PR: 1.5, Z: 20.03 })
|
|
291
|
+
Expect(tmpResult).to.equal("-1110837.0769230769230769230307");
|
|
292
|
+
|
|
293
|
+
let tmpResultPrecise = _Parser.solve('Result = (160 * PR * Z) / (C / 100) * PR * Z + (160 * (1 - C / 100))', { C: "-13", PR: "1.5", Z: "20.03" })
|
|
294
|
+
Expect(tmpResultPrecise).to.equal("-1110837.0769230769230769230307");
|
|
295
|
+
|
|
296
|
+
return fDone();
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
test
|
|
300
|
+
(
|
|
301
|
+
'Exercise End-to-End Expression Parsing with Sets',
|
|
302
|
+
(fDone) =>
|
|
303
|
+
{
|
|
304
|
+
let _Parser = getExpressionParser();
|
|
305
|
+
|
|
306
|
+
Expect(_Parser.solve('1 + 1')).to.equal("2");
|
|
307
|
+
Expect(_Parser.solve("Volume = Width * Height * Depth", { "Width": 73.5, "Height": 28.8, "Depth": 200.5 })).to.equal("424418.4");
|
|
308
|
+
Expect(_Parser.solve("TotalCost = SUM(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("400");
|
|
309
|
+
Expect(_Parser.solve("TotalCost = MEAN(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("80");
|
|
310
|
+
Expect(_Parser.solve("TotalCost = MEDIAN(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("50");
|
|
311
|
+
Expect(_Parser.solve("TotalCost = COUNT(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("5");
|
|
312
|
+
|
|
313
|
+
_Parser.fable.AppData = {
|
|
314
|
+
Teams: [
|
|
315
|
+
{ Team: 'Mariners', States: 'Washington', Score: 100 },
|
|
316
|
+
{ Team: 'Yankees', States: 'New York', Score: 200 },
|
|
317
|
+
{ Team: 'Mets', States: 'New York', Score: 50 },
|
|
318
|
+
{ Team: 'Giants', States: 'California', Score: 45 },
|
|
319
|
+
{ Team: 'Dodgers', States: 'California', Score: 5 },
|
|
320
|
+
{ Team: 'Astros', States: 'Texas', Score: 75 }
|
|
321
|
+
]
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
let tmpHistogramByReference = _Parser.solve(`aggregationhistogram("AppData.Teams", "States", "Score")`);
|
|
325
|
+
Expect(tmpHistogramByReference['New York']).to.equal("250");
|
|
326
|
+
|
|
327
|
+
let tmpHistogram = _Parser.solve(`aggregationhistogrambyobject(getvalue("AppData.Teams"), "States", "Score")`);
|
|
328
|
+
Expect(tmpHistogram['New York']).to.equal("250");
|
|
329
|
+
|
|
330
|
+
Expect(_Parser.solve("DateFromPartsExample = DATEFROMPARTS(2025, 4, 1)")).to.equal("2025-04-01T00:00:00.000Z");
|
|
331
|
+
Expect(_Parser.solve("DateFromPartsExample = DATEADDDAYS(DATEFROMPARTS(2025, 4, 1, 13, 03, 51, 761),87)")).to.equal("2025-06-27T13:03:51.761Z");
|
|
332
|
+
|
|
333
|
+
return fDone();
|
|
334
|
+
}
|
|
335
|
+
);
|
|
336
|
+
test
|
|
337
|
+
(
|
|
338
|
+
'Exercise Value Marshaling',
|
|
339
|
+
(fDone) =>
|
|
340
|
+
{
|
|
341
|
+
let _Parser = getExpressionParser();
|
|
342
|
+
|
|
343
|
+
Expect(_Parser.solve('1 + 1')).to.equal("2");
|
|
344
|
+
Expect(_Parser.solve("Volume = Width * Height * Depth", { "Width": 73.5, "Height": 28.8, "Depth": 200.5 })).to.equal("424418.4");
|
|
345
|
+
Expect(_Parser.solve("TotalCost = SUM(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("400");
|
|
346
|
+
Expect(_Parser.solve("TotalCost = MEAN(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("80");
|
|
347
|
+
Expect(_Parser.solve("TotalCost = MEDIAN(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("50");
|
|
348
|
+
Expect(_Parser.solve("TotalCost = COUNT(ItemCosts)", { "ItemCosts": [100, 200, 50, 45, 5] })).to.equal("5");
|
|
349
|
+
|
|
350
|
+
return fDone();
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
test
|
|
354
|
+
(
|
|
355
|
+
'Exercise Rounding',
|
|
356
|
+
(fDone) =>
|
|
357
|
+
{
|
|
358
|
+
let _Parser = getExpressionParser();
|
|
359
|
+
|
|
360
|
+
let tmpSolveResults = {};
|
|
361
|
+
let tmpDataObject = { X: 5.867, Y: 3.1, Z: 75, Depth: 3, Width: 2 };
|
|
362
|
+
// 1364.0775
|
|
363
|
+
let tmpResult = _Parser.solve('Area = ROUND(X * Y * Z)', tmpDataObject, tmpSolveResults);
|
|
364
|
+
Expect(tmpResult).to.equal("1364");
|
|
365
|
+
tmpResult = _Parser.solve('Area = ROUND(X * Y * Z, 2)', tmpDataObject, tmpSolveResults);
|
|
366
|
+
Expect(tmpResult).to.equal("1364.08");
|
|
367
|
+
return fDone();
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
test
|
|
371
|
+
(
|
|
372
|
+
'Exercise Multi-parameter Functions',
|
|
373
|
+
(fDone) =>
|
|
374
|
+
{
|
|
375
|
+
let _Parser = getExpressionParser();
|
|
376
|
+
|
|
377
|
+
let tmpSolveResults = {};
|
|
378
|
+
let tmpDataObject = { X: 5.867, Y: 3.5, Z: 75.248923423, Depth: 3, Width: 2 };
|
|
379
|
+
// 1364.0775
|
|
380
|
+
let tmpResult = _Parser.solve('Area = ROUND(X * Y * Z)', tmpDataObject, tmpSolveResults);
|
|
381
|
+
Expect(tmpResult).to.equal("1545");
|
|
382
|
+
tmpResult = _Parser.solve('Area = ROUND(X * Y * Z, 3, 3)', tmpDataObject, tmpSolveResults);
|
|
383
|
+
Expect(tmpResult).to.equal("1545.2");
|
|
384
|
+
// Test the getvaluarray function]
|
|
385
|
+
// TODO: Fix the return values for these expression return functions
|
|
386
|
+
//tmpResult = _Parser.solve('NewSet = GETVALUEARRAY(X, Y, Z)', tmpDataObject, tmpSolveResults);
|
|
387
|
+
//tmpResult = _Parser.solve('NewSetAverage = SUM(NewSet)', tmpDataObject, tmpSolveResults);
|
|
388
|
+
//Expect(tmpResult).to.equal("84.115923423");
|
|
389
|
+
return fDone();
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
test
|
|
393
|
+
(
|
|
394
|
+
'Exercise Complex Assignments',
|
|
395
|
+
(fDone) =>
|
|
396
|
+
{
|
|
397
|
+
let testFable = new libFable();
|
|
398
|
+
|
|
399
|
+
testFable.AppData = { Students: ["Kim", "Jim", "Joan Jett", "Tank Girl"] };
|
|
400
|
+
|
|
401
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
402
|
+
|
|
403
|
+
let tmpResultObject = {};
|
|
404
|
+
|
|
405
|
+
let tmpSolveResults = {};
|
|
406
|
+
let tmpDataObject = { X: 5.867, Y: 3.5, Z: 75.248923423, Depth: 3, Width: 2, Name: "Jerry" };
|
|
407
|
+
|
|
408
|
+
_Parser.solve('Area = ROUND(X * Y * Z, 3, 3)', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
409
|
+
|
|
410
|
+
// Because the results object doesn't have a name in it, the null coalescence assignment operator should just work
|
|
411
|
+
let tmpResult = _Parser.solve('Name ?= GETVALUE("AppData.Students[0]")', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
412
|
+
Expect(tmpResultObject.Name).to.equal("Kim");
|
|
413
|
+
|
|
414
|
+
tmpResult = _Parser.solve('Area = ROUND(X * Y * Z, 3, 3)', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
415
|
+
Expect(tmpResult).to.equal("1545.2");
|
|
416
|
+
|
|
417
|
+
// Now that name is set, it shouldn't change.
|
|
418
|
+
tmpResult = _Parser.solve('Name ?= GETVALUE("AppData.Students[1]")', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
419
|
+
Expect(tmpResultObject.Name).to.equal("Kim");
|
|
420
|
+
|
|
421
|
+
// Regular assignment should change it.
|
|
422
|
+
tmpResult = _Parser.solve('Name = GETVALUE("AppData.Students[1]")', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
423
|
+
Expect(tmpResultObject.Name).to.equal("Jim");
|
|
424
|
+
|
|
425
|
+
// Regular assignment should change it.
|
|
426
|
+
tmpResult = _Parser.solve('Name = GETVALUE("AppData.Students[3]")', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
427
|
+
Expect(tmpResultObject.Name).to.equal("Tank Girl");
|
|
428
|
+
|
|
429
|
+
// Regular assignment should change it (with an array out of bounds problem...)
|
|
430
|
+
tmpResult = _Parser.solve('Name = GETVALUE("AppData.Students[4]")', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
431
|
+
Expect(tmpResultObject.Name).to.equal(undefined);
|
|
432
|
+
|
|
433
|
+
return fDone();
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
test
|
|
437
|
+
(
|
|
438
|
+
'Exercise Data Generation',
|
|
439
|
+
(fDone) =>
|
|
440
|
+
{
|
|
441
|
+
let testFable = new libFable();
|
|
442
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
443
|
+
|
|
444
|
+
let tmpDataObject = {};
|
|
445
|
+
let tmpSolveResults = {};
|
|
446
|
+
let tmpResultObject = {};
|
|
447
|
+
|
|
448
|
+
let tmpResult;
|
|
449
|
+
tmpResult = _Parser.solve('RandomIntValue = RANDOMINTEGER()', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
450
|
+
Expect(tmpResult).to.not.be.NaN;
|
|
451
|
+
|
|
452
|
+
tmpResult = _Parser.solve('RandomIntValueBetween = RANDOMINTEGERBETWEEN(10, 13)', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
453
|
+
Expect(parseInt(tmpResult)).to.be.at.least(10);
|
|
454
|
+
Expect(parseInt(tmpResult)).to.be.at.most(13);
|
|
455
|
+
|
|
456
|
+
tmpResult = _Parser.solve('RandomFloatValue = randomFloat()', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
457
|
+
Expect(tmpResult).to.not.be.NaN;
|
|
458
|
+
|
|
459
|
+
tmpResult = _Parser.solve('RandomFloatValueBetween = randomFloatBetween(10.5, 13.78)', tmpDataObject, tmpSolveResults, false, tmpResultObject);
|
|
460
|
+
Expect(parseFloat(tmpResult)).to.be.at.least(10.5);
|
|
461
|
+
Expect(parseFloat(tmpResult)).to.be.at.most(13.78);
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
return fDone();
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
test
|
|
468
|
+
(
|
|
469
|
+
'Complex Histogram Arithmatic',
|
|
470
|
+
(fDone) =>
|
|
471
|
+
{
|
|
472
|
+
let testFable = new libFable();
|
|
503
473
|
|
|
474
|
+
let testCityData = require('./data/cities.json');
|
|
475
|
+
testFable.AppData = { Cities: testCityData };
|
|
504
476
|
|
|
505
|
-
|
|
506
|
-
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('550.83');
|
|
477
|
+
// let tmpDistribution = testFable.Math.histogramDistributionByExactValue(testFable.AppData.Cities, 'state');
|
|
507
478
|
|
|
508
|
-
|
|
509
|
-
|
|
479
|
+
// Expect(tmpDistribution.Alabama).to.equal(12);
|
|
480
|
+
// Expect(tmpDistribution.Colorado).to.equal(21);
|
|
481
|
+
// Expect(tmpDistribution.Florida).to.equal(73);
|
|
482
|
+
// Expect(tmpDistribution.Georgia).to.equal(18);
|
|
510
483
|
|
|
484
|
+
// Now through the solver
|
|
511
485
|
|
|
512
|
-
|
|
513
|
-
Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
|
|
486
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
514
487
|
|
|
515
|
-
|
|
516
|
-
|
|
488
|
+
testFable.AppData.Value1 = "100"; // Comment
|
|
489
|
+
testFable.AppData.Value2 = "-80.5"; // Comment
|
|
490
|
+
testFable.AppData.Value3 = "10000"; // Comment
|
|
491
|
+
testFable.AppData.Value4 = "-333.333"; // Comment
|
|
492
|
+
testFable.AppData.Value5 = "0"; // Comment
|
|
517
493
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
);
|
|
521
|
-
test
|
|
522
|
-
(
|
|
523
|
-
'plumbing histogram into aggregation',
|
|
524
|
-
() =>
|
|
525
|
-
{
|
|
526
|
-
let testFable = new libFable();
|
|
494
|
+
let tmpResultsObject = {};
|
|
495
|
+
let tmpDestinationObject = {};
|
|
527
496
|
|
|
528
|
-
|
|
529
|
-
|
|
497
|
+
_Parser.solve('DistributionResult = distributionhistogram("AppData.Cities", "state")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
498
|
+
_Parser.solve('AggregationResult = aggregationHistogram("AppData.Cities", "state", "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
499
|
+
_Parser.solve('PopSum = sum(flatten(AppData.Cities[].population, AppData.Cities[].latitude))', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
530
500
|
|
|
531
|
-
|
|
501
|
+
//_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
502
|
+
//Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
|
|
503
|
+
_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
504
|
+
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('1937.23');
|
|
532
505
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
testFable.AppData.ResultsObject = tmpResultsObject;
|
|
536
|
-
let tmpDestinationObject = {};
|
|
537
|
-
testFable.AppData.DestinationObject = tmpDestinationObject;
|
|
506
|
+
_Parser.solve('MadeUpValueArray = ROUND(AVG(cleanvaluearray(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5), 1)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
507
|
+
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('2421.54');
|
|
538
508
|
|
|
539
|
-
_Parser.solve('
|
|
540
|
-
|
|
509
|
+
// _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, -80.5, 10000, -333.333, 0)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
510
|
+
// Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
|
|
541
511
|
|
|
542
|
-
Expect(tmpDestinationObject.DistributionResult.Alabama).to.equal(12);
|
|
543
|
-
Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
|
|
544
512
|
|
|
545
|
-
|
|
513
|
+
_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, 10, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
514
|
+
Expect(tmpDestinationObject.MadeUpValueArray).to.equal('550.83');
|
|
546
515
|
|
|
547
|
-
|
|
548
|
-
|
|
516
|
+
// _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(-5, 5, 0, -10, 10, -25, 25, -50, 50)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
517
|
+
// Expect(tmpDestinationObject.MadeUpValueArray).to.equal('25');
|
|
549
518
|
|
|
550
|
-
_Parser.solve('Smallest = smallestinset(AppData.Cities[], "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
551
|
-
Expect(tmpDestinationObject.Smallest.population).to.equal('36877');
|
|
552
519
|
|
|
553
|
-
|
|
554
|
-
|
|
520
|
+
Expect(tmpDestinationObject.DistributionResult.Alabama).to.equal(12);
|
|
521
|
+
Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
|
|
555
522
|
|
|
556
|
-
|
|
557
|
-
|
|
523
|
+
Expect(tmpDestinationObject.AggregationResult.Alabama).to.equal('1279813');
|
|
524
|
+
Expect(tmpDestinationObject.PopSum).to.equal(testCityData.reduce((sum, city) => testFable.Math.addPrecise(city.population, sum), '0'));
|
|
558
525
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
suite
|
|
569
|
-
(
|
|
570
|
-
'Data Expressions',
|
|
571
|
-
function()
|
|
572
|
-
{
|
|
573
|
-
test
|
|
574
|
-
(
|
|
575
|
-
'Concatenates Strings',
|
|
576
|
-
() =>
|
|
577
|
-
{
|
|
578
|
-
let testFable = new libFable();
|
|
526
|
+
return fDone();
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
test
|
|
530
|
+
(
|
|
531
|
+
'plumbing histogram into aggregation',
|
|
532
|
+
() =>
|
|
533
|
+
{
|
|
534
|
+
let testFable = new libFable();
|
|
579
535
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
{
|
|
583
|
-
Cities: testCityData.slice(0, 4),
|
|
584
|
-
CityNames: testCityData.slice(0, 4).map((c) => c.city),
|
|
585
|
-
Null: null,
|
|
586
|
-
};
|
|
587
|
-
testFable.AppData.CityNames[2] = { };
|
|
588
|
-
testFable.AppData.Cities[2].city = { cat: '12345', dog: 'waffle' };
|
|
536
|
+
let testCityData = require('./data/cities.json');
|
|
537
|
+
testFable.AppData = { Cities: testCityData };
|
|
589
538
|
|
|
590
|
-
|
|
539
|
+
// Now through the solver
|
|
591
540
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
541
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
542
|
+
let tmpResultsObject = {};
|
|
543
|
+
testFable.AppData.ResultsObject = tmpResultsObject;
|
|
544
|
+
let tmpDestinationObject = {};
|
|
545
|
+
testFable.AppData.DestinationObject = tmpDestinationObject;
|
|
595
546
|
|
|
596
|
-
|
|
597
|
-
|
|
547
|
+
_Parser.solve('DistributionResult = distributionhistogram("AppData.Cities", "state")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
548
|
+
_Parser.solve('AggregationResult = aggregationHistogram("AppData.Cities", "state", "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
598
549
|
|
|
599
|
-
|
|
600
|
-
|
|
550
|
+
Expect(tmpDestinationObject.DistributionResult.Alabama).to.equal(12);
|
|
551
|
+
Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
|
|
601
552
|
|
|
602
|
-
|
|
603
|
-
Expect(tmpDestinationObject.RawNames).to.equal('New YorkLos Angeles[object Object]Houston');
|
|
553
|
+
Expect(tmpDestinationObject.AggregationResult.Alabama).to.equal('1279813');
|
|
604
554
|
|
|
605
|
-
|
|
606
|
-
|
|
555
|
+
_Parser.solve('SumByAddress = SUM(FLATTEN(AppData.DestinationObject.AggregationResult))', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
556
|
+
Expect(tmpDestinationObject.SumByAddress).to.equal(testCityData.reduce((sum, city) => testFable.Math.addPrecise(city.population, sum), '0'));
|
|
607
557
|
|
|
608
|
-
|
|
609
|
-
|
|
558
|
+
_Parser.solve('Smallest = smallestinset(AppData.Cities[], "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
559
|
+
Expect(tmpDestinationObject.Smallest.population).to.equal('36877');
|
|
610
560
|
|
|
611
|
-
|
|
612
|
-
|
|
561
|
+
_Parser.solve('Largest = largestinset(AppData.Cities[], "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
562
|
+
Expect(tmpDestinationObject.Largest.city).to.equal('New York');
|
|
613
563
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
Expect(tmpDestinationObject.RawNamesArgs).to.equal('New Yorkarg name');
|
|
564
|
+
_Parser.solve('Tenth = entryinset(AppData.Cities[], "population", "-10")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
565
|
+
Expect(tmpDestinationObject.Tenth.city).to.equal('San Jose');
|
|
617
566
|
|
|
618
|
-
|
|
619
|
-
|
|
567
|
+
_Parser.solve('TenthNum = entryinset(AppData.Cities[], "population", -10)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
568
|
+
Expect(tmpDestinationObject.TenthNum.city).to.equal('San Jose');
|
|
620
569
|
|
|
621
|
-
|
|
622
|
-
|
|
570
|
+
_Parser.solve('TenthNumHacked = entryinset(AppData.Cities[], "population", (10 * -1))', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
571
|
+
Expect(tmpDestinationObject.TenthNumHacked.city).to.equal('San Jose');
|
|
572
|
+
}
|
|
573
|
+
);
|
|
623
574
|
}
|
|
624
575
|
);
|
|
625
|
-
|
|
626
|
-
);
|
|
627
|
-
suite
|
|
628
|
-
(
|
|
629
|
-
'Conditional Expressions',
|
|
630
|
-
function()
|
|
631
|
-
{
|
|
632
|
-
test
|
|
576
|
+
suite
|
|
633
577
|
(
|
|
634
|
-
'
|
|
635
|
-
()
|
|
578
|
+
'Data Expressions',
|
|
579
|
+
function ()
|
|
636
580
|
{
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
581
|
+
test
|
|
582
|
+
(
|
|
583
|
+
'Concatenates Strings',
|
|
584
|
+
() =>
|
|
585
|
+
{
|
|
586
|
+
let testFable = new libFable();
|
|
587
|
+
|
|
588
|
+
let testCityData = require('./data/cities.json');
|
|
589
|
+
testFable.AppData =
|
|
590
|
+
{
|
|
591
|
+
Cities: testCityData.slice(0, 4),
|
|
592
|
+
CityNames: testCityData.slice(0, 4).map((c) => c.city),
|
|
593
|
+
Null: null,
|
|
594
|
+
};
|
|
595
|
+
testFable.AppData.CityNames[2] = {};
|
|
596
|
+
testFable.AppData.Cities[2].city = { cat: '12345', dog: 'waffle' };
|
|
597
|
+
|
|
598
|
+
// Now through the solver
|
|
599
|
+
|
|
600
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
601
|
+
let tmpResultsObject = {};
|
|
602
|
+
let tmpDestinationObject = {};
|
|
603
|
+
|
|
604
|
+
_Parser.solve('Names = concat(AppData.Cities[].city)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
605
|
+
Expect(tmpDestinationObject.Names).to.equal('New YorkLos AngelesHouston');
|
|
606
|
+
|
|
607
|
+
_Parser.solve('Names2 = concat(AppData.CityNames)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
608
|
+
Expect(tmpDestinationObject.Names2).to.equal('New YorkLos AngelesHouston');
|
|
609
|
+
|
|
610
|
+
_Parser.solve('RawNames = concatRaw(AppData.CityNames)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
611
|
+
Expect(tmpDestinationObject.RawNames).to.equal('New YorkLos Angeles[object Object]Houston');
|
|
612
|
+
|
|
613
|
+
_Parser.solve('JoinedNames = join(", ", AppData.CityNames)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
614
|
+
Expect(tmpDestinationObject.JoinedNames).to.equal('New York, Los Angeles, Houston');
|
|
615
|
+
|
|
616
|
+
_Parser.solve('RawJoinedNames = joinRaw(" ", AppData.CityNames)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
617
|
+
Expect(tmpDestinationObject.RawJoinedNames).to.equal('New York Los Angeles [object Object] Houston');
|
|
618
|
+
|
|
619
|
+
_Parser.solve('NamesArgs = concat("cat", "dog", "waffle")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
620
|
+
Expect(tmpDestinationObject.NamesArgs).to.equal('catdogwaffle');
|
|
621
|
+
|
|
622
|
+
testFable.AppData.CityName = 'New York';
|
|
623
|
+
_Parser.solve('RawNamesArgs = concatRaw(AppData.CityName, "arg name")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
624
|
+
Expect(tmpDestinationObject.RawNamesArgs).to.equal('New Yorkarg name');
|
|
625
|
+
|
|
626
|
+
_Parser.solve('JoinedNamesArgs = join(", ", AppData.CityNames[1], AppData.CityNames[2])', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
627
|
+
Expect(tmpDestinationObject.JoinedNamesArgs).to.equal('Los Angeles');
|
|
628
|
+
|
|
629
|
+
_Parser.solve('RawJoinedNamesArgs = joinRaw(" ", AppData.Cities[].city, "My Extra City")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
630
|
+
Expect(tmpDestinationObject.RawJoinedNamesArgs).to.equal('New York Los Angeles [object Object] Houston My Extra City');
|
|
631
|
+
}
|
|
632
|
+
);
|
|
662
633
|
}
|
|
663
634
|
);
|
|
664
|
-
|
|
665
|
-
test
|
|
635
|
+
suite
|
|
666
636
|
(
|
|
667
|
-
'Conditional
|
|
668
|
-
()
|
|
637
|
+
'Conditional Expressions',
|
|
638
|
+
function ()
|
|
669
639
|
{
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
640
|
+
test
|
|
641
|
+
(
|
|
642
|
+
'Conditional When',
|
|
643
|
+
() =>
|
|
644
|
+
{
|
|
645
|
+
let testFable = new libFable();
|
|
646
|
+
|
|
647
|
+
let testCityData = require('./data/cities.json');
|
|
648
|
+
testFable.AppData =
|
|
649
|
+
{
|
|
650
|
+
Cities: testCityData.slice(0, 4),
|
|
651
|
+
Null: null,
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
// Now through the solver
|
|
655
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
656
|
+
let tmpResultsObject = {};
|
|
657
|
+
let tmpDestinationObject = {};
|
|
658
|
+
|
|
659
|
+
_Parser.solve('Name = When(AppData.Cities[0].city, AppData.Cities[0].city)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
660
|
+
Expect(tmpDestinationObject.Name).to.equal('New York');
|
|
661
|
+
|
|
662
|
+
_Parser.solve('Overrun = When(AppData.Cities[10000000].city, AppData.Cities[10000000].city)', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
663
|
+
Expect(tmpDestinationObject.Overrun).to.equal('');
|
|
664
|
+
|
|
665
|
+
testFable.AppData.ECDMonth = 'January';
|
|
666
|
+
testFable.AppData.ECDYear = '2023';
|
|
667
|
+
_Parser.solve('EstimatedCompletionDate = ResolveHtmlEntities(When(AppData.ECDMonth, Join(", ", AppData.ECDMonth, AppData.ECDYear)))',
|
|
668
|
+
testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
669
|
+
Expect(tmpDestinationObject.EstimatedCompletionDate).to.equal('January, 2023');
|
|
670
|
+
}
|
|
671
|
+
);
|
|
672
|
+
|
|
673
|
+
test
|
|
674
|
+
(
|
|
675
|
+
'Conditional If',
|
|
676
|
+
() =>
|
|
677
|
+
{
|
|
678
|
+
let testFable = new libFable();
|
|
679
|
+
|
|
680
|
+
let testCityData = require('./data/cities.json');
|
|
681
|
+
testFable.AppData =
|
|
682
|
+
{
|
|
683
|
+
Cities: testCityData.slice(0, 4),
|
|
684
|
+
Null: null,
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
// Now through the solver
|
|
688
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
689
|
+
let tmpResultsObject = {};
|
|
690
|
+
let tmpDestinationObject = {};
|
|
691
|
+
|
|
692
|
+
_Parser.solve('GTE = If(AppData.Cities[0].latitude, "<", "50", "west", "east")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
693
|
+
Expect(tmpDestinationObject.GTE).to.equal('west');
|
|
694
|
+
|
|
695
|
+
_Parser.solve('Equals = If(AppData.Cities[0].city, "==", "New York", "yes", "no")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
696
|
+
Expect(tmpDestinationObject.Equals).to.equal('yes');
|
|
697
|
+
|
|
698
|
+
_Parser.solve('EpsilonEquals = If("1.0000000001", "==", "1", "yes", "no")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
699
|
+
Expect(tmpDestinationObject.EpsilonEquals).to.equal('yes');
|
|
700
|
+
|
|
701
|
+
_Parser.solve('PreciseEquals = If("1.0000000001", "===", "1", "yes", "no")', testFable, tmpResultsObject, false, tmpDestinationObject);
|
|
702
|
+
Expect(tmpDestinationObject.PreciseEquals).to.equal('no');
|
|
703
|
+
}
|
|
704
|
+
);
|
|
695
705
|
}
|
|
696
706
|
);
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
}
|
|
700
|
-
);
|
|
707
|
+
}
|
|
708
|
+
);
|