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;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  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: {
 | 
			
		||||
    /*{
 | 
			
		||||
        content: any,
 | 
			
		||||
@ -294,27 +321,57 @@ var Struct = {
 | 
			
		||||
      if (op.start == null) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      var res = null;
 | 
			
		||||
      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--;
 | 
			
		||||
        }
 | 
			
		||||
      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> {
 | 
			
		||||
      o = o.start;
 | 
			
		||||
      var res = [];
 | 
			
		||||
      while ( o != null) {
 | 
			
		||||
        var operation = yield* this.getOperation(o);
 | 
			
		||||
        if (!operation.deleted) {
 | 
			
		||||
          res.push(f(operation.content));
 | 
			
		||||
        }
 | 
			
		||||
        o = operation.right;
 | 
			
		||||
      }
 | 
			
		||||
      return res;
 | 
			
		||||
    },
 | 
			
		||||
    insert: function* (op, pos : number, contents : Array<any>) {
 | 
			
		||||
      var ref = yield* Struct.List.ref.call(this, op, pos);
 | 
			
		||||
      var right = ref != null ? ref.id : null;
 | 
			
		||||
      var left = ref != null ? ref.left : null;
 | 
			
		||||
      var left, right;
 | 
			
		||||
      if (pos === 0) {
 | 
			
		||||
        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) {
 | 
			
		||||
        var insert = {
 | 
			
		||||
          left: left,
 | 
			
		||||
@ -361,13 +418,14 @@ var Struct = {
 | 
			
		||||
    },
 | 
			
		||||
    get: function* (op, 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));
 | 
			
		||||
    },
 | 
			
		||||
    set: function* (op, name, value) {
 | 
			
		||||
      var right = op.map[name] || null;
 | 
			
		||||
      var insert = {
 | 
			
		||||
        left: null,
 | 
			
		||||
        right: op.map[name] || null,
 | 
			
		||||
        right: right,
 | 
			
		||||
        parent: op.id,
 | 
			
		||||
        parentSub: name
 | 
			
		||||
      };
 | 
			
		||||
@ -379,6 +437,19 @@ var Struct = {
 | 
			
		||||
        insert.content = value;
 | 
			
		||||
      }
 | 
			
		||||
      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) {
 | 
			
		||||
      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";
 | 
			
		||||
      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(){
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,16 @@
 | 
			
		||||
    *val () {
 | 
			
		||||
      var t = yield "transaction";
 | 
			
		||||
      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]);
 | 
			
		||||
      } else if (arguments.length === 2) {
 | 
			
		||||
        return yield* Y.Struct.Map.set.call(t, model, arguments[0], arguments[1]);
 | 
			
		||||
@ -15,6 +24,11 @@
 | 
			
		||||
        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(){
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ function getRandomNumber(n) {
 | 
			
		||||
  return Math.floor(Math.random() * n);
 | 
			
		||||
}
 | 
			
		||||
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* 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];
 | 
			
		||||
    y.transact(function*(root){
 | 
			
		||||
      var list = yield* Y.List();
 | 
			
		||||
      yield* root.val("list", list);
 | 
			
		||||
      yield* list.insert(0, [1, 2, 3, 4]);
 | 
			
		||||
      yield* list.delete(1);
 | 
			
		||||
      expect(yield* root.val("list")).not.toBeUndefined();
 | 
			
		||||
    });
 | 
			
		||||
    y.connector.flushAll();
 | 
			
		||||
    function* transaction (root) {
 | 
			
		||||
      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) {
 | 
			
		||||
      u.transact(transaction);
 | 
			
		||||
@ -200,19 +225,66 @@ describe("Yjs", function(){
 | 
			
		||||
  describe("Map random tests", function(){
 | 
			
		||||
    var randomMapTransactions = [
 | 
			
		||||
      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(){
 | 
			
		||||
      this.users[0].connector.flushAll();
 | 
			
		||||
      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
			
		||||
      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(){
 | 
			
		||||
      applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
 | 
			
		||||
      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(){
 | 
			
		||||
    beforeEach(function(){
 | 
			
		||||
      this.u1 = this.users[0];
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user