chai = require('chai') expect = chai.expect should = chai.should() sinon = require('sinon') sinonChai = require('sinon-chai') _ = require("underscore") chai.use(sinonChai) Connector = require "../../y-test/lib/y-test.coffee" Y = require "../lib/y.coffee" Test = require "./TestSuite" class JsonTest extends Test makeNewUser: (userId)-> conn = new Connector userId super new Y conn type: "JsonTest" getRandomRoot: (user_num, root)-> root ?= @users[user_num] types = @users[user_num].types if _.random(0,1) is 1 # take root root else # take child elems = null if root.type is "Object" elems = for oname,val of root.val() val else if root.type is "Array" elems = root.val() else return root elems = elems.filter (elem)-> (elem.type is "Array") or (elem.type is "Object") if elems.length is 0 root else p = elems[_.random(0, elems.length-1)] @getRandomRoot user_num, p getContent: (user_num)-> @users[user_num].toJson(true) getGeneratingFunctions: (user_num)-> types = @users[user_num].types super(user_num).concat [ f : (y)=> # SET PROPERTY l = y.val().length y.val(_.random(0, l-1), @getRandomText(), 'immutable') null types : [types.Array] , f : (y)=> # Delete Array Element list = y.val() if list.length > 0 key = list[_random(0,list.length-1)] y.delete(key) types: [types.Array] , f : (y)=> # insert TEXT mutable l = y.val().length y.val(_.random(0, l-1), @getRamdomObject()) types: [types.Array] , f : (y)=> # insert string l = y.val().length y.val(_.random(0, l-1), @getRandomText(), 'immutable') null types : [types.Array] , f : (y)=> # Delete Object Property list = for name, o of y.val() name if list.length > 0 key = list[_random(0,list.length-1)] y.delete(key) types: [types.Object] , f : (y)=> # SET Object Property y.val(@getRandomKey(), @getRandomObject()) types: [types.Object] , f : (y)=> # SET PROPERTY TEXT y.val(@getRandomKey(), @getRandomText(), 'mutable') types: [types.Object] ] describe "JsonFramework", -> beforeEach (done)-> @timeout 50000 @yTest = new JsonTest() @users = @yTest.users @test_user = @yTest.makeNewUser "test_user" done() it "can handle many engines, many operations, concurrently (random)", -> console.log "" # TODO @yTest.run() it "has a working test suite", -> @yTest.compareAll() it "handles double-late-join", -> test = new JsonTest("double") test.run() @yTest.run() u1 = test.users[0] u2 = @yTest.users[1] ops1 = u1.HB._encode() ops2 = u2.HB._encode() u1.HB.renewStateVector u2.HB.getOperationCounter() u2.HB.renewStateVector u1.HB.getOperationCounter() u1.engine.applyOps ops2 u2.engine.applyOps ops1 expect(test.getContent(0)).to.deep.equal(@yTest.getContent(1)) it "can handle creaton of complex json (1)", -> @yTest.users[0].val('a', 'q', "mutable") @yTest.users[1].val('a', 't', "mutable") @yTest.compareAll() q = @yTest.users[2].val('a') q.insert(0,'A') @yTest.compareAll() expect(@yTest.getSomeUser().val("a").val()).to.equal("At") it "can handle creaton of complex json (2)", -> @yTest.getSomeUser().val('x', {'a':'b'}) @yTest.getSomeUser().val('a', {'a':{q:"dtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt"}}, "mutable") @yTest.getSomeUser().val('b', {'a':{}}) @yTest.getSomeUser().val('c', {'a':'c'}) @yTest.getSomeUser().val('c', {'a':'b'}) @yTest.compareAll() q = @yTest.getSomeUser().val("a").val("a").val("q") q.insert(0,'A') @yTest.compareAll() expect(@yTest.getSomeUser().val("a").val("a").val("q").val()).to.equal("Adtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt") it "can handle creaton of complex json (3)", -> @yTest.users[0].val('l', [1,2,3], "mutable") @yTest.users[1].val('l', [4,5,6], "mutable") @yTest.compareAll() @yTest.users[2].val('l').insert(0,'A') w = @yTest.users[1].val('l').insert(0,'B', "mutable").val(0) w.insert 1, "C" expect(w.val()).to.equal("BC") @yTest.compareAll() it "handles immutables and primitive data types", -> @yTest.getSomeUser().val('string', "text", "immutable") @yTest.getSomeUser().val('number', 4, "immutable") @yTest.getSomeUser().val('object', {q:"rr"}, "immutable") @yTest.getSomeUser().val('null', null) @yTest.compareAll() expect(@yTest.getSomeUser().val('string')).to.equal "text" expect(@yTest.getSomeUser().val('number')).to.equal 4 expect(@yTest.getSomeUser().val('object').val('q')).to.equal "rr" expect(@yTest.getSomeUser().val('null') is null).to.be.ok it "handles immutables and primitive data types (2)", -> @yTest.users[0].val('string', "text", "immutable") @yTest.users[1].val('number', 4, "immutable") @yTest.users[2].val('object', {q:"rr"}, "immutable") @yTest.users[0].val('null', null) @yTest.compareAll() expect(@yTest.getSomeUser().val('string')).to.equal "text" expect(@yTest.getSomeUser().val('number')).to.equal 4 expect(@yTest.getSomeUser().val('object').val('q')).to.equal "rr" expect(@yTest.getSomeUser().val('null') is null).to.be.ok it "Observers work on JSON Types (add type observers, local and foreign)", -> u = @yTest.users[0] @yTest.flushAll() last_task = null observer1 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("add") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('0') expect(change.name).to.equal("newStuff") last_task = "observer1" u.observe observer1 u.val("newStuff","someStuff","mutable") expect(last_task).to.equal("observer1") u.unobserve observer1 observer2 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("add") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('1') expect(change.name).to.equal("moreStuff") last_task = "observer2" u.observe observer2 v = @yTest.users[1] v.val("moreStuff","someMoreStuff") @yTest.flushAll() expect(last_task).to.equal("observer2") u.unobserve observer2 it "Observers work on JSON Types (update type observers, local and foreign)", -> u = @yTest.users[0].val("newStuff","oldStuff","mutable").val("moreStuff","moreOldStuff","mutable") @yTest.flushAll() last_task = null observer1 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("update") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('0') expect(change.name).to.equal("newStuff") expect(change.oldValue.val()).to.equal("oldStuff") last_task = "observer1" u.observe observer1 u.val("newStuff","someStuff") expect(last_task).to.equal("observer1") u.unobserve observer1 observer2 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("update") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('1') expect(change.name).to.equal("moreStuff") expect(change.oldValue.val()).to.equal("moreOldStuff") last_task = "observer2" u.observe observer2 v = @yTest.users[1] v.val("moreStuff","someMoreStuff") @yTest.flushAll() expect(last_task).to.equal("observer2") u.unobserve observer2 it "Observers work on JSON Types (delete type observers, local and foreign)", -> u = @yTest.users[0].val("newStuff","oldStuff","mutable").val("moreStuff","moreOldStuff","mutable") @yTest.flushAll() last_task = null observer1 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("delete") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('0') expect(change.name).to.equal("newStuff") expect(change.oldValue.val()).to.equal("oldStuff") last_task = "observer1" u.observe observer1 u.delete("newStuff") expect(last_task).to.equal("observer1") u.unobserve observer1 observer2 = (changes)-> expect(changes.length).to.equal(1) change = changes[0] expect(change.type).to.equal("delete") expect(change.object).to.equal(u) expect(change.changedBy).to.equal('1') expect(change.name).to.equal("moreStuff") expect(change.oldValue.val()).to.equal("moreOldStuff") last_task = "observer2" u.observe observer2 v = @yTest.users[1] v.delete("moreStuff") @yTest.flushAll() expect(last_task).to.equal("observer2") u.unobserve observer2