causalityjs
Version:
A library for reactive programming based on Javascript proxies.
388 lines (328 loc) • 11.9 kB
JavaScript
;
require = require("esm")(module);
const {create,resetObjectIds,observeAll,transaction} = require("../causality.js");
const assert = require('assert');
describe("Projections", function(){
var listNodePrototype = {
last : function() {
if (this.next == null) {
return this;
} else {
return this.next.last();
}
}
};
var createListNode = function(value, cacheId) {
const newNode = Object.create(listNodePrototype);
newNode.value = value;
newNode.next = null;
newNode.previous = null;
return create(newNode, cacheId);
// return create({ // This code somehow generates set events for last. This might have to do with Node.js internals...
// value : value,
// next: null,
// previous: null,
// last : function() {
// if (this.next == null) {
// return this;
// } else {
// return this.next.last();
// }
// }
// });
};
var createTransparentListNode = function(value, cacheId) {
return create({value : value}, cacheId);
};
var createListHead = function(cacheId) {
return create({
first: null,
last: null
}, cacheId);
};
var createTreeNode = function(value, children) {
return create({
flattenArrayPreOrder : function() {
let result = create([], this.__id + "_array");
result.push(create({value: value}, this.__id + "_node"));
this.children.forEach(function(child) {
let childList = child.flattenArrayPreOrder();
result.push.apply(result, childList);
});
return result;
},
flattenArrayPreOrderRecursive : function() {
// console.log("flattenArrayPreOrderRecursive " + this.__id + "_array");
let result = create([], this.__id + "_array");
result.push(create({value: value}, this.__id + "_node"));
this.children.forEach(function(child) {
let childList = child.reCached('flattenArrayPreOrderRecursive');
result.push.apply(result, childList);
});
return result;
},
flattenLinkedPreOrder : function() {
let firstNode = createListNode(this.value, this.__id + "_list");
let node = firstNode;
this.children.forEach(function(child) {
// child.reCachedInCache('flattenLinkedPreOrder');
let childList = child.flattenLinkedPreOrder();
node.next = childList;
childList.previous = node;
node = childList.last();
});
return firstNode;
},
flattenLinkedPreOrderRecursive : function() {
// console.log("flattenLinkedPreOrderRecursive " + this.__id + "_head");
let listHead = createListHead(this.__id + "_head");
let firstNode = createTransparentListNode(this.value, this.__id + "_node");
listHead.first = firstNode;
// firstNode.previous = null;
let node = firstNode;
this.children.forEach(function(child) {
// child.reCachedInCache('flattenLinkedPreOrder');
let childList = child.reCached('flattenLinkedPreOrderRecursive');
// console.log("linking next and previous together" + node.__id + " -> " + childList.first.__id);
node.next = childList.first;
childList.first.previous = node;
node = childList.last;
});
// node.next = null; // To be sure
listHead.last = node;
return listHead;
},
value : value,
children : create(children)
});
};
it("Testing just flattening", function(){
var tree = createTreeNode(1, [
createTreeNode(2, [
createTreeNode(3, []),
createTreeNode(4, [])
]),
createTreeNode(5, [
createTreeNode(6, []),
createTreeNode(7, [])
])
]);
var flattened = tree.flattenLinkedPreOrder();
// console.log(flattened);
var number = 1;
assert.equal(flattened.value, number++);
while(flattened.next !== null) {
flattened = flattened.next;
assert.equal(flattened.value, number++);
}
});
it("Testing non-recursive projection, linked list version", function(){
resetObjectIds();
var tree = createTreeNode(1, [
createTreeNode(2, [
createTreeNode(3, []),
createTreeNode(4, [])
]),
createTreeNode(5, [
createTreeNode(6, []),
createTreeNode(7, [])
])
]);
var flattened = tree.reCached('flattenLinkedPreOrder');
// Assert original shape
var expectedValues = [1, 2, 3, 4, 5, 6, 7];
var flattenedNode = flattened;
assert.equal(flattenedNode.value, expectedValues.shift());
while(flattenedNode.next !== null) {
flattenedNode = flattenedNode.next;
assert.equal(flattenedNode.value, expectedValues.shift());
}
// Observe all
let detectedEvents = [];
flattenedNode = flattened;
let observedNodes = [];
observedNodes.push(flattenedNode);
while(flattenedNode.next !== null) {
flattenedNode = flattenedNode.next;
observedNodes.push(flattenedNode);
}
observeAll(observedNodes, function(event) {
detectedEvents.push(event);
});
// Update tree
// console.log("Update tree");
tree.children[0].children.push(createTreeNode(4.5, []));
// Assert eventws
assert.equal(detectedEvents[0].type, 'set');
assert.equal(detectedEvents[0].property, 'next');
assert.equal(detectedEvents[0].newValue.value, 4.5);
assert.equal(detectedEvents[0].newValue.__cacheId, '23_list');
assert.equal(detectedEvents[0].oldValue.value, 5);
assert.equal(detectedEvents[0].oldValue.__cacheId, '12_list');
assert.equal(detectedEvents[0].objectId, 18);
assert.equal(detectedEvents[1].type, 'set');
assert.equal(detectedEvents[1].property, 'previous');
assert.equal(detectedEvents[1].newValue.value, 4.5);
assert.equal(detectedEvents[1].newValue.__cacheId, '23_list');
assert.equal(detectedEvents[1].oldValue.value, 4);
assert.equal(detectedEvents[1].oldValue.__cacheId, '4_list');
assert.equal(detectedEvents[1].objectId, 19);
// Assert updated
expectedValues = [1, 2, 3, 4, 4.5, 5, 6, 7];
flattenedNode = flattened;
assert.equal(flattenedNode.value, expectedValues.shift());
while(flattenedNode.next !== null) {
flattenedNode = flattenedNode.next;
assert.equal(flattenedNode.value, expectedValues.shift());
}
});
it("Testing non-recursive projection, array version", function(){
resetObjectIds();
var tree = createTreeNode(1, [
createTreeNode(2, [
createTreeNode(3, []),
createTreeNode(4, [])
]),
createTreeNode(5, [
createTreeNode(6, []),
createTreeNode(7, [])
])
]);
var flattened = tree.reCached('flattenArrayPreOrder');
// Assert original shape
assert.deepEqual(flattened.map((object) => { return object.value; }), [1, 2, 3, 4, 5, 6, 7]);
// Observe array
let detectedEvents = [];
flattened.observe(function(event) {
detectedEvents.push(event);
});
// Update tree
// console.log("=======================================================");
tree.children[0].children.push(createTreeNode(4.5, []));
// console.log("=======================================================");
// Assert eventws
const expected1 = [
{ type: 'splice',
index: 4,
removed: [],
added: [ { value: 4.5 } ],
objectId: 15 } ];
expected1[0].object = flattened;
assert.deepEqual(detectedEvents, expected1 );
// Assert updated
assert.deepEqual(flattened.map((object) => { return object.value; }), [1, 2, 3, 4, 4.5, 5, 6, 7]);
});
it("Testing recursive projection, array version", function( done ){
resetObjectIds();
var tree = createTreeNode(1, [
createTreeNode(2, [
createTreeNode(3, []),
createTreeNode(4, [])
]),
createTreeNode(5, [
createTreeNode(6, []),
createTreeNode(7, [])
])
]);
var flattened = tree.reCached('flattenArrayPreOrderRecursive');
// Assert original shape
assert.deepEqual(flattened.map((object) => { return object.value; }), [1, 2, 3, 4, 5, 6, 7]);
// Observe array
let detectedEvents = [];
flattened.observe(function(event) {
detectedEvents.push(event);
// Assert eventws
const expected1 = [
{ type: 'splice',
index: 4,
removed: [],
added: [ { value: 4.5 } ],
objectId: 15 } ];
expected1[0].object = flattened;
assert.deepEqual(detectedEvents, expected1 );
// Assert updated
assert.deepEqual(flattened.map((object) => { return object.value; }), [1, 2, 3, 4, 4.5, 5, 6, 7]);
done();
});
// Update tree
tree.children[0].children.push(createTreeNode(4.5, []));
});
it("Testing recursive projection, linked list version", function( done ){
resetObjectIds();
var tree = createTreeNode(1, [
createTreeNode(2, [
createTreeNode(3, []),
createTreeNode(4, [])
]),
createTreeNode(5, [
createTreeNode(6, []),
createTreeNode(7, [])
])
]);
var flattened = tree.reCached('flattenLinkedPreOrderRecursive');
// Assert original shape
var expectedValues = [1, 2, 3, 4, 5, 6, 7];
var flattenedNode = flattened.first;
assert.equal(flattenedNode.value, expectedValues.shift());
while(typeof(flattenedNode.next) !== 'undefined') {
flattenedNode = flattenedNode.next;
assert.equal(flattenedNode.value, expectedValues.shift());
}
// Observe all
let detectedEvents = [];
flattenedNode = flattened.first;
let observedNodes = [];
observedNodes.push(flattenedNode);
while(typeof(flattenedNode.next) !== 'undefined') {
flattenedNode = flattenedNode.next;
observedNodes.push(flattenedNode);
}
observeAll(observedNodes, function(event) {
detectedEvents.push(event);
if( !detectedEvents[1] ) return;
// Assert eventws
assert.equal(detectedEvents[0].type, 'set');
assert.equal(detectedEvents[0].property, 'next');
assert.equal(detectedEvents[0].newValue.value, 4.5);
assert.equal(detectedEvents[0].newValue.__cacheId, '30_node');
assert.equal(detectedEvents[0].oldValue.value, 5);
assert.equal(detectedEvents[0].oldValue.__cacheId, '12_node');
assert.equal(detectedEvents[0].objectId, 22);
assert.equal(detectedEvents[1].type, 'set');
assert.equal(detectedEvents[1].property, 'previous');
assert.equal(detectedEvents[1].newValue.value, 4.5);
assert.equal(detectedEvents[1].newValue.__cacheId, '30_node');
assert.equal(detectedEvents[1].oldValue.value, 4);
assert.equal(detectedEvents[1].oldValue.__cacheId, '4_node');
assert.equal(detectedEvents[1].objectId, 24);
// Assert updated
expectedValues = [1, 2, 3, 4, 4.5, 5, 6, 7];
flattenedNode = flattened.first;
assert.equal(flattenedNode.value, expectedValues.shift());
while(typeof(flattenedNode.next) !== 'undefined') {
flattenedNode = flattenedNode.next;
assert.equal(flattenedNode.value, expectedValues.shift());
}
done();
});
// Update tree
transaction(function() {
tree.children[0].children.push(createTreeNode(4.5, []));
});
});
});
// let cnt = 0;
// const state = create({});
// let out = {};
//
// repeatOnChange(function(){
// // console.log("=== Reevaluate ===");
// cnt++;
// for( let key in state ){
// if( state[key].hobby ){
// out[key] = state[key].hobby.length;
// }
// }
// // console.log("=== finished ===");
// });
//