Skip to content

Commit b0b6a95

Browse files
committed
fix(json-ot): 🐛 make compose() hand-crafted tests pass
1 parent 8b07e31 commit b0b6a95

File tree

3 files changed

+23
-14
lines changed

3 files changed

+23
-14
lines changed

src/json-ot/types/ot-string/StringType.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,10 @@ export const apply = (str: string, op: StringTypeOp): string => {
144144
export const compose = (op1: StringTypeOp, op2: StringTypeOp): StringTypeOp => {
145145
const op3: StringTypeOp = [];
146146
const len1 = op1.length;
147+
const len2 = op2.length;
147148
let off1 = 0;
148149
let i1 = 0;
149-
for (let i2 = 0; i2 < op2.length; i2++) {
150+
for (let i2 = 0; i2 < len2; i2++) {
150151
const comp2 = op2[i2];
151152
let doDelete = false;
152153
switch (typeof comp2) {
@@ -196,25 +197,31 @@ export const compose = (op1: StringTypeOp, op2: StringTypeOp): StringTypeOp => {
196197
const comp1 = i1 >= len1 ? remaining : op1[i1];
197198
const length1 = componentLength(comp1);
198199
const isDelete = idDeleteComponent(comp1);
199-
if (remaining >= length1) {
200-
i1++;
201-
off1 = 0;
202-
const end = off2 + length1;
203-
if (isDelete) append(op3, copyComponent(comp1));
204-
else {
200+
if (remaining >= (length1 - off1)) {
201+
if (isDelete) {
202+
append(op3, copyComponent(comp1));
203+
i1++;
204+
off1 = 0;
205+
} else {
206+
const end = off2 + (length1 - off1);
205207
switch (typeof comp1) {
206208
case 'number': append(op3, isReversible ? [comp2[0].substring(off2, end)] : -length1); break;
207-
case 'string': off2 += length1; break;
209+
case 'string': {
210+
off2 += (length1 - off1);
211+
break;
212+
}
208213
}
214+
i1++;
215+
off1 = 0;
216+
off2 = end;
209217
}
210-
if (!isDelete) off2 = end;
211218
} else {
212219
if (isDelete) {
213-
append(op3, copyComponent(comp1));
220+
append(op3, copyComponent(comp1));
214221
} else {
215222
switch (typeof comp1) {
216223
case 'number': append(op3, isReversible ? [comp2[0].substring(off2)] : -remaining); break;
217-
case 'string': off2 += remaining; break;
224+
// case 'string': break;
218225
}
219226
}
220227
off1 += remaining;

src/json-ot/types/ot-string/__tests__/StringOtFuzzer.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {RandomJson} from "../../../../json-random";
22
import {Fuzzer} from "../../../../util/Fuzzer";
3-
import {append} from "../StringType";
3+
import {append, normalize} from "../StringType";
44
import {StringTypeOp} from "../types";
55

66
export class StringOtFuzzer extends Fuzzer {
@@ -10,7 +10,7 @@ export class StringOtFuzzer extends Fuzzer {
1010

1111
genOp(str: string): StringTypeOp {
1212
if (!str) return [this.genString()];
13-
const op: StringTypeOp = [];
13+
let op: StringTypeOp = [];
1414
let off = 0;
1515
let remaining = str.length;
1616
while (remaining > 0) {
@@ -24,7 +24,7 @@ export class StringOtFuzzer extends Fuzzer {
2424
if (Math.random() < 0.5) {
2525
append(op, -len);
2626
} else {
27-
append(op, [str.substr(off, len)]);
27+
append(op, [str.substring(off, off + len)]);
2828
}
2929
off += len;
3030
},
@@ -35,6 +35,7 @@ export class StringOtFuzzer extends Fuzzer {
3535
fn();
3636
remaining = str.length - off;
3737
}
38+
op = normalize(op);
3839
if (op.length === 1 && typeof op[0] === 'number' && op[0] > 0) return [this.genString()];
3940
return op;
4041
}

src/json-ot/types/ot-string/__tests__/StringType.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ describe('compose()', () => {
104104
['insert in previous insert', 'aabb', [2, '1111'], [4, '22'], 'aa112211bb'],
105105
['fuzzer bug #1', 'd6', ['}B'], [['}'], ';0q', 2, ['6']], ';0qBd'],
106106
['fuzzer bug #2', 'Ai', [['A'], '#', -1], [-1], ''],
107+
['fuzzer bug #3', 'M}', ['!y1'], ["'/*s", 2, ',/@', -2, ['}']], "'/*s!y,/@"],
107108
];
108109

109110
describe('can compose', () => {

0 commit comments

Comments
 (0)