UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

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