From 4c7fcf42fd3569be11e5e4bd2cef154b8edabb10 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 12 Jun 2024 23:55:37 +0200 Subject: [PATCH 1/6] =?UTF-8?q?test(json-crdt-extensions):=20=F0=9F=92=8D?= =?UTF-8?q?=20setup=20alphabet=20test=20helpers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../peritext/__tests__/setup.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/json-crdt-extensions/peritext/__tests__/setup.ts b/src/json-crdt-extensions/peritext/__tests__/setup.ts index 7a2e2832f1..47438f02cc 100644 --- a/src/json-crdt-extensions/peritext/__tests__/setup.ts +++ b/src/json-crdt-extensions/peritext/__tests__/setup.ts @@ -103,3 +103,57 @@ export const setupNumbersWithTombstonesKit = (sid?: number): Kit => { sid, ); }; + +/** + * Creates a Peritext instance with text "abcdefghijklmnopqrstuvwxyz", no edits. + */ +export const setupAlphabetKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, 'abcdefghijklmnopqrstuvwxyz'); + if (str.view() !== 'abcdefghijklmnopqrstuvwxyz') throw new Error('Invalid text'); + }); +}; + +/** + * Creates a Peritext instance with text "abcdefghijklmnopqrstuvwxyz", two text chunks. + */ +export const setupAlphabetWithTwoChunksKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, 'lmnopqrstuvwxyz'); + str.ins(0, 'abcdefghijk'); + if (str.view() !== 'abcdefghijklmnopqrstuvwxyz') throw new Error('Invalid text'); + }); +}; + +/** + * Creates a Peritext instance with text "abcdefghijklmnopqrstuvwxyz", with RGA chunks split. + */ +export const setupAlphabetChunkSplitKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, 'lmnwxyz'); + str.ins(3, 'opqrstuv'); + str.ins(0, 'abcdefghijk'); + if (str.view() !== 'abcdefghijklmnopqrstuvwxyz') throw new Error('Invalid text'); + }); +}; + +/** + * Creates a Peritext instance with text "abcdefghijklmnopqrstuvwxyz", with RGA deletes. + */ +export const setupAlphabetWithDeletesKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, 'lmXXXnwYxyz'); + str.del(2, 3); + str.ins(3, 'opqrstuv'); + str.del(12, 1); + str.ins(0, 'ab1c3defghijk4444'); + str.del(2, 1); + str.del(3, 1); + str.del(11, 4); + if (str.view() !== 'abcdefghijklmnopqrstuvwxyz') throw new Error('Invalid text'); + }); +}; From 21c66ef4aa9763414057e5318310a537994bc612 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 12 Jun 2024 23:57:16 +0200 Subject: [PATCH 2/6] =?UTF-8?q?test(json-crdt-extensions):=20=F0=9F=92=8D?= =?UTF-8?q?=20add=20block=20refresh=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/__tests__/Blocks.refresh.spec.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts diff --git a/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts new file mode 100644 index 0000000000..61a6dd7d4a --- /dev/null +++ b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts @@ -0,0 +1,64 @@ +import {Kit, setupAlphabetChunkSplitKit, setupAlphabetKit, setupAlphabetWithDeletesKit, setupAlphabetWithTwoChunksKit} from '../../__tests__/setup'; + +const runStrTests = (setup: () => Kit) => { + test('updates block hash only where something was changed - leading block', () => { + const {editor, peritext} = setup(); + editor.cursor.setAt(10); + editor.saved.insMarker(['p'], 'p1'); + editor.cursor.setAt(22); + editor.saved.insMarker(['p'], 'p2'); + editor.cursor.setAt(editor.txt.str.length()); + peritext.refresh(); + const rootHash1 = peritext.blocks.root.hash; + const firstBlockHash1 = peritext.blocks.root.children[0].hash; + const secondBlockHash1 = peritext.blocks.root.children[1].hash; + editor.cursor.setAt(2); + editor.insert('___'); + peritext.refresh(); + const rootHash2 = peritext.blocks.root.hash; + const firstBlockHash2 = peritext.blocks.root.children[0].hash; + const secondBlockHash2 = peritext.blocks.root.children[1].hash; + expect(rootHash1).not.toBe(rootHash2); + expect(firstBlockHash1).not.toBe(firstBlockHash2); + expect(secondBlockHash1).toBe(secondBlockHash2); + }); + + test('updates block hash only where hash has changed - middle block', () => { + const {editor, peritext} = setup(); + editor.cursor.setAt(10); + editor.saved.insMarker(['p', 'p1']); + editor.cursor.setAt(22); + editor.saved.insMarker(['p'], 'p2'); + peritext.refresh(); + const rootHash1 = peritext.blocks.root.hash; + const firstBlockHash1 = peritext.blocks.root.children[0].hash; + const secondBlockHash1 = peritext.blocks.root.children[1].hash; + editor.cursor.setAt(13); + editor.insert('___'); + peritext.refresh(); + const rootHash2 = peritext.blocks.root.hash; + const firstBlockHash2 = peritext.blocks.root.children[0].hash; + const secondBlockHash2 = peritext.blocks.root.children[1].hash; + expect(rootHash1).not.toBe(rootHash2); + expect(firstBlockHash1).toBe(firstBlockHash2); + expect(secondBlockHash1).not.toBe(secondBlockHash2); + }); +}; + +describe('Blocks.refresh', () => { + describe('basic alphabet', () => { + runStrTests(setupAlphabetKit); + }); + + describe('alphabet with two chunks', () => { + runStrTests(setupAlphabetWithTwoChunksKit); + }); + + describe('alphabet with chunk split', () => { + runStrTests(setupAlphabetChunkSplitKit); + }); + + describe('alphabet with deletes', () => { + runStrTests(setupAlphabetWithDeletesKit); + }); +}); From 5e4cce256096f23419bb4b007729c3ec23fac149 Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 13 Jun 2024 00:00:30 +0200 Subject: [PATCH 3/6] =?UTF-8?q?style(json-crdt-extensions):=20=F0=9F=92=84?= =?UTF-8?q?=20run=20Prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/__tests__/Blocks.refresh.spec.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts index 61a6dd7d4a..e42cfdc5be 100644 --- a/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts +++ b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts @@ -1,6 +1,12 @@ -import {Kit, setupAlphabetChunkSplitKit, setupAlphabetKit, setupAlphabetWithDeletesKit, setupAlphabetWithTwoChunksKit} from '../../__tests__/setup'; +import { + Kit, + setupAlphabetChunkSplitKit, + setupAlphabetKit, + setupAlphabetWithDeletesKit, + setupAlphabetWithTwoChunksKit, +} from '../../__tests__/setup'; -const runStrTests = (setup: () => Kit) => { +const runTests = (setup: () => Kit) => { test('updates block hash only where something was changed - leading block', () => { const {editor, peritext} = setup(); editor.cursor.setAt(10); @@ -47,18 +53,18 @@ const runStrTests = (setup: () => Kit) => { describe('Blocks.refresh', () => { describe('basic alphabet', () => { - runStrTests(setupAlphabetKit); + runTests(setupAlphabetKit); }); describe('alphabet with two chunks', () => { - runStrTests(setupAlphabetWithTwoChunksKit); + runTests(setupAlphabetWithTwoChunksKit); }); describe('alphabet with chunk split', () => { - runStrTests(setupAlphabetChunkSplitKit); + runTests(setupAlphabetChunkSplitKit); }); describe('alphabet with deletes', () => { - runStrTests(setupAlphabetWithDeletesKit); + runTests(setupAlphabetWithDeletesKit); }); }); From 595c4972a924a4c474cd480bde273085af67eb4d Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 13 Jun 2024 00:06:51 +0200 Subject: [PATCH 4/6] =?UTF-8?q?test(json-crdt-extensions):=20=F0=9F=92=8D?= =?UTF-8?q?=20add=20more=20numbers=20test=20helpers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../peritext/__tests__/setup.ts | 42 +++++++++++++++++++ .../block/__tests__/Blocks.refresh.spec.ts | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/json-crdt-extensions/peritext/__tests__/setup.ts b/src/json-crdt-extensions/peritext/__tests__/setup.ts index 47438f02cc..b1a1a182ee 100644 --- a/src/json-crdt-extensions/peritext/__tests__/setup.ts +++ b/src/json-crdt-extensions/peritext/__tests__/setup.ts @@ -104,6 +104,48 @@ export const setupNumbersWithTombstonesKit = (sid?: number): Kit => { ); }; +/** + * Creates a Peritext instance with text "0123456789", two RGA chunks. + */ +export const setupNumbersWithTwoChunksKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, '56789'); + str.ins(0, '01234'); + if (str.view() !== '0123456789') throw new Error('Invalid text'); + }); +}; + +/** + * Creates a Peritext instance with text "0123456789", with RGA chunks split. + */ +export const setupNumbersWithRgaSplitKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, '012389'); + str.ins(4, '4567'); + if (str.view() !== '0123456789') throw new Error('Invalid text'); + }); +}; + +/** + * Creates a Peritext instance with text "0123456789", with multiple chunks and deletes. + */ +export const setupNumbersWithMultipleChunksAndDeletesKit = (): Kit => { + return setupKit('', (model) => { + const str = model.s.text.toExt().text(); + str.ins(0, '0'); + str.ins(0, '1'); + str.ins(0, '2xyz3'); + str.del(3, 3); + str.ins(4, '4589'); + str.ins(6, '67'); + str.ins(6, 'cool worlds'); + str.del(8, 11); + if (str.view() !== '0123456789') throw new Error('Invalid text'); + }); +}; + /** * Creates a Peritext instance with text "abcdefghijklmnopqrstuvwxyz", no edits. */ diff --git a/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts index e42cfdc5be..bc726ede8d 100644 --- a/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts +++ b/src/json-crdt-extensions/peritext/block/__tests__/Blocks.refresh.spec.ts @@ -51,7 +51,7 @@ const runTests = (setup: () => Kit) => { }); }; -describe('Blocks.refresh', () => { +describe('Blocks.refresh()', () => { describe('basic alphabet', () => { runTests(setupAlphabetKit); }); From ba8ef56dea0b36560767a19726480d0409c4e0ac Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 13 Jun 2024 00:13:55 +0200 Subject: [PATCH 5/6] =?UTF-8?q?test(json-crdt-extensions):=20=F0=9F=92=8D?= =?UTF-8?q?=20user=20numbers=20tests=20in=20more=20places?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../peritext/__tests__/setup.ts | 16 +++++++------- .../block/__tests__/Inline.key.spec.ts | 22 ++++++++++++++++++- .../overlay/__tests__/Overlay.markers.spec.ts | 21 +++++++++++++++++- .../overlay/__tests__/Overlay.pairs.spec.ts | 21 +++++++++++++++++- .../peritext/rga/__tests__/Range.text.spec.ts | 19 ++++++++++++++-- 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/src/json-crdt-extensions/peritext/__tests__/setup.ts b/src/json-crdt-extensions/peritext/__tests__/setup.ts index b1a1a182ee..38180b8fd0 100644 --- a/src/json-crdt-extensions/peritext/__tests__/setup.ts +++ b/src/json-crdt-extensions/peritext/__tests__/setup.ts @@ -58,7 +58,7 @@ export const setupNumbersKit = (): Kit => { return setupKit('', (model) => { const str = model.s.text.toExt().text(); str.ins(0, '0123456789'); - if (str.view() !== '0123456789') throw new Error('Invalid text'); + if (str.view() !== '0123456789') throw new Error('Invalid text: ' + str.view()); }); }; @@ -98,7 +98,7 @@ export const setupNumbersWithTombstonesKit = (sid?: number): Kit => { str.ins(2, 'x234'); str.del(2, 1); str.del(10, 3); - if (str.view() !== '0123456789') throw new Error('Invalid text'); + if (str.view() !== '0123456789') throw new Error('Invalid text: ' + str.view()); }, sid, ); @@ -112,7 +112,7 @@ export const setupNumbersWithTwoChunksKit = (): Kit => { const str = model.s.text.toExt().text(); str.ins(0, '56789'); str.ins(0, '01234'); - if (str.view() !== '0123456789') throw new Error('Invalid text'); + if (str.view() !== '0123456789') throw new Error('Invalid text: ' + str.view()); }); }; @@ -124,7 +124,7 @@ export const setupNumbersWithRgaSplitKit = (): Kit => { const str = model.s.text.toExt().text(); str.ins(0, '012389'); str.ins(4, '4567'); - if (str.view() !== '0123456789') throw new Error('Invalid text'); + if (str.view() !== '0123456789') throw new Error('Invalid text: ' + str.view()); }); }; @@ -135,14 +135,14 @@ export const setupNumbersWithMultipleChunksAndDeletesKit = (): Kit => { return setupKit('', (model) => { const str = model.s.text.toExt().text(); str.ins(0, '0'); - str.ins(0, '1'); - str.ins(0, '2xyz3'); + str.ins(1, '1'); + str.ins(2, '2xyz3'); str.del(3, 3); str.ins(4, '4589'); str.ins(6, '67'); - str.ins(6, 'cool worlds'); + str.ins(8, 'cool worlds'); str.del(8, 11); - if (str.view() !== '0123456789') throw new Error('Invalid text'); + if (str.view() !== '0123456789') throw new Error('Invalid text: ' + str.view()); }); }; diff --git a/src/json-crdt-extensions/peritext/block/__tests__/Inline.key.spec.ts b/src/json-crdt-extensions/peritext/block/__tests__/Inline.key.spec.ts index d4b6dcf7ca..e67b8f24c7 100644 --- a/src/json-crdt-extensions/peritext/block/__tests__/Inline.key.spec.ts +++ b/src/json-crdt-extensions/peritext/block/__tests__/Inline.key.spec.ts @@ -1,7 +1,15 @@ import {Timestamp} from '../../../../json-crdt-patch'; import {updateId} from '../../../../json-crdt/hash'; import {updateNum} from '../../../../json-hash'; -import {Kit, setupKit, setupNumbersKit, setupNumbersWithTombstonesKit} from '../../__tests__/setup'; +import { + Kit, + setupKit, + setupNumbersKit, + setupNumbersWithMultipleChunksAndDeletesKit, + setupNumbersWithRgaSplitKit, + setupNumbersWithTombstonesKit, + setupNumbersWithTwoChunksKit, +} from '../../__tests__/setup'; import {Point} from '../../rga/Point'; import {Inline} from '../Inline'; @@ -92,6 +100,18 @@ describe('Inline', () => { runKeyTests(setupNumbersWithTombstonesKit); }); + describe('numbers "0123456789", two RGA chunks', () => { + runKeyTests(setupNumbersWithTwoChunksKit); + }); + + describe('numbers "0123456789", with RGA split', () => { + runKeyTests(setupNumbersWithRgaSplitKit); + }); + + describe('numbers "0123456789", with multiple deletes', () => { + runKeyTests(setupNumbersWithMultipleChunksAndDeletesKit); + }); + describe('numbers "0123456789", with default schema and tombstones and constant sid', () => { runKeyTests(() => setupNumbersWithTombstonesKit(12313123)); }); diff --git a/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.markers.spec.ts b/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.markers.spec.ts index b454f60ff5..3b6abc3890 100644 --- a/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.markers.spec.ts +++ b/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.markers.spec.ts @@ -1,4 +1,11 @@ -import {Kit, setupNumbersKit, setupNumbersWithTombstonesKit} from '../../__tests__/setup'; +import { + Kit, + setupNumbersKit, + setupNumbersWithMultipleChunksAndDeletesKit, + setupNumbersWithRgaSplitKit, + setupNumbersWithTombstonesKit, + setupNumbersWithTwoChunksKit, +} from '../../__tests__/setup'; import {MarkerOverlayPoint} from '../MarkerOverlayPoint'; const runMarkersTests = (setup: () => Kit) => { @@ -109,3 +116,15 @@ describe('numbers "0123456789", no edits', () => { describe('numbers "0123456789", with default schema and tombstones', () => { runMarkersTests(setupNumbersWithTombstonesKit); }); + +describe('numbers "0123456789", two RGA chunks', () => { + runMarkersTests(setupNumbersWithTwoChunksKit); +}); + +describe('numbers "0123456789", with RGA split', () => { + runMarkersTests(setupNumbersWithRgaSplitKit); +}); + +describe('numbers "0123456789", with multiple deletes', () => { + runMarkersTests(setupNumbersWithMultipleChunksAndDeletesKit); +}); diff --git a/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.pairs.spec.ts b/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.pairs.spec.ts index 5d5addca61..b5abb42d62 100644 --- a/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.pairs.spec.ts +++ b/src/json-crdt-extensions/peritext/overlay/__tests__/Overlay.pairs.spec.ts @@ -1,5 +1,12 @@ import {next} from 'sonic-forest/lib/util'; -import {Kit, setupNumbersKit, setupNumbersWithTombstonesKit} from '../../__tests__/setup'; +import { + Kit, + setupNumbersKit, + setupNumbersWithMultipleChunksAndDeletesKit, + setupNumbersWithRgaSplitKit, + setupNumbersWithTombstonesKit, + setupNumbersWithTwoChunksKit, +} from '../../__tests__/setup'; import {Anchor} from '../../rga/constants'; import {MarkerOverlayPoint} from '../MarkerOverlayPoint'; import {OverlayPoint} from '../OverlayPoint'; @@ -162,3 +169,15 @@ describe('numbers "0123456789", no edits', () => { describe('numbers "0123456789", with default schema and tombstones', () => { runPairsTests(setupNumbersWithTombstonesKit); }); + +describe('numbers "0123456789", two RGA chunks', () => { + runPairsTests(setupNumbersWithTwoChunksKit); +}); + +describe('numbers "0123456789", with RGA split', () => { + runPairsTests(setupNumbersWithRgaSplitKit); +}); + +describe('numbers "0123456789", with multiple deletes', () => { + runPairsTests(setupNumbersWithMultipleChunksAndDeletesKit); +}); diff --git a/src/json-crdt-extensions/peritext/rga/__tests__/Range.text.spec.ts b/src/json-crdt-extensions/peritext/rga/__tests__/Range.text.spec.ts index 5373696a53..484f808b02 100644 --- a/src/json-crdt-extensions/peritext/rga/__tests__/Range.text.spec.ts +++ b/src/json-crdt-extensions/peritext/rga/__tests__/Range.text.spec.ts @@ -3,7 +3,10 @@ import { setupHelloWorldKit, setupHelloWorldWithFewEditsKit, setupNumbersKit, + setupNumbersWithMultipleChunksAndDeletesKit, + setupNumbersWithRgaSplitKit, setupNumbersWithTombstonesKit, + setupNumbersWithTwoChunksKit, } from '../../__tests__/setup'; const run = (setup: () => Kit) => { @@ -29,10 +32,22 @@ describe('some edits "hello world"', () => { run(setupHelloWorldWithFewEditsKit); }); -describe('no edits "number"', () => { +describe('numbers "0123456789", no edits', () => { run(setupNumbersKit); }); -describe('heavy edits "number"', () => { +describe('numbers "0123456789", with default schema and tombstones', () => { run(setupNumbersWithTombstonesKit); }); + +describe('numbers "0123456789", two RGA chunks', () => { + run(setupNumbersWithTwoChunksKit); +}); + +describe('numbers "0123456789", with RGA split', () => { + run(setupNumbersWithRgaSplitKit); +}); + +describe('numbers "0123456789", with multiple deletes', () => { + run(setupNumbersWithMultipleChunksAndDeletesKit); +}); From 6e2ce3d9c6ba228bc63a6c085015c3a5168765ec Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 13 Jun 2024 00:29:25 +0200 Subject: [PATCH 6/6] =?UTF-8?q?test(json-crdt-extensions):=20=F0=9F=92=8D?= =?UTF-8?q?=20add=20blocks=20inline=20element=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/Peritext.render-inline.spec.ts | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 src/json-crdt-extensions/peritext/__tests__/Peritext.render-inline.spec.ts diff --git a/src/json-crdt-extensions/peritext/__tests__/Peritext.render-inline.spec.ts b/src/json-crdt-extensions/peritext/__tests__/Peritext.render-inline.spec.ts new file mode 100644 index 0000000000..4d03a06644 --- /dev/null +++ b/src/json-crdt-extensions/peritext/__tests__/Peritext.render-inline.spec.ts @@ -0,0 +1,280 @@ +import {render} from './render'; +import { + Kit, + setupNumbersKit, + setupNumbersWithMultipleChunksAndDeletesKit, + setupNumbersWithRgaSplitKit, + setupNumbersWithTombstonesKit, + setupNumbersWithTwoChunksKit, +} from './setup'; + +const runTests = (_setup: () => Kit) => { + const setup = () => { + const kit = _setup(); + const view = () => { + kit.peritext.editor.delCursors(); + kit.peritext.refresh(); + return render(kit.peritext.blocks.root); + }; + return {...kit, view}; + }; + + test('renders plain text', () => { + const {view} = setup(); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0123456789" { } +" +`); + }); + + test('can annotate beginning of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(0, 3); + editor.saved.insOverwrite('BOLD'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "" { } + "012" { BOLD = [ 1, 3 ] } + "3456789" { } +" +`); + }); + + test('can annotate middle of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(3, 3); + editor.saved.insOverwrite('BOLD'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "012" { } + "345" { BOLD = [ 1, 3 ] } + "6789" { } +" +`); + }); + + test('can annotate end of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(7, 3); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0123456" { } + "789" { ITALIC = [ 1, 3 ] } + "" { } +" +`); + }); + + test('can annotate two regions', () => { + const {editor, view} = setup(); + editor.cursor.setAt(1, 2); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(5, 3); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0" { } + "12" { BOLD = [ 1, 3 ] } + "34" { } + "567" { ITALIC = [ 1, 3 ] } + "89" { } +" +`); + }); + + test('can annotate two adjacent regions', () => { + const {editor, view} = setup(); + editor.cursor.setAt(0, 2); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(2, 3); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "" { } + "01" { BOLD = [ 1, 3 ] } + "" { } + "234" { ITALIC = [ 1, 3 ] } + "56789" { } +" +`); + }); + + test('can annotate two adjacent regions at the end of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(5, 2); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(7, 3); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "01234" { } + "56" { BOLD = [ 1, 3 ] } + "" { } + "789" { ITALIC = [ 1, 3 ] } + "" { } +" +`); + }); + + test('can annotate overlapping regions at the beginning of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(0, 2); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(1, 2); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "" { } + "0" { BOLD = [ 1, 1 ] } + "1" { BOLD = [ 1, 2 ], ITALIC = [ 1, 1 ] } + "2" { ITALIC = [ 1, 2 ] } + "3456789" { } +" +`); + }); + + test('can annotate overlapping regions in the middle of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(4, 2); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(5, 2); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0123" { } + "4" { BOLD = [ 1, 1 ] } + "5" { BOLD = [ 1, 2 ], ITALIC = [ 1, 1 ] } + "6" { ITALIC = [ 1, 2 ] } + "789" { } +" +`); + }); + + test('can annotate a contained region at the beginning of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(0, 5); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(1, 2); + editor.saved.insOverwrite('ITALIC'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "" { } + "0" { BOLD = [ 1, 1 ] } + "12" { BOLD = [ 1, 0 ], ITALIC = [ 1, 3 ] } + "34" { BOLD = [ 1, 2 ] } + "56789" { } +" +`); + }); + + test('can annotate twice contained region in the middle of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(4, 5); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(5, 3); + editor.saved.insOverwrite('ITALIC'); + editor.cursor.setAt(6, 1); + editor.saved.insOverwrite('UNDERLINE'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0123" { } + "4" { BOLD = [ 1, 1 ] } + "5" { BOLD = [ 1, 0 ], ITALIC = [ 1, 1 ] } + "6" { BOLD = [ 1, 0 ], ITALIC = [ 1, 0 ], UNDERLINE = [ 1, 3 ] } + "7" { BOLD = [ 1, 0 ], ITALIC = [ 1, 2 ] } + "8" { BOLD = [ 1, 2 ] } + "9" { } +" +`); + }); + + test('can annotate twice contained region at the end of text', () => { + const {editor, view} = setup(); + editor.cursor.setAt(5, 5); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(6, 3); + editor.saved.insOverwrite('ITALIC'); + editor.cursor.setAt(7, 1); + editor.saved.insOverwrite('UNDERLINE'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "01234" { } + "5" { BOLD = [ 1, 1 ] } + "6" { BOLD = [ 1, 0 ], ITALIC = [ 1, 1 ] } + "7" { BOLD = [ 1, 0 ], ITALIC = [ 1, 0 ], UNDERLINE = [ 1, 3 ] } + "8" { BOLD = [ 1, 0 ], ITALIC = [ 1, 2 ] } + "9" { BOLD = [ 1, 2 ] } + "" { } +" +`); + }); + + test('can annotate three intermingled regions', () => { + const {editor, view} = setup(); + editor.cursor.setAt(2, 6); + editor.saved.insOverwrite('BOLD'); + editor.cursor.setAt(1, 5); + editor.saved.insOverwrite('ITALIC'); + editor.cursor.setAt(4, 5); + editor.saved.insOverwrite('UNDERLINE'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "0" { } + "1" { ITALIC = [ 1, 1 ] } + "23" { BOLD = [ 1, 1 ], ITALIC = [ 1, 0 ] } + "45" { BOLD = [ 1, 0 ], ITALIC = [ 1, 2 ], UNDERLINE = [ 1, 1 ] } + "67" { BOLD = [ 1, 2 ], UNDERLINE = [ 1, 0 ] } + "8" { UNDERLINE = [ 1, 2 ] } + "9" { } +" +`); + }); + + test('can insert zero length slice', () => { + const {editor, view} = setup(); + editor.cursor.setAt(2, 0); + editor.saved.insOverwrite('CURSOR'); + expect(view()).toMatchInlineSnapshot(` +"<> + <0> + "01" { } + "23456789" { CURSOR = [ 1, 4 ] } +" +`); + }); +}; + +describe('numbers "0123456789", no edits', () => { + runTests(setupNumbersKit); +}); + +describe('numbers "0123456789", with default schema and tombstones', () => { + runTests(setupNumbersWithTombstonesKit); +}); + +describe('numbers "0123456789", two RGA chunks', () => { + runTests(setupNumbersWithTwoChunksKit); +}); + +describe('numbers "0123456789", with RGA split', () => { + runTests(setupNumbersWithRgaSplitKit); +}); + +describe('numbers "0123456789", with multiple deletes', () => { + runTests(setupNumbersWithMultipleChunksAndDeletesKit); +});