UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

214 lines (210 loc) 9.67 kB
var chai, graph, journal; if (typeof process !== 'undefined' && process.execPath && process.execPath.match(/node|iojs/)) { if (!chai) { chai = require('chai'); } graph = require('../src/lib/Graph.coffee'); journal = require('../src/lib/Journal.coffee'); } else { graph = require('noflo/src/lib/Graph.js'); journal = require('noflo/src/lib/Journal.js'); } describe('Journal', function() { describe('connected to initialized graph', function() { var g, j; g = new graph.Graph; g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); j = new journal.Journal(g); return it('should have just the initial transaction', function() { return chai.expect(j.store.lastRevision).to.equal(0); }); }); describe('following basic graph changes', function() { var g, j; g = new graph.Graph; j = new journal.Journal(g); return it('should create one transaction per change', function() { g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); chai.expect(j.store.lastRevision).to.equal(3); g.removeNode('Baz'); return chai.expect(j.store.lastRevision).to.equal(4); }); }); describe('pretty printing', function() { var g, j; g = new graph.Graph; j = new journal.Journal(g); g.startTransaction('test1'); g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); g.addInitial(42, 'Foo', 'in'); g.removeNode('Foo'); g.endTransaction('test1'); g.startTransaction('test2'); g.removeNode('Baz'); g.endTransaction('test2'); return it('should be human readable', function() { var ref; ref = ">>> 0: initial\n<<< 0: initial\n>>> 1: test1\nFoo(Bar)\nBaz(Foo)\nFoo out -> in Baz\n'42' -> in Foo\nMETA Foo out -> in Baz\nFoo out -X> in Baz\n'42' -X> in Foo\nMETA Foo\nDEL Foo(Bar)\n<<< 1: test1"; return chai.expect(j.toPrettyString(0, 2)).to.equal(ref); }); }); describe('jumping to revision', function() { var g, j; g = new graph.Graph; j = new journal.Journal(g); g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); g.addInitial(42, 'Foo', 'in'); g.removeNode('Foo'); return it('should change the graph', function() { j.moveToRevision(0); chai.expect(g.nodes.length).to.equal(0); j.moveToRevision(2); chai.expect(g.nodes.length).to.equal(2); j.moveToRevision(5); return chai.expect(g.nodes.length).to.equal(1); }); }); describe('linear undo/redo', function() { var g, graphBeforeError, j; g = new graph.Graph; j = new journal.Journal(g); g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); g.addInitial(42, 'Foo', 'in'); graphBeforeError = g.toJSON(); chai.expect(g.nodes.length).to.equal(2); it('undo should restore previous revision', function() { g.removeNode('Foo'); chai.expect(g.nodes.length).to.equal(1); j.undo(); chai.expect(g.nodes.length).to.equal(2); return chai.expect(g.toJSON()).to.deep.equal(graphBeforeError); }); it('redo should apply the same change again', function() { j.redo(); return chai.expect(g.nodes.length).to.equal(1); }); return it('undo should also work multiple revisions back', function() { g.removeNode('Baz'); j.undo(); j.undo(); chai.expect(g.nodes.length).to.equal(2); return chai.expect(g.toJSON()).to.deep.equal(graphBeforeError); }); }); return describe('undo/redo of metadata changes', function() { var g, j; g = new graph.Graph; j = new journal.Journal(g); g.addNode('Foo', 'Bar'); g.addNode('Baz', 'Foo'); g.addEdge('Foo', 'out', 'Baz', 'in'); it('adding group', function() { g.addGroup('all', ['Foo', 'Bax'], { 'label': 'all nodes' }); chai.expect(g.groups.length).to.equal(1); return chai.expect(g.groups[0].name).to.equal('all'); }); it('undoing group add', function() { j.undo(); return chai.expect(g.groups.length).to.equal(0); }); it('redoing group add', function() { j.redo(); return chai.expect(g.groups[0].metadata['label']).to.equal('all nodes'); }); it('changing group metadata adds revision', function() { var r; r = j.store.lastRevision; g.setGroupMetadata('all', { 'label': 'ALL NODES!' }); return chai.expect(j.store.lastRevision).to.equal(r + 1); }); it('undoing group metadata change', function() { j.undo(); return chai.expect(g.groups[0].metadata['label']).to.equal("all nodes"); }); it('redoing group metadata change', function() { j.redo(); return chai.expect(g.groups[0].metadata['label']).to.equal("ALL NODES!"); }); it('setting node metadata', function() { g.setNodeMetadata('Foo', { "oneone": 11, 2: "two" }); return chai.expect(Object.keys(g.getNode('Foo').metadata).length).to.equal(2); }); it('undoing set node metadata', function() { j.undo(); return chai.expect(Object.keys(g.getNode('Foo').metadata).length).to.equal(0); }); return it('redoing set node metadata', function() { j.redo(); return chai.expect(g.getNode('Foo').metadata["oneone"]).to.equal(11); }); }); }); describe('Journalling of graph merges', function() { var A, B, a, b, g, j; A = "{\n\"properties\": { \"name\": \"Example\", \"foo\": \"Baz\", \"bar\": \"Foo\" },\n\"inports\": {\n \"in\": { \"process\": \"Foo\", \"port\": \"in\", \"metadata\": { \"x\": 5, \"y\": 100 } }\n},\n\"outports\": {\n \"out\": { \"process\": \"Bar\", \"port\": \"out\", \"metadata\": { \"x\": 500, \"y\": 505 } }\n},\n\"groups\": [\n { \"name\": \"first\", \"nodes\": [ \"Foo\" ], \"metadata\": { \"label\": \"Main\" } },\n { \"name\": \"second\", \"nodes\": [ \"Foo2\", \"Bar2\" ], \"metadata\": {} }\n],\n\"processes\": {\n \"Foo\": { \"component\": \"Bar\", \"metadata\": { \"display\": { \"x\": 100, \"y\": 200 }, \"hello\": \"World\" } },\n \"Bar\": { \"component\": \"Baz\", \"metadata\": {} },\n \"Foo2\": { \"component\": \"foo\", \"metadata\": {} },\n \"Bar2\": { \"component\": \"bar\", \"metadata\": {} }\n},\n\"connections\": [\n { \"src\": { \"process\": \"Foo\", \"port\": \"out\" }, \"tgt\": { \"process\": \"Bar\", \"port\": \"in\" }, \"metadata\": { \"route\": \"foo\", \"hello\": \"World\" } },\n { \"src\": { \"process\": \"Foo\", \"port\": \"out2\" }, \"tgt\": { \"process\": \"Bar\", \"port\": \"in2\" } },\n { \"data\": \"Hello, world!\", \"tgt\": { \"process\": \"Foo\", \"port\": \"in\" } },\n { \"data\": \"Hello, world, 2!\", \"tgt\": { \"process\": \"Foo\", \"port\": \"in2\" } },\n { \"data\": \"Cheers, world!\", \"tgt\": { \"process\": \"Foo\", \"port\": \"arr\" } }\n]\n}"; B = "{\n\"properties\": { \"name\": \"Example\", \"foo\": \"Baz\", \"bar\": \"Foo\" },\n\"inports\": {\n \"in\": { \"process\": \"Foo\", \"port\": \"in\", \"metadata\": { \"x\": 500, \"y\": 1 } }\n},\n\"outports\": {\n \"out\": { \"process\": \"Bar\", \"port\": \"out\", \"metadata\": { \"x\": 500, \"y\": 505 } }\n},\n\"groups\": [\n { \"name\": \"second\", \"nodes\": [ \"Foo\", \"Bar\" ] }\n],\n\"processes\": {\n \"Foo\": { \"component\": \"Bar\", \"metadata\": { \"display\": { \"x\": 100, \"y\": 200 }, \"hello\": \"World\" } },\n \"Bar\": { \"component\": \"Baz\", \"metadata\": {} },\n \"Bar2\": { \"component\": \"bar\", \"metadata\": {} },\n \"Bar3\": { \"component\": \"bar2\", \"metadata\": {} }\n},\n\"connections\": [\n { \"src\": { \"process\": \"Foo\", \"port\": \"out\" }, \"tgt\": { \"process\": \"Bar\", \"port\": \"in\" }, \"metadata\": { \"route\": \"foo\", \"hello\": \"World\" } },\n { \"src\": { \"process\": \"Foo2\", \"port\": \"out2\" }, \"tgt\": { \"process\": \"Bar3\", \"port\": \"in2\" } },\n { \"data\": \"Hello, world!\", \"tgt\": { \"process\": \"Foo\", \"port\": \"in\" } },\n { \"data\": \"Hello, world, 2!\", \"tgt\": { \"process\": \"Bar3\", \"port\": \"in2\" } },\n { \"data\": \"Cheers, world!\", \"tgt\": { \"process\": \"Bar2\", \"port\": \"arr\" } }\n]\n}"; a = null; b = null; g = null; j = null; return describe('G -> B', function() { it('G starts out as A', function(done) { return graph.loadJSON(JSON.parse(A), function(err, instance) { if (err) { return done(err); } a = instance; return graph.loadJSON(JSON.parse(A), function(err, instance) { if (err) { return done(err); } g = instance; chai.expect(graph.equivalent(a, g)).to.equal(true); return done(); }); }); }); it('G and B starts out different', function(done) { return graph.loadJSON(JSON.parse(B), function(err, instance) { if (err) { return done(err); } b = instance; chai.expect(graph.equivalent(g, b)).to.equal(false); return done(); }); }); it('merge should make G equivalent to B', function(done) { j = new journal.Journal(g); g.startTransaction('merge'); graph.mergeResolveTheirs(g, b); g.endTransaction('merge'); chai.expect(graph.equivalent(g, b)).to.equal(true); return done(); }); return it('undoing merge should make G equivalent to A again', function(done) { var res; j.undo(); res = graph.equivalent(g, a); chai.expect(res).to.equal(true); return done(); }); }); });