Skip to content

Commit

Permalink
fix: fixed requested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
joaopereira12 committed Jul 26, 2024
1 parent 08ace2b commit 007ae91
Show file tree
Hide file tree
Showing 8 changed files with 1,432 additions and 1,478 deletions.
43 changes: 18 additions & 25 deletions packages/crdt/src/builtins/LWWElementSet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ export class LWWElementSet<T> {

lookup(element: T): boolean {

const addElemTimestmp = this._adds.get(element);
const remElemTimestmp = this._removes.get(element);
const addTimestamp = this._adds.get(element);
const removeTimestamp = this._removes.get(element);

if (addElemTimestmp !== undefined &&
(remElemTimestmp === undefined || addElemTimestmp > remElemTimestmp)) {
return true;
if (addTimestamp !== undefined) {
if (removeTimestamp === undefined || addTimestamp > removeTimestamp || (addTimestamp-removeTimestamp === 0 && this._bias === Bias.ADD)) {
return true;
}
}
return false;
}

add(element: T, timestamp: number): void {
this._adds.set(element, timestamp);
add(element: T): void {
this._adds.set(element, Date.now());
}

remove(element: T, timestamp: number): void {
this._removes.set(element, timestamp);
remove(element: T): void {
this._removes.set(element, Date.now());
}

getAdds(): Map<T, number> {
Expand All @@ -58,26 +59,18 @@ export class LWWElementSet<T> {

merge(peerSet: LWWElementSet<T>): void {

for (let element of peerSet._adds.keys()) {
if (!this._adds.has(element) || this.compareTimestamp(this._adds.get(element)!, peerSet.getAdds().get(element)!)) {
this._adds.set(element, peerSet.getAdds().get(element)!);
for (let [element, timestamp] of peerSet._adds.entries()) {
const thisTimestamp = this._adds.get(element);
if (!thisTimestamp || thisTimestamp < timestamp) {
this._adds.set(element, timestamp);
}
}

for (let element of peerSet._removes.keys()) {
if (!this._removes.has(element) || this.compareTimestamp(this._removes.get(element)!, peerSet.getRemoves().get(element)!)) {
this._removes.set(element, peerSet.getRemoves().get(element)!);
for (let [element, timestamp] of peerSet._removes.entries()) {
const thisTimestamp = this._removes.get(element);
if (!thisTimestamp || thisTimestamp < timestamp) {
this._removes.set(element, timestamp);
}
}
}

private compareTimestamp(thisTime: number, otherTime: number) {

const timestampComparison = thisTime - otherTime;

if (timestampComparison === 0) {
return this._bias !== Bias.ADD;
}
return timestampComparison < 0;
}
}
69 changes: 69 additions & 0 deletions packages/crdt/tests/GCounter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { describe, test, expect, beforeEach, afterEach } from "vitest";
import { GCounter } from "../src/builtins/GCounter";

describe("G-Counter Tests", () => {

let set1: GCounter;
let set2: GCounter;

beforeEach(() => {
set1 = new GCounter({ "node1": 5, "node2": 10});
set2 = new GCounter({ "node1": 5, "node2": 10});
});

test("Test Initial Values", () => {
expect(set1.value()).toBe(15);
expect(set2.value()).toBe(15);
});

test("Test Increment", () => {

set1.increment("node1", 10);
set1.increment("node2", 5);

expect(set1.value()).toBe(30);
});

test("Test Compare", () => {

expect(set1.compare(set2)).toBe(true);

set2.increment("node1", 5);

expect(set1.compare(set2)).toBe(false);

let set3 = new GCounter({ "node1": 5, "node2": 10, "node3": 15 });

expect(set1.compare(set3)).toBe(false);
});

test("Test Merge", () => {

const counter1 = new GCounter({ "node1": 5 });
const counter2 = new GCounter({ "node2": 10 });

counter1.merge(counter2);

expect(counter1.counts).toEqual({ "node1": 5, "node2": 10 });
expect(counter1.value()).toBe(15);

set1.increment("node1", 5);
set2.increment("node2", 10);
expect(set1.value()).toBe(35);
expect(set2.value()).toBe(40);
set1.merge(set2);
expect(set1.value()).toBe(45);
expect(set1.counts[0]).toBe(10);
expect(set1.counts[1]).toBe(20);
expect(set1.counts[2]).toBe(15);

set2.merge(set1);
expect(set2.value()).toBe(45);
expect(set2.counts[0]).toBe(10);
expect(set2.counts[1]).toBe(20);
expect(set2.counts[2]).toBe(15);

expect(set2.compare(set1)).toBe(true);
});

});
46 changes: 46 additions & 0 deletions packages/crdt/tests/GSet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, test, expect, beforeEach, afterEach } from "vitest";
import { GSet } from "../src/builtins/GSet";

describe("G-Set Tests", () => {

let set1: GSet<string>;
let set2: GSet<string>;

beforeEach(() => {
set1 = new GSet<string>(new Set<string>(["walter", "jesse", "mike"]));
set2 = new GSet<string>(new Set<string>(["walter", "jesse", "mike"]));
});

test("Test Add", () => {
set1.add("gustavo");
set2.add("gustavo");

expect(set1.lookup("gustavo")).toBe(true);
expect(set2.lookup("gustavo")).toBe(true);
});

test("Test Compare", () => {
expect(set1.compare(set2)).toBe(true);

set1.add("gustavo");

expect(set1.compare(set2)).toBe(false);

set2.add("gustavo");

expect(set1.compare(set2)).toBe(true);
});

test("Test Merge", () => {
set1.add("gustavo");
set2.add("lalo");

expect(set1.compare(set2)).toBe(false);

set1.merge(set2);
set2.merge(set1);

expect(set1.compare(set2)).toBe(true);

});
});
106 changes: 106 additions & 0 deletions packages/crdt/tests/LWWElementSet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { describe, test, expect, beforeEach } from "vitest";
import { LWWElementSet, Bias } from "../src/builtins/LWWElementSet";

describe("LWW-Element-Set Tests", () => {

const testValues = ["walter", "jesse", "mike"];

let set1: LWWElementSet<string>;
let set2: LWWElementSet<string>;
let set3: LWWElementSet<string>;

beforeEach(() => {
set1 = new LWWElementSet<string>(new Map(), new Map(), Bias.ADD);
set2 = new LWWElementSet<string>(new Map(), new Map(), Bias.ADD);
set3 = new LWWElementSet<string>(new Map(), new Map(), Bias.REMOVE);

testValues.forEach((value) => {
set1.add(value);
set2.add(value);
set3.add(value);
});
});

test("Test Add Elements", () => {

expect(set1.lookup("gustavo")).toBe(false);

set1.add("gustavo");

expect(set1.lookup("gustavo")).toBe(true);

});

test("Test Remove Elements", () => {

expect(set1.lookup("mike")).toBe(true);

set1.remove("mike");

expect(set1.lookup("mike")).toBe(false);

});

test("Test Compare Sets", () => {

expect(set1.compare(set2)).toBe(true);
expect(set1.compare(set3)).toBe(true);
expect(set3.compare(set2)).toBe(true);

set1.remove("jesse");

expect(set1.compare(set2)).toBe(false);
expect(set1.compare(set3)).toBe(false);
expect(set3.compare(set2)).toBe(true);

});

describe("Test Merge Elements" , () => {

test("Merge Sets", () => {

// Adding different names to each set
set1.add("gustavo");
set2.add("saul");

expect(set1.compare(set2)).toBe(false);

set1.merge(set2);
set2.merge(set1);

expect(set1.compare(set2)).toBe(true);

});

test("Same Element, different Timestamps", () => {

const timestamp = Date.now();
set1.getAdds().set("gustavo", timestamp);
set2.getAdds().set("gustavo", timestamp + 5);

expect(set1.getAdds().get("gustavo")).toBe(timestamp);

set1.merge(set2);
set2.merge(set1);

expect(set1.getAdds().get("gustavo")).toBe(timestamp + 5);
expect(set2.getAdds().get("gustavo")).toBe(timestamp + 5);

});

test("Merge Removal Timestamps", () => {

const timestamp = Date.now();

set1.getAdds().set("gustavo", timestamp);
set2.getRemoves().set("gustavo", timestamp + 5);

set1.merge(set2);


expect(set1.lookup("gustavo")).toBe(false);
expect(set1.getRemoves().get("gustavo")).toBe(timestamp + 5);

});
});
});
60 changes: 60 additions & 0 deletions packages/crdt/tests/PNCounter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe, test, expect, beforeEach, afterEach } from "vitest";
import { PNCounter } from "../src/builtins/PNCounter";
import { GCounter } from "../src/builtins/GCounter";

describe("PN-Counter Tests", () => {

let set1: PNCounter;
let set2: PNCounter;

beforeEach(() => {
set1 = new PNCounter(new GCounter({ 0: 5, 1: 10, 2: 15 }), new GCounter({ 0: 3, 1: 4, 2: 3 }));
set2 = new PNCounter(new GCounter({ 0: 5, 1: 10, 2: 15 }), new GCounter({ 0: 3, 1: 4, 2: 3 }));
});

test("Test Initial Value", () => {
expect(set1.value()).toBe(20);
expect(set2.value()).toBe(20);
});

test("Test Increment", () => {
set1.increment(0,10);
set2.increment(0,20);
expect(set1.value()).toBe(30);
expect(set2.value()).toBe(40);
});

test("Test Decrement", () => {
set1.decrement(0,10);
set2.decrement(0,20);
expect(set1.value()).toBe(10);
expect(set2.value()).toBe(0);
});

test("Test Compare", () => {
expect(set1.compare(set2)).toBe(true);

set1.decrement(0,10);

expect(set1.compare(set2)).toBe(false);

set2.decrement(0,10);

expect(set1.compare(set2)).toBe(true);
});

test("Test Merge", () => {
set1.increment(0,10);
set2.decrement(1,5);

expect(set1.compare(set2)).toBe(false);
expect(set2.compare(set1)).toBe(false);

set1.merge(set2);
set2.merge(set1);

expect(set1.compare(set2)).toBe(true);
expect(set2.compare(set1)).toBe(true);
});

});
Loading

0 comments on commit 007ae91

Please sign in to comment.