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 ) {
|
||||||
pos--;
|
if (!o.deleted) {
|
||||||
|
res = o;
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return o;
|
|
||||||
},
|
},
|
||||||
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);
|
||||||
res.push(f(operation.content));
|
if (!operation.deleted) {
|
||||||
|
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