Skip to content

Commit 7eecc01

Browse files
committed
test(json-crdt-extensions): 💍 add Overlay.tuples() tests
1 parent 5cff839 commit 7eecc01

File tree

2 files changed

+143
-2
lines changed

2 files changed

+143
-2
lines changed

src/json-crdt-extensions/peritext/overlay/Overlay.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export class Overlay<T = string> implements Printable, Stateful {
3131
public root: OverlayPoint<T> | undefined = undefined;
3232

3333
/** A virtual absolute start point, used when the absolute start is missing. */
34-
private readonly START: OverlayPoint<T>;
34+
public readonly START: OverlayPoint<T>;
3535

3636
/** A virtual absolute end point, used when the absolute end is missing. */
37-
private readonly END: OverlayPoint<T>;
37+
public readonly END: OverlayPoint<T>;
3838

3939
constructor(protected readonly txt: Peritext<T>) {
4040
const id = txt.str.id;
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import {next} from 'sonic-forest/lib/util';
2+
import {Kit, setupHelloWorldKit, setupHelloWorldWithFewEditsKit, setupNumbersKit, setupNumbersWithTombstonesKit} from '../../__tests__/setup';
3+
import {Anchor} from '../../rga/constants';
4+
import {MarkerOverlayPoint} from '../MarkerOverlayPoint';
5+
import {OverlayPoint} from '../OverlayPoint';
6+
7+
const runPairsTests = (setup: () => Kit) => {
8+
describe('.tuples()', () => {
9+
test('returns [START, END] single tuple for an empty overlay', () => {
10+
const {peritext} = setup();
11+
const overlay = peritext.overlay;
12+
overlay.refresh();
13+
const list = [...overlay.tuples()];
14+
expect(list).toEqual([
15+
[overlay.START, overlay.END],
16+
]);
17+
});
18+
19+
test('when caret at abs start, returns one [p, END] tuple', () => {
20+
const {peritext} = setup();
21+
const overlay = peritext.overlay;
22+
peritext.editor.cursor.set(peritext.pointAbsStart());
23+
overlay.refresh();
24+
const list = [...overlay.tuples()];
25+
const p1 = overlay.first()!;
26+
expect(peritext.editor.cursor.start.rightChar()?.view()).toBe(peritext.strApi().view()[0]);
27+
expect(list).toEqual([
28+
[p1, overlay.END],
29+
]);
30+
});
31+
32+
test('when caret at abs end, returns one [START, p] tuple', () => {
33+
const {peritext} = setup();
34+
const overlay = peritext.overlay;
35+
peritext.editor.cursor.set(peritext.pointAbsEnd());
36+
overlay.refresh();
37+
const list = [...overlay.tuples()];
38+
const p1 = overlay.first()!;
39+
expect(peritext.editor.cursor.start.leftChar()?.view()).toBe(peritext.strApi().view().slice(-1));
40+
expect(list).toEqual([
41+
[overlay.START, p1]
42+
]);
43+
});
44+
45+
test('for only caret in overlay, returns two edge tuples', () => {
46+
const {peritext} = setup();
47+
const overlay = peritext.overlay;
48+
peritext.editor.cursor.setAt(5);
49+
overlay.refresh();
50+
const list = [...overlay.tuples()];
51+
const p1 = overlay.first()!;
52+
expect(peritext.editor.cursor.start.leftChar()?.view()).toBe(peritext.strApi().view()[4]);
53+
expect(list).toEqual([
54+
[overlay.START, p1],
55+
[p1, overlay.END],
56+
]);
57+
});
58+
59+
test('for a cursor selection, returns three tuples', () => {
60+
const {peritext} = setup();
61+
const overlay = peritext.overlay;
62+
peritext.editor.cursor.setAt(3, 3);
63+
overlay.refresh();
64+
const list = [...overlay.tuples()];
65+
const p1 = overlay.first()!;
66+
const p2 = next(p1)!;
67+
expect(peritext.editor.cursor.text()).toBe(peritext.strApi().view().slice(3, 6));
68+
expect(list).toEqual([
69+
[overlay.START, p1],
70+
[p1, p2],
71+
[p2, overlay.END],
72+
]);
73+
});
74+
75+
test('for a cursor selection at abs start, returns two tuples', () => {
76+
const {peritext} = setup();
77+
const overlay = peritext.overlay;
78+
const range = peritext.range(peritext.pointAbsStart(), peritext.pointAt(5));
79+
peritext.editor.cursor.setRange(range);
80+
overlay.refresh();
81+
const list = [...overlay.tuples()];
82+
const p1 = overlay.first()!;
83+
const p2 = next(p1)!;
84+
expect(list).toEqual([
85+
[p1, p2],
86+
[p2, overlay.END],
87+
]);
88+
});
89+
90+
test('for a cursor selection at abs end, returns two tuples', () => {
91+
const {peritext} = setup();
92+
const overlay = peritext.overlay;
93+
const range = peritext.range(peritext.pointAt(5, Anchor.Before), peritext.pointAbsEnd());
94+
peritext.editor.cursor.setRange(range);
95+
overlay.refresh();
96+
const list = [...overlay.tuples()];
97+
const p1 = overlay.first()!;
98+
const p2 = next(p1)!;
99+
expect(list).toEqual([
100+
[overlay.START, p1],
101+
[p1, p2],
102+
]);
103+
});
104+
105+
test('for a marker and a slice after the marker, returns 4 tuples', () => {
106+
const {peritext} = setup();
107+
const {editor, overlay} = peritext;
108+
editor.cursor.setAt(3);
109+
const [marker] = editor.saved.insMarker('<paragraph>');
110+
editor.cursor.setAt(6, 2);
111+
editor.extra.insStack('<b>');
112+
overlay.refresh();
113+
const p1 = overlay.first()!;
114+
const p2 = next(p1)!;
115+
const p3 = next(p2)!;
116+
const list = [...overlay.tuples()];
117+
expect(list).toEqual([
118+
[overlay.START, p1],
119+
[p1, p2],
120+
[p2, p3],
121+
[p3, overlay.END],
122+
]);
123+
expect(p1 instanceof MarkerOverlayPoint).toBe(true);
124+
expect(p2 instanceof OverlayPoint).toBe(true);
125+
expect(p3 instanceof OverlayPoint).toBe(true);
126+
expect((p1 as MarkerOverlayPoint).marker).toBe(marker);
127+
expect(p2.layers.length).toBe(2);
128+
expect(p3.layers.length).toBe(0);
129+
expect(p2.refs.length).toBe(2);
130+
expect(p3.refs.length).toBe(2);
131+
});
132+
});
133+
};
134+
135+
describe('numbers "hello world", no edits', () => {
136+
runPairsTests(setupHelloWorldKit);
137+
});
138+
139+
describe('numbers "hello world", with default schema and tombstones', () => {
140+
runPairsTests(setupHelloWorldWithFewEditsKit);
141+
});

0 commit comments

Comments
 (0)