1 | const {compile, and, or, root, arg0, arg1, setter, splice, bind, chain} = require('../../index');
|
2 | const {
|
3 | describeCompilers,
|
4 | evalOrLoad,
|
5 | currentValues,
|
6 | funcLibrary,
|
7 | expectTapFunctionToHaveBeenCalled,
|
8 | rand
|
9 | } = require('../test-utils');
|
10 | const _ = require('lodash');
|
11 |
|
12 | describe('testing array', () => {
|
13 | describeCompilers(['simple', 'optimizing', 'bytecode'], compiler => {
|
14 | describe('map', () => {
|
15 | it('simple map', () => {
|
16 | const model = {negated: root.map(val => val.not().call('tap')), set: setter(arg0)};
|
17 | const optCode = evalOrLoad(compile(model, {compiler}));
|
18 | const inst = optCode([true, true, false, false, false], funcLibrary);
|
19 | expect(inst.negated).toEqual([false, false, true, true, true]);
|
20 | expectTapFunctionToHaveBeenCalled(inst.$model.length, compiler);
|
21 | inst.set(1, false);
|
22 | expect(inst.negated).toEqual([false, true, true, true, true]);
|
23 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
24 | });
|
25 | it('simple map with effect', () => {
|
26 | const model = {effect: root.map(val => or(val.ternary(chain(true).effect('tap'), null), val)), set: setter(arg0)};
|
27 | const optCode = evalOrLoad(compile(model, {compiler}));
|
28 | const inst = optCode([true, true, false, false, false], funcLibrary);
|
29 | expect(inst.effect).toEqual([true, true, false, false, false]);
|
30 | expectTapFunctionToHaveBeenCalled(inst.$model.filter(k => k).length, {compiler: 'optimizing'});
|
31 | inst.set(1, false);
|
32 | expect(inst.effect).toEqual([true, false, false, false, false]);
|
33 | expectTapFunctionToHaveBeenCalled(0, {compiler: 'optimizing'});
|
34 | inst.set(2, true);
|
35 | expect(inst.effect).toEqual([true, false, true, false, false]);
|
36 | expectTapFunctionToHaveBeenCalled(1, {compiler: 'optimizing'});
|
37 | });
|
38 | it('map return empty object if falsy', () => {
|
39 | const model = {orEmpty: root.map(val => or(val, {}).call('tap')), set: setter(arg0)};
|
40 | const optCode = evalOrLoad(compile(model, {compiler}));
|
41 | const inst = optCode([{x: 1}, false, {x: 2}], funcLibrary);
|
42 | expect(inst.orEmpty).toEqual([{x: 1}, {}, {x: 2}]);
|
43 | expectTapFunctionToHaveBeenCalled(inst.$model.length, compiler);
|
44 | inst.set(2, false);
|
45 | expect(inst.orEmpty).toEqual([{x: 1}, {}, {}]);
|
46 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
47 | });
|
48 | it('map return empty object if falsy', () => {
|
49 | const model = {orEmpty: root.map(val => or(val, []).call('tap')), set: setter(arg0)};
|
50 | const optCode = evalOrLoad(compile(model, {compiler}));
|
51 | const inst = optCode([[1], false, [2]], funcLibrary);
|
52 | expect(inst.orEmpty).toEqual([[1], [], [2]]);
|
53 | expectTapFunctionToHaveBeenCalled(inst.$model.length, compiler);
|
54 | inst.set(2, false);
|
55 | expect(inst.orEmpty).toEqual([[1], [], []]);
|
56 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
57 | });
|
58 | });
|
59 |
|
60 | describe('any', () => {
|
61 | it('simple any', () => {
|
62 | const model = {
|
63 | anyTruthy: root.any(val => val.call('tap')),
|
64 | set: setter(arg0)
|
65 | };
|
66 | const optModel = evalOrLoad(compile(model, {compiler}));
|
67 | const inst = optModel([true, false, false, false, false], funcLibrary);
|
68 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
69 | expect(inst.anyTruthy).toEqual(true);
|
70 | inst.set(0, false);
|
71 | expectTapFunctionToHaveBeenCalled(inst.$model.length, compiler);
|
72 | expect(inst.anyTruthy).toEqual(false);
|
73 | inst.set(3, true);
|
74 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
75 | expect(inst.anyTruthy).toEqual(true);
|
76 | inst.set(4, true);
|
77 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
78 | expect(inst.anyTruthy).toEqual(true);
|
79 | inst.set(3, false);
|
80 | expectTapFunctionToHaveBeenCalled(2, compiler);
|
81 | expect(inst.anyTruthy).toEqual(true);
|
82 | inst.set(4, false);
|
83 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
84 | expect(inst.anyTruthy).toEqual(false);
|
85 | });
|
86 |
|
87 | it('any when removing elements', () => {
|
88 | const model = {
|
89 | anyTruthy: root.get('data').any(a => a.get('val')),
|
90 | set: setter('data', arg0),
|
91 | clear: setter('data')
|
92 | };
|
93 | const optModel = evalOrLoad(compile(model, {compiler}));
|
94 | const inst = optModel({data: [{val: false}, {val: true}, {val: false}]}, funcLibrary);
|
95 | expect(inst.anyTruthy).toEqual(true);
|
96 | inst.clear([]);
|
97 | expect(inst.anyTruthy).toEqual(false);
|
98 | });
|
99 | })
|
100 |
|
101 | it('simple keyBy', () => {
|
102 | const model = {
|
103 | itemByIdx: root.keyBy(val => val.get('idx')).mapValues(val => val.get('text').call('tap')),
|
104 | set: setter(arg0),
|
105 | splice: splice()
|
106 | };
|
107 | const optModel = evalOrLoad(compile(model, {compiler}));
|
108 | const inst = optModel([{idx: 1, text: 'a'}, {idx: 2, text: 'b'}, {idx: 3, text: 'c'}], funcLibrary);
|
109 | expectTapFunctionToHaveBeenCalled(3, compiler);
|
110 | expect(inst.itemByIdx).toEqual({1: 'a', 2: 'b', 3: 'c'});
|
111 | inst.set(0, {idx: 4, text: 'd'});
|
112 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
113 | expect(inst.itemByIdx).toEqual({4: 'd', 2: 'b', 3: 'c'});
|
114 | inst.splice(1, 2, {idx: 3, text: 'e'});
|
115 | expect(inst.itemByIdx).toEqual({4: 'd', 3: 'e'});
|
116 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
117 | const reverseArray = [...inst.$model].reverse();
|
118 | inst.splice(0, inst.$model.length, ...reverseArray);
|
119 | expect(inst.itemByIdx).toEqual({4: 'd', 3: 'e'});
|
120 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
121 | });
|
122 |
|
123 | it('raw keyBy', () => {
|
124 | const model = {
|
125 | itemByIdx: root.keyBy(val => val.get('idx')),
|
126 | set: setter(arg0),
|
127 | splice: splice()
|
128 | };
|
129 | const optModel = evalOrLoad(compile(model, {compiler}));
|
130 | const inst = optModel([{idx: 1, text: 'a', foo: 'bar'}, {idx: 2, text: 'b'}, {idx: 1, text: 'c'}], funcLibrary);
|
131 | expect(inst.itemByIdx).toEqual({1: {idx: 1, text: 'c'}, 2: {idx: 2, text: 'b'}});
|
132 | });
|
133 |
|
134 | it('double-valued keyBy', () => {
|
135 | const model = {
|
136 | asObject: root.keyBy(val => val),
|
137 | set: setter(arg0)
|
138 | };
|
139 | const optModel = evalOrLoad(compile(model, {compiler}));
|
140 | const inst = optModel(['a', 'a'], funcLibrary);
|
141 | expect(inst.asObject).toEqual({a: 'a'})
|
142 | inst.set(0, 'b')
|
143 | expect(inst.asObject).toEqual({a: 'a', b: 'b'})
|
144 | });
|
145 |
|
146 | it('simple comparison operations', () => {
|
147 | const arr = root.get('arr');
|
148 | const compareTo = root.get('compareTo');
|
149 | const model = {
|
150 | greaterThan: arr.map(val => val.gt(compareTo).call('tap')),
|
151 | lessThan: arr.map(val => val.lt(compareTo).call('tap')),
|
152 | greaterOrEqual: arr.map(val => val.gte(compareTo).call('tap')),
|
153 | lessThanOrEqual: arr.map(val => val.lte(compareTo).call('tap')),
|
154 | setArr: setter('arr', arg0),
|
155 | setCompareTo: setter('compareTo')
|
156 | };
|
157 | const optModel = evalOrLoad(compile(model, {compiler}));
|
158 | const inst = optModel({arr: [0, 1, 2, 3, 4], compareTo: 2}, funcLibrary);
|
159 | expect(currentValues(inst)).toEqual({
|
160 | greaterThan: [false, false, false, true, true],
|
161 | lessThan: [true, true, false, false, false],
|
162 | greaterOrEqual: [false, false, true, true, true],
|
163 | lessThanOrEqual: [true, true, true, false, false]
|
164 | });
|
165 | expectTapFunctionToHaveBeenCalled(20, compiler);
|
166 | inst.setArr(4, 0);
|
167 | expect(currentValues(inst)).toEqual({
|
168 | greaterThan: [false, false, false, true, false],
|
169 | lessThan: [true, true, false, false, true],
|
170 | greaterOrEqual: [false, false, true, true, false],
|
171 | lessThanOrEqual: [true, true, true, false, true]
|
172 | });
|
173 | expectTapFunctionToHaveBeenCalled(4, compiler);
|
174 | inst.setCompareTo(100);
|
175 | expect(currentValues(inst)).toEqual({
|
176 | greaterThan: [false, false, false, false, false],
|
177 | lessThan: [true, true, true, true, true],
|
178 | greaterOrEqual: [false, false, false, false, false],
|
179 | lessThanOrEqual: [true, true, true, true, true]
|
180 | });
|
181 | expectTapFunctionToHaveBeenCalled(6, compiler);
|
182 | });
|
183 | it('test creation of arrays', () => {
|
184 | const sumsTuple = root.map(item => [item.get(0).plus(item.get(1))]);
|
185 | const mapOfSum = sumsTuple.map(item => item.get(0).call('tap'));
|
186 |
|
187 | const model = {mapOfSum, set0: setter(arg0, 0), set1: setter(arg0, 1)};
|
188 | const optCode = evalOrLoad(compile(model, {compiler}));
|
189 | const initialData = [[1, 2], [3, 4], [5, 6]];
|
190 | const inst = optCode(initialData, funcLibrary);
|
191 | expect(inst.mapOfSum).toEqual([3, 7, 11]);
|
192 | expectTapFunctionToHaveBeenCalled(3, compiler);
|
193 | inst.set0(0, 7);
|
194 | expect(inst.mapOfSum).toEqual([9, 7, 11]);
|
195 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
196 | inst.$startBatch();
|
197 | inst.set0(1, 4);
|
198 | inst.set1(1, 3);
|
199 | inst.$endBatch();
|
200 | expect(inst.mapOfSum).toEqual([9, 7, 11]);
|
201 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
202 | });
|
203 | it('test assign/defaults', () => {
|
204 | const model = {
|
205 | assign: root.assign().mapValues(val => val.call('tap')),
|
206 | defaults: root.defaults().mapValues(val => val.call('tap')),
|
207 | set: setter(arg0),
|
208 | setInner: setter(arg0, arg1),
|
209 | splice: splice()
|
210 | };
|
211 | const optCode = evalOrLoad(compile(model, {compiler}));
|
212 | const initialData = [{a: 1}, {b: 2}, {a: 5}];
|
213 | const inst = optCode(initialData, funcLibrary);
|
214 | expect(currentValues(inst)).toEqual({assign: {a: 5, b: 2}, defaults: {a: 1, b: 2}});
|
215 | expectTapFunctionToHaveBeenCalled(4, compiler);
|
216 | inst.set(0, {a: 7});
|
217 | expect(currentValues(inst)).toEqual({assign: {a: 5, b: 2}, defaults: {a: 7, b: 2}});
|
218 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
219 | inst.setInner(2, 'a', 9);
|
220 | expect(currentValues(inst)).toEqual({assign: {a: 9, b: 2}, defaults: {a: 7, b: 2}});
|
221 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
222 | inst.splice(1, 1);
|
223 | expect(currentValues(inst)).toEqual({assign: {a: 9}, defaults: {a: 7}});
|
224 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
225 | });
|
226 | it('ranges', () => {
|
227 | const model = {
|
228 | range: root
|
229 | .get('end')
|
230 | .range()
|
231 | .map(item => item.call('tap')),
|
232 | rangeStart: root
|
233 | .get('end')
|
234 | .range(root.get('start'))
|
235 | .map(item => item.call('tap')),
|
236 | rangeStep: root
|
237 | .get('end')
|
238 | .range(root.get('start'), root.get('step'))
|
239 | .map(item => item.call('tap')),
|
240 | setEnd: setter('end'),
|
241 | setStep: setter('step'),
|
242 | setStart: setter('start')
|
243 | };
|
244 | const initialData = {start: 2, end: 5, step: 2};
|
245 | const optCode = evalOrLoad(compile(model, {compiler}));
|
246 | const inst = optCode(initialData, funcLibrary);
|
247 | expect(inst.range).toEqual([0, 1, 2, 3, 4]);
|
248 | expect(inst.rangeStart).toEqual([2, 3, 4]);
|
249 | expect(inst.rangeStep).toEqual([2, 4]);
|
250 | expectTapFunctionToHaveBeenCalled(10, compiler);
|
251 | inst.setEnd(7);
|
252 | expect(inst.range).toEqual([0, 1, 2, 3, 4, 5, 6]);
|
253 | expect(inst.rangeStart).toEqual([2, 3, 4, 5, 6]);
|
254 | expect(inst.rangeStep).toEqual([2, 4, 6]);
|
255 | expectTapFunctionToHaveBeenCalled(5, compiler);
|
256 | });
|
257 | it('test range/size', () => {
|
258 | const matches = root.get('items').filter(val => val.eq(root.get('match')));
|
259 | const model = {
|
260 | fizzBuzz: matches
|
261 | .size()
|
262 | .range(1)
|
263 | .map(val =>
|
264 | val
|
265 | .mod(15)
|
266 | .eq(0)
|
267 | .ternary(
|
268 | 'fizzbuzz',
|
269 | val
|
270 | .mod(3)
|
271 | .eq(0)
|
272 | .ternary(
|
273 | 'fizz',
|
274 | val
|
275 | .mod(5)
|
276 | .eq(0)
|
277 | .ternary('buzz', val)
|
278 | )
|
279 | )
|
280 | )
|
281 | .map(val => val.call('tap')),
|
282 | spliceItems: splice('items'),
|
283 | setMatch: setter('match')
|
284 | };
|
285 | const initialData = {
|
286 | items: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2],
|
287 | match: 1
|
288 | };
|
289 | const optCode = evalOrLoad(compile(model, {compiler}));
|
290 | const inst = optCode(initialData, funcLibrary);
|
291 | expect(inst.fizzBuzz).toEqual([1, 2, 'fizz', 4, 'buzz']);
|
292 | inst.setMatch(0);
|
293 | expect(inst.fizzBuzz).toEqual([
|
294 | 1,
|
295 | 2,
|
296 | 'fizz',
|
297 | 4,
|
298 | 'buzz',
|
299 | 'fizz',
|
300 | 7,
|
301 | 8,
|
302 | 'fizz',
|
303 | 'buzz',
|
304 | 11,
|
305 | 'fizz',
|
306 | 13,
|
307 | 14,
|
308 | 'fizzbuzz'
|
309 | ]);
|
310 | inst.setMatch(2);
|
311 | expect(inst.fizzBuzz).toEqual([1, 2, 'fizz']);
|
312 | });
|
313 | it('range from primitive', () => {
|
314 | const model = {
|
315 | result: chain(10)
|
316 | .range()
|
317 | .filter(item => item.mod(root.get('skip')).eq(0))
|
318 | .map(item => item.call('tap')),
|
319 | set: setter('skip')
|
320 | };
|
321 | const optModel = evalOrLoad(compile(model, {compiler}));
|
322 | const initialData = {skip: 3};
|
323 | const inst = optModel(initialData, funcLibrary);
|
324 | expect(inst.result).toEqual([0, 3, 6, 9]);
|
325 | expectTapFunctionToHaveBeenCalled(4, compiler);
|
326 | inst.set(6);
|
327 | expect(inst.result).toEqual([0, 6]);
|
328 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
329 | });
|
330 | it('range to map from length 0', () => {
|
331 | const model = {
|
332 | result: chain(root.get('len'))
|
333 | .range()
|
334 | .map(item => item.plus(root.get('base')).call('tap')),
|
335 | set: setter('len')
|
336 | };
|
337 | const optModel = evalOrLoad(compile(model, {compiler}));
|
338 | const initialData = {len: 0, base: 2};
|
339 | const inst = optModel(initialData, funcLibrary);
|
340 | expect(inst.result).toEqual([]);
|
341 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
342 | inst.set(1);
|
343 | expect(inst.result).toEqual([2]);
|
344 | expectTapFunctionToHaveBeenCalled(1, compiler);
|
345 | });
|
346 | it('flatten thats not deep', () => {
|
347 | const model = {
|
348 | result: root.flatten().map((v) => v),
|
349 | set: setter(arg0)
|
350 | }
|
351 | const optModel = evalOrLoad(compile(model, {compiler}))
|
352 | const initialData = [[1], [3], [4, [5]]]
|
353 | const inst = optModel(initialData, funcLibrary)
|
354 | expect(inst.result).toEqual([1, 3, 4, [5]])
|
355 | inst.set(0, [2])
|
356 | expect(inst.result).toEqual([2, 3, 4, [5]])
|
357 | })
|
358 | it('flatten thats not deep with objects', () => {
|
359 | const model = {
|
360 | result: root.flatten().map((v) => v),
|
361 | set: setter(arg0)
|
362 | }
|
363 | const optModel = evalOrLoad(compile(model, {compiler}))
|
364 | const initialData = [[{a: 1}], [{a: 3}], [{a: 4}]]
|
365 | const inst = optModel(initialData, funcLibrary)
|
366 | expect(inst.result).toEqual([{a: 1}, {a: 3}, {a: 4}])
|
367 | })
|
368 | it('flatten array changes length', () => {
|
369 | const model = {
|
370 | clean: root.get('target'),
|
371 | data: root.get('target').map(v => v),
|
372 | result: root.get('target').map(v => v).flatten(),
|
373 | result2: root.get('target').flatten(),
|
374 | splice: splice('target')
|
375 | }
|
376 | const optModel = evalOrLoad(compile(model, {compiler}))
|
377 | const initialData = {target: [[1], [2], [3], [4]]}
|
378 | const inst = optModel(initialData, funcLibrary)
|
379 | expect(inst.result).toEqual([1, 2, 3, 4])
|
380 | inst.splice(0, 2, [6], [6], [6])
|
381 | expect(inst.data).toEqual([[6], [6], [6], [3], [4]], 'sanity')
|
382 | expect(inst.result).toEqual([6, 6, 6, 3, 4])
|
383 | inst.splice(0, 3, [67, 67])
|
384 | expect(inst.data).toEqual([[67, 67], [3], [4]], 'sanity')
|
385 | expect(inst.result).toEqual([67, 67, 3, 4])
|
386 | expect(inst.result2).toEqual([67, 67, 3, 4])
|
387 | inst.splice(0, 1, [68, 68])
|
388 | expect(inst.data).toEqual([[68, 68], [3], [4]], 'sanity')
|
389 | expect(inst.result).toEqual([68, 68, 3, 4])
|
390 | expect(inst.result2).toEqual([68, 68, 3, 4])
|
391 | })
|
392 | it('flatten root.array changes length', () => {
|
393 | const model = {
|
394 | clean: root,
|
395 | data: root.map(v => v),
|
396 | result: root.map(v => v).flatten(),
|
397 | result2: root.flatten(),
|
398 | splice: splice()
|
399 | }
|
400 | const optModel = evalOrLoad(compile(model, {compiler}))
|
401 | const initialData = [[1], [2], [3], [4]]
|
402 | const inst = optModel(initialData, funcLibrary)
|
403 | expect(inst.result).toEqual([1, 2, 3, 4])
|
404 | inst.splice(0, 2, [6], [6], [6])
|
405 | expect(inst.data).toEqual([[6], [6], [6], [3], [4]], 'sanity')
|
406 | expect(inst.result).toEqual([6, 6, 6, 3, 4])
|
407 | inst.splice(0, 3, [67, 67])
|
408 | expect(inst.data).toEqual([[67, 67], [3], [4]], 'sanity')
|
409 | expect(inst.result).toEqual([67, 67, 3, 4])
|
410 | expect(inst.result2).toEqual([67, 67, 3, 4])
|
411 | inst.splice(0, 1, [68, 68])
|
412 | expect(inst.data).toEqual([[68, 68], [3], [4]], 'sanity')
|
413 | expect(inst.result).toEqual([68, 68, 3, 4])
|
414 | expect(inst.result2).toEqual([68, 68, 3, 4])
|
415 | })
|
416 | it('flatten with two empty arrays', () => {
|
417 | const model = {
|
418 | clean: root.get('target'),
|
419 | data: root.get('target').map(v => v),
|
420 | result: root.get('target').map(v => v).flatten(),
|
421 | result2: root.get('target').flatten(),
|
422 | splice: splice('target')
|
423 | }
|
424 | const optModel = evalOrLoad(compile(model, {compiler}))
|
425 | const initialData = {target: [[], []]}
|
426 | const inst = optModel(initialData, funcLibrary)
|
427 | expect(inst.result).toEqual([])
|
428 | inst.splice(0, 0, [], [], [])
|
429 | expect(inst.result).toEqual([])
|
430 | inst.splice(2, 0, [1])
|
431 | expect(inst.result).toEqual([1])
|
432 | })
|
433 | it('flatten with adding empty array', () => {
|
434 | const model = {
|
435 | clean: root.get('target'),
|
436 | data: root.get('target').map(v => v),
|
437 | result: root.get('target').map(v => v).flatten(),
|
438 | result2: root.get('target').flatten(),
|
439 | splice: splice('target')
|
440 | }
|
441 | const optModel = evalOrLoad(compile(model, {compiler}))
|
442 | const initialData = {target: [[1], [2], [3], [4]]}
|
443 | const inst = optModel(initialData, funcLibrary)
|
444 | expect(inst.result).toEqual([1, 2, 3, 4])
|
445 | inst.splice(0, 2, [], [], [])
|
446 | expect(inst.result).toEqual([3, 4])
|
447 | inst.splice(0, 0, [], [6], [])
|
448 | expect(inst.result).toEqual([6, 3, 4])
|
449 | })
|
450 | it('flatten with empty array', () => {
|
451 | const model = {
|
452 | result: root.flatten(),
|
453 | set: setter(arg0)
|
454 | };
|
455 | const optModel = evalOrLoad(compile(model, {compiler}))
|
456 | const initialData = []
|
457 | const inst = optModel(initialData, funcLibrary)
|
458 | expect(inst.result).toEqual([])
|
459 | })
|
460 | it('sum', () => {
|
461 | const model = {
|
462 | result: root.sum(),
|
463 | set: setter(arg0)
|
464 | };
|
465 | const optModel = evalOrLoad(compile(model, {compiler}));
|
466 | const initialData = [1, 3, 5];
|
467 | const inst = optModel(initialData, funcLibrary);
|
468 | expect(inst.result).toEqual(9);
|
469 | inst.set(2, 1);
|
470 | inst.set(0, 5);
|
471 | expect(inst.result).toEqual(9);
|
472 | });
|
473 | it('sum with empty array', () => {
|
474 | const model = {
|
475 | result: root.sum(),
|
476 | set: setter(arg0)
|
477 | };
|
478 | const optModel = evalOrLoad(compile(model, {compiler}));
|
479 | const initialData = [];
|
480 | const inst = optModel(initialData, funcLibrary);
|
481 | expect(inst.result).toEqual(0);
|
482 | });
|
483 | it('sum with array that changes length', () => {
|
484 | const model = {
|
485 | result: root.sum(),
|
486 | splice: splice(),
|
487 | set: setter(arg0)
|
488 | };
|
489 | const optModel = evalOrLoad(compile(model, {compiler}));
|
490 | const initialData = [1, 2, 3, 4];
|
491 | const inst = optModel(initialData, funcLibrary);
|
492 | expect(inst.result).toEqual(10);
|
493 | inst.splice(0, 1)
|
494 | expect(inst.result).toEqual(9);
|
495 | inst.splice(0, 0, 6)
|
496 | expect(inst.result).toEqual(15)
|
497 | });
|
498 | it('concat', () => {
|
499 | const model = {
|
500 | result: root.get('a').concat(root.get('b')),
|
501 | set: setter('a', arg0)
|
502 | };
|
503 | const optModel = evalOrLoad(compile(model, {compiler}));
|
504 | const initialData = {a: [1, 3, 5], b: [2, 6]};
|
505 | const inst = optModel(initialData, funcLibrary);
|
506 | expect(inst.result).toEqual([1, 3, 5, 2, 6]);
|
507 | inst.set(2, 1);
|
508 | expect(inst.result).toEqual([1, 3, 1, 2, 6]);
|
509 | });
|
510 | it('concat with empty array', () => {
|
511 | const model = {
|
512 | result: root.get('a').concat(root.get('b')),
|
513 | set: setter('a', arg0)
|
514 | };
|
515 | const optModel = evalOrLoad(compile(model, {compiler}));
|
516 | const initialData = {a: [1, 3, 5], b: []};
|
517 | const inst = optModel(initialData, funcLibrary);
|
518 | expect(inst.result).toEqual([1, 3, 5]);
|
519 | inst.set(2, 1);
|
520 | expect(inst.result).toEqual([1, 3, 1]);
|
521 | });
|
522 |
|
523 | it('concat with empty array', () => {
|
524 | const model = {
|
525 | result: root.get('b').concat(root.get('a')),
|
526 | set: setter('a', arg0)
|
527 | };
|
528 | const optModel = evalOrLoad(compile(model, {compiler}));
|
529 | const initialData = {a: [1, 3, 5], b: []};
|
530 | const inst = optModel(initialData, funcLibrary);
|
531 | expect(inst.result).toEqual([1, 3, 5]);
|
532 | });
|
533 | it('append with primitive', () => {
|
534 | const initialData = ['a', 'b', 'c'];
|
535 | const model = {
|
536 | result: root.append('d')
|
537 | };
|
538 | const optModel = evalOrLoad(compile(model, {compiler}));
|
539 | const inst = optModel(initialData);
|
540 | expect(inst.result).toEqual(['a', 'b', 'c', 'd']);
|
541 | });
|
542 | it('append with array', () => {
|
543 | const initialData = ['a', 'b', 'c'];
|
544 | const model = {
|
545 | result: root.append(['d'])
|
546 | };
|
547 | const optModel = evalOrLoad(compile(model, {compiler}));
|
548 | const inst = optModel(initialData);
|
549 | expect(inst.result).toEqual(['a', 'b', 'c', ['d']]);
|
550 | });
|
551 | describe('includes', () => {
|
552 | it('should return true if includes value', () => {
|
553 | const initialData = {data: [1, 2, 3]};
|
554 | const value = 1
|
555 | const model = {
|
556 | includes: root.get('data').includes(value)
|
557 | };
|
558 | const optModel = evalOrLoad(compile(model, {compiler}));
|
559 |
|
560 | const inst = optModel(initialData);
|
561 | expect(inst.includes).toEqual(_.includes(initialData.data, value));
|
562 | });
|
563 | it('should return false if not includes value', () => {
|
564 | const initialData = {data: [1, 2, 3]};
|
565 | const value = 4
|
566 | const model = {
|
567 | includes: root.get('data').includes(value)
|
568 | };
|
569 | const optModel = evalOrLoad(compile(model, {compiler}));
|
570 |
|
571 | const inst = optModel(initialData);
|
572 | expect(inst.includes).toEqual(_.includes(initialData.data, value));
|
573 | });
|
574 | })
|
575 | describe('findIndex', () => {
|
576 | it('should return right index by predicate', () => {
|
577 | const initialData = {data: [{id: 1}, {id: 2}, {id: 3}]};
|
578 | const findId = 2;
|
579 | const model = {
|
580 | findIndex: root.get('data').findIndex(item => item.get('id').eq(findId))
|
581 | };
|
582 | const optModel = evalOrLoad(compile(model, {compiler}));
|
583 |
|
584 | const inst = optModel(initialData);
|
585 | expect(inst.findIndex).toEqual(1);
|
586 | });
|
587 | it('should support findding the first element', () => {
|
588 | const initialData = {data: [{id: 1}, {id: 2}, {id: 3}]};
|
589 | const findId = 1;
|
590 | const model = {
|
591 | findIndex: root.get('data').findIndex(item => item.get('id').eq(findId))
|
592 | };
|
593 | const optModel = evalOrLoad(compile(model, {compiler}));
|
594 |
|
595 | const inst = optModel(initialData);
|
596 | expect(inst.findIndex).toEqual(0);
|
597 | });
|
598 |
|
599 | it('should return -1 if not found', () => {
|
600 | const initialData = {data: [{id: 1}, {id: 2}, {id: 3}]};
|
601 | const findId = 4;
|
602 | const model = {
|
603 | findIndex: root.get('data').findIndex(item => item.get('id').eq(findId))
|
604 | };
|
605 | const optModel = evalOrLoad(compile(model, {compiler}));
|
606 |
|
607 | const inst = optModel(initialData);
|
608 | expect(inst.findIndex).toEqual(-1);
|
609 | });
|
610 | })
|
611 | it('branching - soft tracking', () => {
|
612 | const valuesInArrays = root.map(item => or(item.get('arr'), [item.get('val')]));
|
613 | const indexes = root.map((item, idx) => idx);
|
614 | const model = {
|
615 | result: indexes.map(idx => valuesInArrays.get(idx).get(0)),
|
616 | set: setter(arg0)
|
617 | };
|
618 | const optModel = evalOrLoad(compile(model, {compiler}));
|
619 | const initialData = [{arr: [1]}, {val: 2}, {arr: [3]}];
|
620 | const inst = optModel(initialData);
|
621 | expect(inst.result).toEqual([1, 2, 3]);
|
622 | inst.set(0, {val: 4});
|
623 | expect(inst.result).toEqual([4, 2, 3]);
|
624 | inst.set(1, {arr: [5]});
|
625 | expect(inst.result).toEqual([4, 5, 3]);
|
626 | });
|
627 | it('test binding', () => {
|
628 | const model = {
|
629 | doubleFunctions: root.map(item => bind('double', item)).map(item => item.call('tap')),
|
630 | multFunctions: root.map(item => bind('mult', item)).map(item => item.call('tap')),
|
631 | updateFunctions: root.map((item, key) => bind('updateSelf', key, item.mult(2))).map(item => item.call('tap')),
|
632 | set: setter(arg0)
|
633 | };
|
634 | const initialData = [3, 4];
|
635 | const optModel = evalOrLoad(compile(model, {compiler}));
|
636 | const extraFn = {
|
637 | double: x => x * 2,
|
638 | mult: (x, y) => x * y,
|
639 | updateSelf(index, val) {
|
640 | this.set(index, val);
|
641 | }
|
642 | };
|
643 | const inst = optModel(initialData, {...extraFn, ...funcLibrary});
|
644 | expect(inst.doubleFunctions[0]()).toEqual(6);
|
645 | expect(inst.doubleFunctions[1]()).toEqual(8);
|
646 | expect(inst.multFunctions[0](5)).toEqual(15);
|
647 | expect(inst.multFunctions[1](5)).toEqual(20);
|
648 | const old = inst.doubleFunctions[0];
|
649 | expectTapFunctionToHaveBeenCalled(6, compiler);
|
650 | inst.updateFunctions[0]();
|
651 | expectTapFunctionToHaveBeenCalled(0, compiler);
|
652 | expect(inst.doubleFunctions[0]()).toEqual(12);
|
653 | expect(inst.doubleFunctions[1]()).toEqual(8);
|
654 | });
|
655 | it('test reverse', () => {
|
656 | const model = {
|
657 | numbers: root.reverse()
|
658 | };
|
659 | const optModel = evalOrLoad(compile(model, {compiler}));
|
660 | const initialData = [1, 2, 3, 4, 5];
|
661 |
|
662 | const inst = optModel(initialData);
|
663 | expect(inst.numbers).toEqual(initialData.reverse());
|
664 | });
|
665 |
|
666 | describe('isEmpty', () => {
|
667 | it('should return true for empty array', () => {
|
668 | const initialData = {data: []}
|
669 | const model = {
|
670 | isEmpty: root.get('data').isEmpty()
|
671 | };
|
672 | const optModel = evalOrLoad(compile(model, {compiler}));
|
673 |
|
674 | const inst = optModel(initialData);
|
675 | expect(inst.isEmpty).toEqual(true);
|
676 | });
|
677 |
|
678 | it('should return false for non empty array', () => {
|
679 | const initialData = {data: [1]}
|
680 | const model = {
|
681 | isEmpty: root.get('data').isEmpty()
|
682 | };
|
683 | const optModel = evalOrLoad(compile(model, {compiler}));
|
684 |
|
685 | const inst = optModel(initialData);
|
686 | expect(inst.isEmpty).toEqual(false);
|
687 | });
|
688 | })
|
689 |
|
690 | describe('intersection', () => {
|
691 | it('should return an array of unique values that are included in given arrays', () => {
|
692 | const initialData = {a: ['a', 'b', 'c', 'd'], b: ['b', 'd']}
|
693 | const model = {
|
694 | result: root.get('a').intersection(root.get('b'))
|
695 | };
|
696 | const optModel = evalOrLoad(compile(model, {compiler}));
|
697 | const inst = optModel(initialData, funcLibrary);
|
698 | expect(inst.result).toEqual(['b', 'd']);
|
699 | })
|
700 | })
|
701 |
|
702 | describe('uniq', () => {
|
703 | it('should return a duplicate-free version of an array', () => {
|
704 | const initialData = {a: ['a', 'a', 'b', 'c', 'c', 'c']}
|
705 | const model = {
|
706 | result: root.get('a').uniq()
|
707 | };
|
708 | const optModel = evalOrLoad(compile(model, {compiler}));
|
709 | const inst = optModel(initialData, funcLibrary);
|
710 | expect(inst.result).toEqual(['a', 'b', 'c']);
|
711 | })
|
712 | })
|
713 |
|
714 | it('test head', () => {
|
715 | const model = {
|
716 | first: root.head()
|
717 | };
|
718 | const optModel = evalOrLoad(compile(model, {compiler}));
|
719 | const initialData = ['a', 2, 3, 4, 5];
|
720 |
|
721 | const inst = optModel(initialData);
|
722 | expect(inst.first).toEqual(initialData[0]);
|
723 | });
|
724 | it('test last', () => {
|
725 | const model = {
|
726 | last: root.last()
|
727 | };
|
728 | const optModel = evalOrLoad(compile(model, {compiler}));
|
729 | const initialData = [1, 2, 3, 4, 5];
|
730 |
|
731 | const inst = optModel(initialData);
|
732 | expect(inst.last).toEqual(initialData[initialData.length - 1]);
|
733 | });
|
734 | it('test compact', () => {
|
735 | const initialData = {data: [null, 1, '', false, 'test']};
|
736 | const model = {
|
737 | compact: root.get('data').compact()
|
738 | };
|
739 | const optModel = evalOrLoad(compile(model, {compiler}));
|
740 |
|
741 | const inst = optModel(initialData);
|
742 | expect(inst.compact).toEqual(_.compact(initialData.data));
|
743 | });
|
744 |
|
745 | describe('every', () => {
|
746 | it('should return true if predicate returns truthy for all elements in the array', () => {
|
747 | const initialData = {data: [1, 1, 1]};
|
748 | const model = {
|
749 | every: root.get('data').every(item => item.eq(1))
|
750 | };
|
751 | const optModel = evalOrLoad(compile(model, {compiler}));
|
752 |
|
753 | const inst = optModel(initialData);
|
754 | expect(inst.every).toBe(true);
|
755 | });
|
756 |
|
757 | it('should return false if predicate does not return truthy for all elements in the array', () => {
|
758 | const initialData = {data: [1, 2, 1]};
|
759 | const model = {
|
760 | every: root.get('data').every(item => item.eq(1))
|
761 | };
|
762 | const optModel = evalOrLoad(compile(model, {compiler}));
|
763 |
|
764 | const inst = optModel(initialData);
|
765 | expect(inst.every).toBe(false);
|
766 | });
|
767 | });
|
768 | describe('isArray tests', () => {
|
769 | it('should return true if is array', () => {
|
770 | const model = {
|
771 | isArray: root.isArray()
|
772 | };
|
773 | const optModel = evalOrLoad(compile(model, {compiler}));
|
774 | const initialData = [1, 2, 3];
|
775 |
|
776 | const inst = optModel(initialData);
|
777 | expect(inst.isArray).toEqual(true);
|
778 | });
|
779 | it('should return false if not array', () => {
|
780 | const model = {
|
781 | isArray: root.isArray()
|
782 | };
|
783 | const optModel = evalOrLoad(compile(model, {compiler}));
|
784 | const initialData = 5;
|
785 |
|
786 | const inst = optModel(initialData);
|
787 | expect(inst.isArray).toEqual(false);
|
788 | });
|
789 | });
|
790 | describe('test rewrite local functions', () => {
|
791 | it('should hoist the reused function', () => {
|
792 | const add10 = src => new Array(10).fill().reduce(v => v.plus(1), src)
|
793 | const model = {
|
794 | add30: root.map(val => add10(val).plus(add10(val)).plus(add10(val)))
|
795 | };
|
796 | const src = compile(model, {compiler, prettier: true})
|
797 | if (typeof src === 'string') {
|
798 | expect(src.split(' + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1').length - 1).toEqual(1)
|
799 | }
|
800 | const optModel = evalOrLoad(src);
|
801 | const initialData = [1, 2, 3];
|
802 |
|
803 | const inst = optModel(initialData);
|
804 | expect(inst.add30).toEqual([33, 36, 39]);
|
805 | })
|
806 | })
|
807 | });
|
808 | });
|