Skip to content

Commit 1105357

Browse files
committed
fix(json-crdt): 🐛 make CBOR-based codec pass all tests
1 parent 1e37987 commit 1105357

File tree

4 files changed

+59
-40
lines changed

4 files changed

+59
-40
lines changed

src/json-crdt/codec/structural/binary/Decoder.ts

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -80,26 +80,13 @@ export class Decoder extends CborDecoderBase<CrdtReader> {
8080
return !peek ? UNDEFINED : this.cNode();
8181
}
8282

83-
protected nodeLength(minor: number): number {
84-
if (minor < 24) return minor;
85-
switch (minor) {
86-
case 24:
87-
return this.reader.u8();
88-
case 25:
89-
return this.reader.u16();
90-
case 26:
91-
return this.reader.u32();
92-
}
93-
return 0;
94-
}
95-
96-
public cNode(): JsonNode {
83+
protected cNode(): JsonNode {
9784
const reader = this.reader;
9885
const id = this.ts();
9986
const octet = reader.u8();
10087
const major = octet >> 5;
10188
const minor = octet & 0b11111;
102-
const length = this.nodeLength(minor);
89+
const length = minor < 24 ? minor : minor === 24 ? reader.u8() : minor === 25 ? reader.u16() : reader.u32();
10390
switch (major) {
10491
case CRDT_MAJOR.CON: return this.cCon(id, length);
10592
case CRDT_MAJOR.VAL: return this.cVal(id);
@@ -112,35 +99,35 @@ export class Decoder extends CborDecoderBase<CrdtReader> {
11299
throw new Error('UNKNOWN_NODE');
113100
}
114101

115-
public cCon(id: ITimestampStruct, length: number): ConNode {
102+
protected cCon(id: ITimestampStruct, length: number): ConNode {
116103
const doc = this.doc;
117104
const data = !length ? this.val() : this.ts();
118105
const node = new ConNode(id, data);
119106
doc.index.set(id, node);
120107
return node;
121108
}
122109

123-
public cVal(id: ITimestampStruct): ValNode {
110+
protected cVal(id: ITimestampStruct): ValNode {
124111
const child = this.cNode();
125112
const doc = this.doc;
126113
const node = new ValNode(doc, id, child.id);
127114
doc.index.set(id, node);
128115
return node;
129116
}
130117

131-
public cObj(id: ITimestampStruct, length: number): ObjNode {
118+
protected cObj(id: ITimestampStruct, length: number): ObjNode {
132119
const obj = new ObjNode(this.doc, id);
133120
for (let i = 0; i < length; i++) this.cObjChunk(obj);
134121
this.doc.index.set(id, obj);
135122
return obj;
136123
}
137124

138-
private cObjChunk(obj: ObjNode): void {
125+
protected cObjChunk(obj: ObjNode): void {
139126
const key: string = this.key();
140127
obj.keys.set(key, this.cNode().id);
141128
}
142129

143-
public cVec(id: ITimestampStruct, length: number): VecNode {
130+
protected cVec(id: ITimestampStruct, length: number): VecNode {
144131
const reader = this.reader;
145132
const obj = new VecNode(this.doc, id);
146133
const elements = obj.elements;
@@ -155,7 +142,7 @@ export class Decoder extends CborDecoderBase<CrdtReader> {
155142
return obj;
156143
}
157144

158-
public cArr(id: ITimestampStruct, length: number): ArrNode {
145+
protected cArr(id: ITimestampStruct, length: number): ArrNode {
159146
const obj = new ArrNode(this.doc, id);
160147
obj.ingest(length, this.cArrChunk);
161148
this.doc.index.set(id, obj);
@@ -171,7 +158,7 @@ export class Decoder extends CborDecoderBase<CrdtReader> {
171158
return new ArrChunk(id, length, ids);
172159
};
173160

174-
public cStr(id: ITimestampStruct, length: number): StrNode {
161+
protected cStr(id: ITimestampStruct, length: number): StrNode {
175162
const node = new StrNode(id);
176163
if (length) node.ingest(length, this.cStrChunk);
177164
this.doc.index.set(id, node);
@@ -191,7 +178,7 @@ export class Decoder extends CborDecoderBase<CrdtReader> {
191178
return new StrChunk(id, text.length, text);
192179
};
193180

194-
public cBin(id: ITimestampStruct, length: number): BinNode {
181+
protected cBin(id: ITimestampStruct, length: number): BinNode {
195182
const node = new BinNode(id);
196183
if (length) node.ingest(length, this.cBinChunk);
197184
this.doc.index.set(id, node);

src/json-crdt/codec/structural/binary/Encoder.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class Encoder extends CborEncoder<CrdtWriter> {
125125
const ts = this.ts;
126126
const writer = this.writer;
127127
ts(obj.id);
128-
this.writeTL(CRDT_MAJOR_OVERLAY.VEC, obj.size());
128+
this.writeTL(CRDT_MAJOR_OVERLAY.ARR, obj.size());
129129
const index = this.doc.index;
130130
for (let chunk = obj.first(); chunk; chunk = obj.next(chunk)) {
131131
const span = chunk.span;
@@ -152,12 +152,12 @@ export class Encoder extends CborEncoder<CrdtWriter> {
152152
}
153153
}
154154

155-
protected cBin(obj: BinNode): void {
155+
protected cBin(node: BinNode): void {
156156
const ts = this.ts;
157157
const writer = this.writer;
158-
ts(obj.id);
159-
this.writeTL(CRDT_MAJOR_OVERLAY.STR, obj.size());
160-
for (let chunk = obj.first(); chunk; chunk = obj.next(chunk)) {
158+
ts(node.id);
159+
this.writeTL(CRDT_MAJOR_OVERLAY.BIN, node.size());
160+
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
161161
const length = chunk.span;
162162
const deleted = chunk.del;
163163
writer.b1vu28(chunk.del, length);
@@ -167,15 +167,15 @@ export class Encoder extends CborEncoder<CrdtWriter> {
167167
}
168168
}
169169

170-
protected cVal(obj: ValNode): void {
171-
this.ts(obj.id);
170+
protected cVal(node: ValNode): void {
171+
this.ts(node.id);
172172
this.writeTL(CRDT_MAJOR_OVERLAY.VAL, 0);
173-
this.cNode(obj.node());
173+
this.cNode(node.node());
174174
}
175175

176-
protected cCon(obj: ConNode): void {
177-
const val = obj.val;
178-
this.ts(obj.id);
176+
protected cCon(node: ConNode): void {
177+
const val = node.val;
178+
this.ts(node.id);
179179
if (val instanceof Timestamp) {
180180
this.writeTL(CRDT_MAJOR_OVERLAY.CON, 1);
181181
this.ts(val as Timestamp);

src/json-crdt/codec/structural/binary/__tests__/ViewDecoder.spec.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import {Timestamp, VectorClock, equal} from '../../../../../json-crdt-patch/clock';
1+
import {Timestamp, VectorClock} from '../../../../../json-crdt-patch/clock';
22
import {Model} from '../../../../model';
33
import {Encoder} from '../Encoder';
44
import {Decoder} from '../Decoder';
55
import {ViewDecoder} from '../ViewDecoder';
66
import {konst} from '../../../../../json-crdt-patch/builder/Konst';
77

88
describe('logical', () => {
9-
test('decodes clock', () => {
9+
test('can decode various documents', () => {
1010
const doc1 = Model.withLogicalClock(new VectorClock(222, 1));
1111
const encoder = new Encoder();
1212
const viewDecoder = new ViewDecoder();
@@ -15,6 +15,9 @@ describe('logical', () => {
1515
const encoded = encoder.encode(doc1);
1616
const decoded = viewDecoder.decode(encoded);
1717
const decoded2 = decoder.decode(encoded).view();
18+
// console.log(decoded);
19+
// console.log(decoded2);
20+
// console.log(doc1.view());
1821
expect(decoded).toStrictEqual(doc1.view());
1922
expect(decoded2).toStrictEqual(doc1.view());
2023
};
@@ -39,7 +42,7 @@ describe('logical', () => {
3942
assertCanDecode();
4043
});
4144

42-
test('can decode ID as const value', () => {
45+
test('decodes "con" timestamp as null', () => {
4346
const model = Model.withLogicalClock();
4447
model.api.root({
4548
foo: konst(new Timestamp(model.clock.sid, 2)),
@@ -50,4 +53,34 @@ describe('logical', () => {
5053
const view = viewDecoder.decode(encoded);
5154
expect((view as any).foo).toBe(null);
5255
});
56+
57+
test('can decode a simple number', () => {
58+
const model = Model.withLogicalClock();
59+
model.api.root(123);
60+
const encoder = new Encoder();
61+
const viewDecoder = new ViewDecoder();
62+
const encoded = encoder.encode(model);
63+
const view = viewDecoder.decode(encoded);
64+
expect(view).toStrictEqual(123);
65+
});
66+
67+
test('can decode a simple string', () => {
68+
const model = Model.withLogicalClock();
69+
model.api.root('asdf');
70+
const encoder = new Encoder();
71+
const viewDecoder = new ViewDecoder();
72+
const encoded = encoder.encode(model);
73+
const view = viewDecoder.decode(encoded);
74+
expect(view).toStrictEqual('asdf');
75+
});
76+
77+
test('can decode a simple object', () => {
78+
const model = Model.withLogicalClock();
79+
model.api.root({yes: false});
80+
const encoder = new Encoder();
81+
const viewDecoder = new ViewDecoder();
82+
const encoded = encoder.encode(model);
83+
const view = viewDecoder.decode(encoded);
84+
expect(view).toStrictEqual({yes: false});
85+
});
5386
});

src/json-crdt/codec/structural/json/__tests__/runCodecAllTypesSmokeTests.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {konst} from '../../../../../json-crdt-patch/builder/Konst';
22
import {vec} from '../../../../../json-crdt-patch/builder/Tuple';
3-
import {Timestamp} from '../../../../../json-crdt-patch/clock';
43
import {Model} from '../../../../model';
54

65
export const runCodecAllTypesSmokeTests = (assertCodec: (doc: Model) => void) => {
@@ -16,13 +15,13 @@ export const runCodecAllTypesSmokeTests = (assertCodec: (doc: Model) => void) =>
1615
assertCodec(model);
1716
});
1817

19-
test('number with server clock', () => {
18+
test('numbers with server clock', () => {
2019
const model = Model.withServerClock();
2120
model.api.root([1, 0, -4, 1.132, 8324.234234, 888888888888]);
2221
assertCodec(model);
2322
});
2423

25-
test('string', () => {
24+
test('strings', () => {
2625
const model = Model.withLogicalClock();
2726
model.api.root(['', 'abc', '😛']);
2827
assertCodec(model);

0 commit comments

Comments
 (0)