1 | const {compile, and, or, root, arg0, setter} = require('../../index');
|
2 | const {currentValues, funcLibrary, expectTapFunctionToHaveBeenCalled, rand, evalOrLoad} = require('../test-utils');
|
3 |
|
4 | const _ = require('lodash');
|
5 |
|
6 | describe('simple todo', () => {
|
7 | function TodosModel() {
|
8 | const todos = root.get('todos');
|
9 | const pendingTodos = todos.filterBy(val => val.get('done').not());
|
10 | const blockedBy = todos.mapValues(val => val.get('blockedBy'));
|
11 | const todosDone = todos.mapValues(val => val.get('done'));
|
12 | const isNotDone = val =>
|
13 | and(
|
14 | val,
|
15 | todos
|
16 | .get(val)
|
17 | .get('done')
|
18 | .not()
|
19 | );
|
20 | const isNotDone2 = val => and(val, todosDone.get(val).not());
|
21 | const isNotDone3 = val => pendingTodos.get(val);
|
22 | const isBlocked = blockedBy.mapValues(isNotDone);
|
23 | const isBlocked2 = blockedBy.mapValues(isNotDone2);
|
24 | const isBlocked3 = blockedBy.mapValues(isNotDone3);
|
25 | const canItemBeWorkedOn = val =>
|
26 | and(val.get('done').not(), or(val.get('blockedBy').not(), todosDone.get(val.get('blockedBy'))));
|
27 | const canBeWorkedOn = todos.mapValues(canItemBeWorkedOn);
|
28 |
|
29 | const shownTodo = or(and(root.get('showCompleted'), canBeWorkedOn), pendingTodos);
|
30 |
|
31 | const currentTask = root.get('currentTask');
|
32 | const currentTaskTodo = todos.get(currentTask);
|
33 | const statusOfCurrentTask = or(
|
34 | and(currentTaskTodo.get('done'), 'done'),
|
35 | and(isBlocked.get(currentTask), 'blocked'),
|
36 | 'not done'
|
37 | );
|
38 |
|
39 | const blockedGrouped = pendingTodos.mapValues((val, key) =>
|
40 | todos.filterBy((val, key, context) => val.get('blockedBy').eq(context), key)
|
41 | );
|
42 |
|
43 | return {
|
44 | isBlocked,
|
45 | isBlocked2,
|
46 | isBlocked3,
|
47 | blockedBy,
|
48 | canBeWorkedOn,
|
49 | shownTodo,
|
50 | pendingTodos,
|
51 | blockedGrouped,
|
52 | setTodo: setter('todos', arg0),
|
53 | setShowCompleted: setter('showCompleted'),
|
54 | setCurrentTask: setter('currentTask')
|
55 | };
|
56 | }
|
57 | const countItems = 20;
|
58 |
|
59 | function randomTodoItem(idx) {
|
60 | return {
|
61 | text: `todo_${idx}`,
|
62 | done: rand.range(2) === 0,
|
63 | blockedBy: rand.range(4) === 2 ? `${(idx + rand.range(countItems - 1)) % countItems}` : false
|
64 | };
|
65 | }
|
66 |
|
67 | function generateTestTodoItems(count) {
|
68 | const res = {};
|
69 | for (let idx = 0; idx < count; idx++) {
|
70 | res[`${idx}`] = randomTodoItem(idx);
|
71 | }
|
72 | return res;
|
73 | }
|
74 |
|
75 | it('compare naive and optimized', () => {
|
76 | const naiveFunc = evalOrLoad(compile(TodosModel(), true));
|
77 | const optFunc = evalOrLoad(compile(TodosModel()));
|
78 | const initialState = {
|
79 | todos: generateTestTodoItems(countItems),
|
80 | currentTask: '1',
|
81 | showCompleted: false
|
82 | };
|
83 | const naive = naiveFunc(initialState);
|
84 | const opt = optFunc(initialState);
|
85 | expect(currentValues(naive)).toEqual(currentValues(opt));
|
86 | const actionTypes = [
|
87 | () => {
|
88 | const idx = rand.range(countItems);
|
89 | const todoItem = randomTodoItem(idx);
|
90 | return inst => {
|
91 | inst.setTodo(`${idx}`, todoItem);
|
92 | };
|
93 | },
|
94 | () => {
|
95 | const current = rand.range(countItems);
|
96 | return inst => {
|
97 | inst.setCurrentTask(current);
|
98 | };
|
99 | },
|
100 | () => {
|
101 | const show = rand.range(2) === 1;
|
102 | return inst => {
|
103 | inst.setShowCompleted(show);
|
104 | };
|
105 | }
|
106 | ];
|
107 | new Array(countItems * 10).fill().forEach((__, idx) => {
|
108 | const action = actionTypes[rand.range(actionTypes.length)]();
|
109 | action(naive);
|
110 | action(opt);
|
111 | expect(currentValues(naive)).toEqual(currentValues(opt));
|
112 | });
|
113 | });
|
114 | });
|