list and map types work now and they support delete. added random tests
This commit is contained in:
		
							parent
							
								
									a1026bc365
								
							
						
					
					
						commit
						0493d99d57
					
				@ -50,6 +50,33 @@ var Struct = {
 | 
				
			|||||||
      return op;
 | 
					      return op;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  Delete: {
 | 
				
			||||||
 | 
					    create: function* (op) {
 | 
				
			||||||
 | 
					      if (op.target == null) {
 | 
				
			||||||
 | 
					        throw new Error("You must define a delete target!");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      op.struct = "Delete";
 | 
				
			||||||
 | 
					      yield* Struct.Operation.create.call(this, op);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var target = yield* this.getOperation(op.target);
 | 
				
			||||||
 | 
					      target.deleted = true;
 | 
				
			||||||
 | 
					      yield* this.setOperation(target);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    encode: function (op) {
 | 
				
			||||||
 | 
					      return op;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    requiredOps: function (op) {
 | 
				
			||||||
 | 
					      return [op.target];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    execute: function* (op) {
 | 
				
			||||||
 | 
					      if ((yield* this.addOperation(op)) === false) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      var target = yield* this.getOperation(op.target);
 | 
				
			||||||
 | 
					      target.deleted = true;
 | 
				
			||||||
 | 
					      yield* this.setOperation(target);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  Insert: {
 | 
					  Insert: {
 | 
				
			||||||
    /*{
 | 
					    /*{
 | 
				
			||||||
        content: any,
 | 
					        content: any,
 | 
				
			||||||
@ -294,27 +321,57 @@ var Struct = {
 | 
				
			|||||||
      if (op.start == null) {
 | 
					      if (op.start == null) {
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      var res = null;
 | 
				
			||||||
      var o = yield* this.getOperation(op.start);
 | 
					      var o = yield* this.getOperation(op.start);
 | 
				
			||||||
      while ( pos !== 0 && o.right != null) {
 | 
					
 | 
				
			||||||
        o = (yield* this.getOperation(o.right));
 | 
					      while ( true ) {
 | 
				
			||||||
 | 
					        if (!o.deleted) {
 | 
				
			||||||
 | 
					          res = o;
 | 
				
			||||||
          pos--;
 | 
					          pos--;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      return o;
 | 
					        if (pos >= 0 && o.right != null) {
 | 
				
			||||||
 | 
					          o = (yield* this.getOperation(o.right));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return res;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    delete: function* (op, pos) {
 | 
				
			||||||
 | 
					      var ref = yield* Struct.List.ref.call(this, op, pos);
 | 
				
			||||||
 | 
					      if (ref != null) {
 | 
				
			||||||
 | 
					        yield* Struct.Delete.create.call(this, {
 | 
				
			||||||
 | 
					          target: ref.id
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    map: function* (o : Op, f : Function) : Array<any> {
 | 
					    map: function* (o : Op, f : Function) : Array<any> {
 | 
				
			||||||
      o = o.start;
 | 
					      o = o.start;
 | 
				
			||||||
      var res = [];
 | 
					      var res = [];
 | 
				
			||||||
      while ( o != null) {
 | 
					      while ( o != null) {
 | 
				
			||||||
        var operation = yield* this.getOperation(o);
 | 
					        var operation = yield* this.getOperation(o);
 | 
				
			||||||
 | 
					        if (!operation.deleted) {
 | 
				
			||||||
          res.push(f(operation.content));
 | 
					          res.push(f(operation.content));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        o = operation.right;
 | 
					        o = operation.right;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return res;
 | 
					      return res;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    insert: function* (op, pos : number, contents : Array<any>) {
 | 
					    insert: function* (op, pos : number, contents : Array<any>) {
 | 
				
			||||||
      var ref = yield* Struct.List.ref.call(this, op, pos);
 | 
					      var left, right;
 | 
				
			||||||
      var right = ref != null ? ref.id : null;
 | 
					      if (pos === 0) {
 | 
				
			||||||
      var left = ref != null ? ref.left : null;
 | 
					        left = null;
 | 
				
			||||||
 | 
					        right = op.start;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        var ref = yield* Struct.List.ref.call(this, op, pos - 1);
 | 
				
			||||||
 | 
					        if (ref === null) {
 | 
				
			||||||
 | 
					          left = op.end;
 | 
				
			||||||
 | 
					          right = null;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          left = ref.id;
 | 
				
			||||||
 | 
					          right = ref.right;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      for (var key in contents) {
 | 
					      for (var key in contents) {
 | 
				
			||||||
        var insert = {
 | 
					        var insert = {
 | 
				
			||||||
          left: left,
 | 
					          left: left,
 | 
				
			||||||
@ -361,13 +418,14 @@ var Struct = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    get: function* (op, name) {
 | 
					    get: function* (op, name) {
 | 
				
			||||||
      var res = yield* this.getOperation(op.map[name]);
 | 
					      var res = yield* this.getOperation(op.map[name]);
 | 
				
			||||||
      return (res == null) ? void 0 : (res.opContent == null
 | 
					      return (res == null || res.deleted) ? void 0 : (res.opContent == null
 | 
				
			||||||
                ? res.content : yield* this.getType(res.opContent));
 | 
					                ? res.content : yield* this.getType(res.opContent));
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    set: function* (op, name, value) {
 | 
					    set: function* (op, name, value) {
 | 
				
			||||||
 | 
					      var right = op.map[name] || null;
 | 
				
			||||||
      var insert = {
 | 
					      var insert = {
 | 
				
			||||||
        left: null,
 | 
					        left: null,
 | 
				
			||||||
        right: op.map[name] || null,
 | 
					        right: right,
 | 
				
			||||||
        parent: op.id,
 | 
					        parent: op.id,
 | 
				
			||||||
        parentSub: name
 | 
					        parentSub: name
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
@ -379,6 +437,19 @@ var Struct = {
 | 
				
			|||||||
        insert.content = value;
 | 
					        insert.content = value;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      yield* Struct.Insert.create.call(this, insert);
 | 
					      yield* Struct.Insert.create.call(this, insert);
 | 
				
			||||||
 | 
					      if (right != null) {
 | 
				
			||||||
 | 
					        yield* Struct.Delete.create.call(this, {
 | 
				
			||||||
 | 
					          target: right
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    delete: function* (op, name) {
 | 
				
			||||||
 | 
					      var v = op.map[name] || null;
 | 
				
			||||||
 | 
					      if (v != null) {
 | 
				
			||||||
 | 
					        yield* Struct.Delete.create.call(this, {
 | 
				
			||||||
 | 
					          target: v
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -16,9 +16,22 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    *insert (pos, contents) {
 | 
					    *insert (pos, contents) {
 | 
				
			||||||
 | 
					      if (typeof pos !== "number") {
 | 
				
			||||||
 | 
					        throw new Error("pos must be a number!");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!(contents instanceof Array)) {
 | 
				
			||||||
 | 
					        throw new Error("contents must be an Array of objects!");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      var t = yield "transaction";
 | 
					      var t = yield "transaction";
 | 
				
			||||||
      yield* Y.Struct.List.insert.call(t, this._model, pos, contents);
 | 
					      yield* Y.Struct.List.insert.call(t, this._model, pos, contents);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    *delete (pos) {
 | 
				
			||||||
 | 
					      if (typeof pos !== "number") {
 | 
				
			||||||
 | 
					        throw new Error("pos must be a number!");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      var t = yield "transaction";
 | 
				
			||||||
 | 
					      yield* Y.Struct.List.delete.call(t, this._model, pos);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Y.List = function* YList(){
 | 
					  Y.List = function* YList(){
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,16 @@
 | 
				
			|||||||
    *val () {
 | 
					    *val () {
 | 
				
			||||||
      var t = yield "transaction";
 | 
					      var t = yield "transaction";
 | 
				
			||||||
      var model = yield* t.getOperation(this._model);
 | 
					      var model = yield* t.getOperation(this._model);
 | 
				
			||||||
      if (arguments.length === 1) {
 | 
					      if (arguments.length === 0) {
 | 
				
			||||||
 | 
					        var res = {};
 | 
				
			||||||
 | 
					        for (var key in model.map) {
 | 
				
			||||||
 | 
					          var v = yield* Y.Struct.Map.get.call(t, model, key);
 | 
				
			||||||
 | 
					          if (v != null) {
 | 
				
			||||||
 | 
					            res[key] = v;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					      } else if (arguments.length === 1) {
 | 
				
			||||||
        return yield* Y.Struct.Map.get.call(t, model, arguments[0]);
 | 
					        return yield* Y.Struct.Map.get.call(t, model, arguments[0]);
 | 
				
			||||||
      } else if (arguments.length === 2) {
 | 
					      } else if (arguments.length === 2) {
 | 
				
			||||||
        return yield* Y.Struct.Map.set.call(t, model, arguments[0], arguments[1]);
 | 
					        return yield* Y.Struct.Map.set.call(t, model, arguments[0], arguments[1]);
 | 
				
			||||||
@ -15,6 +24,11 @@
 | 
				
			|||||||
        throw new Error("Implement this case!");
 | 
					        throw new Error("Implement this case!");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    *delete (key) {
 | 
				
			||||||
 | 
					      var t = yield "transaction";
 | 
				
			||||||
 | 
					      var model = yield* t.getOperation(this._model);
 | 
				
			||||||
 | 
					      yield* Y.Struct.Map.delete.call(t, model, key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Y.Map = function* YMap(){
 | 
					  Y.Map = function* YMap(){
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ function getRandomNumber(n) {
 | 
				
			|||||||
  return Math.floor(Math.random() * n);
 | 
					  return Math.floor(Math.random() * n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
var keys = ["a", "b", "c", "d", "e", "f", 1, 2, 3, 4, 5, 6];
 | 
					var keys = ["a", "b", "c", "d", "e", "f", 1, 2, 3, 4, 5, 6];
 | 
				
			||||||
var numberOfYMapTests = 20;
 | 
					var numberOfYMapTests = 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function applyRandomTransactions (users, transactions, numberOfTransactions) {
 | 
					function applyRandomTransactions (users, transactions, numberOfTransactions) {
 | 
				
			||||||
  function* randomTransaction (root) {
 | 
					  function* randomTransaction (root) {
 | 
				
			||||||
@ -180,18 +180,43 @@ describe("Yjs", function(){
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  it("can create a List type", function(){
 | 
					  it("Basic get&set&delete with Map property", function(){
 | 
				
			||||||
 | 
					    var y = this.users[0];
 | 
				
			||||||
 | 
					    y.connector.flushAll();
 | 
				
			||||||
 | 
					    this.users[0].transact(function*(root){
 | 
				
			||||||
 | 
					      yield* root.val("stuff", "c0");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.users[0].transact(function*(root){
 | 
				
			||||||
 | 
					      yield* root.val("stuff", "c1");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.users[0].transact(function*(root){
 | 
				
			||||||
 | 
					      yield* root.delete("stuff");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    y.connector.flushAll();
 | 
				
			||||||
 | 
					    var transaction = function*(root){
 | 
				
			||||||
 | 
					      expect(yield* root.val("stuff")).toBeUndefined();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (var key in this.users) {
 | 
				
			||||||
 | 
					      var u = this.users[key];
 | 
				
			||||||
 | 
					      u.transact(transaction);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("List type: can create, insert, and delete elements", function(){
 | 
				
			||||||
    var y = this.users[0];
 | 
					    var y = this.users[0];
 | 
				
			||||||
    y.transact(function*(root){
 | 
					    y.transact(function*(root){
 | 
				
			||||||
      var list = yield* Y.List();
 | 
					      var list = yield* Y.List();
 | 
				
			||||||
      yield* root.val("list", list);
 | 
					      yield* root.val("list", list);
 | 
				
			||||||
      yield* list.insert(0, [1, 2, 3, 4]);
 | 
					      yield* list.insert(0, [1, 2, 3, 4]);
 | 
				
			||||||
 | 
					      yield* list.delete(1);
 | 
				
			||||||
      expect(yield* root.val("list")).not.toBeUndefined();
 | 
					      expect(yield* root.val("list")).not.toBeUndefined();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    y.connector.flushAll();
 | 
					    y.connector.flushAll();
 | 
				
			||||||
    function* transaction (root) {
 | 
					    function* transaction (root) {
 | 
				
			||||||
      var list = yield* root.val("list");
 | 
					      var list = yield* root.val("list");
 | 
				
			||||||
      expect(yield* list.val()).toEqual([1, 2, 3, 4]);
 | 
					      expect(yield* list.val()).toEqual([1, 3, 4]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for (var u of this.users) {
 | 
					    for (var u of this.users) {
 | 
				
			||||||
      u.transact(transaction);
 | 
					      u.transact(transaction);
 | 
				
			||||||
@ -200,19 +225,66 @@ describe("Yjs", function(){
 | 
				
			|||||||
  describe("Map random tests", function(){
 | 
					  describe("Map random tests", function(){
 | 
				
			||||||
    var randomMapTransactions = [
 | 
					    var randomMapTransactions = [
 | 
				
			||||||
      function* set (map) {
 | 
					      function* set (map) {
 | 
				
			||||||
        yield* map.val("getRandom(keys)", getRandomNumber());
 | 
					        yield* map.val("somekey", getRandomNumber());
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      function* delete_ (map) {
 | 
				
			||||||
 | 
					        yield* map.delete("somekey");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(){
 | 
					    it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(){
 | 
				
			||||||
      this.users[0].connector.flushAll();
 | 
					      this.users[0].connector.flushAll();
 | 
				
			||||||
      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
					      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
				
			||||||
      compareAllUsers(this.users);
 | 
					      compareAllUsers(this.users);
 | 
				
			||||||
 | 
					      var firstMap;
 | 
				
			||||||
 | 
					      for (var u of this.users) {
 | 
				
			||||||
 | 
					        u.transact(function*(root){//eslint-disable-line
 | 
				
			||||||
 | 
					          var val = yield* root.val();
 | 
				
			||||||
 | 
					          if (firstMap == null) {
 | 
				
			||||||
 | 
					            firstMap = val;
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            expect(val).toEqual(firstMap);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(){
 | 
					    it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(){
 | 
				
			||||||
      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
					      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
				
			||||||
      compareAllUsers(this.users);
 | 
					      compareAllUsers(this.users);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					  var numberOfYListTests = 100;
 | 
				
			||||||
 | 
					  describe("List random tests", function(){
 | 
				
			||||||
 | 
					    var randomListTests = [function* insert (root) {
 | 
				
			||||||
 | 
					      var list = yield* root.val("list");
 | 
				
			||||||
 | 
					      yield* list.insert(Math.floor(Math.random() * 10), [getRandomNumber()]);
 | 
				
			||||||
 | 
					    }, function* delete_(root) {
 | 
				
			||||||
 | 
					      var list = yield* root.val("list");
 | 
				
			||||||
 | 
					      yield* list.delete(Math.floor(Math.random() * 10));
 | 
				
			||||||
 | 
					    }];
 | 
				
			||||||
 | 
					    beforeEach(function(){
 | 
				
			||||||
 | 
					      this.users[0].transact(function*(root){
 | 
				
			||||||
 | 
					        var list = yield* Y.List();
 | 
				
			||||||
 | 
					        yield* root.val("list", list);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.users[0].connector.flushAll();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it(`succeeds after ${numberOfYListTests} actions`, function(){
 | 
				
			||||||
 | 
					      applyRandomTransactions(this.users, randomListTests, numberOfYListTests);
 | 
				
			||||||
 | 
					      compareAllUsers(this.users);
 | 
				
			||||||
 | 
					      var userList;
 | 
				
			||||||
 | 
					      this.users[0].transact(function*(root){
 | 
				
			||||||
 | 
					        var list = yield* root.val("list");
 | 
				
			||||||
 | 
					        if (userList == null) {
 | 
				
			||||||
 | 
					          userList = yield* list.val();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          expect(userList).toEqual(yield* list.val());
 | 
				
			||||||
 | 
					          expect(userList.length > 0).toBeTruthy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("Map debug tests", function(){
 | 
					  describe("Map debug tests", function(){
 | 
				
			||||||
    beforeEach(function(){
 | 
					    beforeEach(function(){
 | 
				
			||||||
      this.u1 = this.users[0];
 | 
					      this.u1 = this.users[0];
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user