Path: blob/main/extensions/copilot/src/platform/notebook/test/node/alternativeNotebookTextDocument.spec.tsx
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { afterAll, beforeEach, describe, expect, test } from 'vitest';6import type { NotebookDocument, NotebookDocumentContentChange, TextDocumentChangeEvent } from 'vscode';7import { ExtHostNotebookDocumentData } from '../../../../util/common/test/shims/notebookDocument';8import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';9import { URI } from '../../../../util/vs/base/common/uri';10import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';11import { NotebookCellData, NotebookCellKind, NotebookData, NotebookRange, Range } from '../../../../vscodeTypes';12import { createAlternativeNotebookDocument, createAlternativeNotebookDocumentSnapshot, IAlternativeNotebookDocument, IAlternativeNotebookDocumentSnapshot, toAltNotebookCellChangeEdit, toAltNotebookChangeEdit } from '../../common/alternativeNotebookTextDocument';1314describe('Alternative Notebook (text) Content', () => {15const disposables = new DisposableStore();1617afterAll(() => {18disposables.clear();19});2021function createNotebook(cells: NotebookCellData[], withMarkdownCells: boolean = false) {22const notebook = ExtHostNotebookDocumentData.fromNotebookData(URI.file('notebook.ipynb'), new NotebookData(cells), 'jupyter-notebook');23const altDocSnapshot = createAlternativeNotebookDocumentSnapshot(notebook.document, !withMarkdownCells);24const altDoc = createAlternativeNotebookDocument(notebook.document, !withMarkdownCells);2526expect(altDocSnapshot.getText()).toBe(altDoc.getText());27return { notebookData: notebook, notebook: notebook.document, altDocSnapshot, altDoc };28}29[true, false].forEach(withMarkdownCells => {30describe(`Alt Content ${withMarkdownCells ? 'with' : 'without'} Markdown Cells`, () => {31test(`Generate Alt Content`, async () => {32const cells = [33new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")', 'python'),34];35const { altDocSnapshot } = createNotebook(cells, withMarkdownCells);36expect(altDocSnapshot.getText()).toMatchSnapshot();37});38test(`No Content`, async () => {39const { altDocSnapshot } = createNotebook([], withMarkdownCells);40expect(altDocSnapshot.getText()).toMatchSnapshot();41});42test(`No Content without code cells`, async () => {43const cells = [44new NotebookCellData(NotebookCellKind.Markup, '# This is a sample notebook', 'markdown'),45];46const { altDocSnapshot } = createNotebook(cells, withMarkdownCells);47expect(altDocSnapshot.getText()).toMatchSnapshot();48});49test(`With Markdown Cells`, async () => {50const cells = [51new NotebookCellData(NotebookCellKind.Markup, '# This is a sample notebook', 'markdown'),52new NotebookCellData(NotebookCellKind.Markup, '## Header', 'markdown'),53new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")', 'python'),54new NotebookCellData(NotebookCellKind.Markup, 'Comments', 'markdown'),55new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),56];57const { altDocSnapshot } = createNotebook(cells, withMarkdownCells);58expect(altDocSnapshot.getText()).toMatchSnapshot();59});60test(`EOLs`, async () => {61const cells = [62new NotebookCellData(NotebookCellKind.Code, 'import sys\nimport os', 'python'),63new NotebookCellData(NotebookCellKind.Code, 'import pandas\r\nimport requests', 'python'),64new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\r\nprint("Foo Bar")\r\nprint("Bar Baz")', 'python'),65new NotebookCellData(NotebookCellKind.Code, 'print(sys.executable)\nprint(sys.version)', 'python'),66];67const { altDocSnapshot } = createNotebook(cells, withMarkdownCells);6869expect(altDocSnapshot.getText()).toMatchSnapshot();7071expect(altDocSnapshot.getText()).not.toContain('\r\n'); // Ensure no CRLF, only LF72expect(altDocSnapshot.getText()).toContain('\n'); // Ensure no CRLF, only LF73});74});75});76describe('Position Mapping', () => {77test(`All cells have same EOL`, async () => {78const cells = [79new NotebookCellData(NotebookCellKind.Code, 'import sys\nimport os', 'python'),80new NotebookCellData(NotebookCellKind.Code, 'import pandas\nimport requests', 'python'),81new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")', 'python'),82new NotebookCellData(NotebookCellKind.Code, 'print(sys.executable)\nprint(sys.version)', 'python'),83];84const { notebook, altDocSnapshot } = createNotebook(cells);8586expect(altDocSnapshot.getText(new OffsetRange(53, 53))).toBe('');87expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 53))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 0)]]);88expect(altDocSnapshot.fromAltRange(new Range(1, 0, 1, 0))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 0)]]);89expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(53, 53)]);9091expect(altDocSnapshot.getText(new OffsetRange(53, 59))).toBe('import');92expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 59))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);93expect(altDocSnapshot.fromAltRange(new Range(1, 0, 1, 6))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);94expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(53, 59)]);9596expect(altDocSnapshot.getText(new OffsetRange(53, 64))).toBe('import sys\n');97expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 64))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 0)]]);98expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 0))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 0)]]);99expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 1, 0)])).toEqual([new OffsetRange(53, 64)]);100101expect(altDocSnapshot.getText(new OffsetRange(53, 73))).toBe('import sys\nimport os');102expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 73))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);103expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 9))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);104expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(53, 73)]);105106expect(altDocSnapshot.getText(new OffsetRange(53, 74))).toBe('import sys\nimport os\n');107expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 74))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);108expect(altDocSnapshot.fromAltRange(new Range(1, 0, 3, 0))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);109expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(53, 73)]);110111// Translating alt text range across cells will only return contents of one cell.112expect(altDocSnapshot.getText(new OffsetRange(53, 140))).toBe('import sys\nimport os\n#%% vscode.cell [id=#VSC-bdb3864a] [language=python]\nimport pandas');113expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 140))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)], [notebook.cellAt(1), new Range(0, 0, 0, 13)]]);114expect(altDocSnapshot.fromAltRange(new Range(1, 0, 4, 13))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)], [notebook.cellAt(1), new Range(0, 0, 0, 13)]]);115116expect(altDocSnapshot.getText(new OffsetRange(71, 73))).toBe('os');117expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(71, 73))).toEqual([[notebook.cellAt(0), new Range(1, 7, 1, 9)]]);118expect(altDocSnapshot.fromAltRange(new Range(2, 7, 2, 9))).toEqual([[notebook.cellAt(0), new Range(1, 7, 1, 9)]]);119expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(1, 7, 1, 9)])).toEqual([new OffsetRange(71, 73)]);120121expect(altDocSnapshot.getText(new OffsetRange(127, 127))).toBe('');122expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(127, 127))).toEqual([[notebook.cellAt(1), new Range(0, 0, 0, 0)]]);123expect(altDocSnapshot.fromAltRange(new Range(4, 0, 4, 0))).toEqual([[notebook.cellAt(1), new Range(0, 0, 0, 0)]]);124expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(1), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(127, 127)]);125126expect(altDocSnapshot.getText(new OffsetRange(127, 133))).toBe('import');127expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(127, 133))).toEqual([[notebook.cellAt(1), new Range(0, 0, 0, 6)]]);128expect(altDocSnapshot.fromAltRange(new Range(4, 0, 4, 6))).toEqual([[notebook.cellAt(1), new Range(0, 0, 0, 6)]]);129expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(1), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(127, 133)]);130131expect(altDocSnapshot.getText(new OffsetRange(134, 258))).toBe('pandas\nimport requests\n#%% vscode.cell [id=#VSC-8862d4f3] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar');132expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(134, 258))).toEqual([133[notebook.cellAt(1), new Range(0, 7, 1, 15)],134[notebook.cellAt(2), new Range(0, 0, 2, 10)],135]);136expect(altDocSnapshot.fromAltRange(new Range(4, 7, 9, 10))).toEqual([137[notebook.cellAt(1), new Range(0, 7, 1, 15)],138[notebook.cellAt(2), new Range(0, 0, 2, 10)],139]);140141expect(altDocSnapshot.getText(new OffsetRange(134, 156))).toBe('pandas\nimport requests');142expect(notebook.cellAt(1).document.getText(new Range(0, 7, 1, 15))).toBe('pandas\nimport requests');143expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(1), [new Range(0, 7, 1, 15)])).toEqual([new OffsetRange(134, 156)]);144expect(altDocSnapshot.getText(new OffsetRange(210, 258))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');145expect(notebook.cellAt(2).document.getText(new Range(0, 0, 2, 10))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');146expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 2, 10)])).toEqual([new OffsetRange(210, 258)]);147148expect(altDocSnapshot.getText(new OffsetRange(210, 265))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n');149expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(210, 265))).toEqual([[notebook.cellAt(2), new Range(0, 0, 2, 16)]]);150expect(altDocSnapshot.fromAltRange(new Range(7, 0, 10, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 2, 16)]]);151expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 2, 16)])).toEqual([new OffsetRange(210, 264)]);152153expect(altDocSnapshot.getText(new OffsetRange(318, 358))).toBe('print(sys.executable)\nprint(sys.version)');154expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(318, 358))).toEqual([[notebook.cellAt(3), new Range(0, 0, 1, 18)]]);155expect(altDocSnapshot.fromAltRange(new Range(11, 0, 12, 18))).toEqual([[notebook.cellAt(3), new Range(0, 0, 1, 18)]]);156expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(3), [new Range(0, 0, 1, 18)])).toEqual([new OffsetRange(318, 358)]);157158expect(altDocSnapshot.getText(new OffsetRange(60, 349))).toBe('sys\nimport os\n#%% vscode.cell [id=#VSC-bdb3864a] [language=python]\nimport pandas\nimport requests\n#%% vscode.cell [id=#VSC-8862d4f3] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n#%% vscode.cell [id=#VSC-e07487cb] [language=python]\nprint(sys.executable)\nprint(sys');159expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(60, 349))).toEqual([160[notebook.cellAt(0), new Range(0, 7, 1, 9)],161[notebook.cellAt(1), new Range(0, 0, 1, 15)],162[notebook.cellAt(2), new Range(0, 0, 2, 16)],163[notebook.cellAt(3), new Range(0, 0, 1, 9)]164]);165expect(altDocSnapshot.fromAltRange(new Range(1, 7, 12, 9))).toEqual([166[notebook.cellAt(0), new Range(0, 7, 1, 9)],167[notebook.cellAt(1), new Range(0, 0, 1, 15)],168[notebook.cellAt(2), new Range(0, 0, 2, 16)],169[notebook.cellAt(3), new Range(0, 0, 1, 9)]170]);171});172test(`All cells have same EOL (with MD cells excluded)`, async () => {173const cells = [174new NotebookCellData(NotebookCellKind.Markup, '# This is a sample notebook', 'markdown'),175new NotebookCellData(NotebookCellKind.Markup, '## Header', 'markdown'),176new NotebookCellData(NotebookCellKind.Code, 'import sys\nimport os', 'python'),177new NotebookCellData(NotebookCellKind.Markup, 'Comments', 'markdown'),178new NotebookCellData(NotebookCellKind.Code, 'import pandas\nimport requests', 'python'),179new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")', 'python'),180new NotebookCellData(NotebookCellKind.Code, 'print(sys.executable)\nprint(sys.version)', 'python'),181];182const { notebook, altDocSnapshot } = createNotebook(cells);183184expect(altDocSnapshot.getText(new OffsetRange(53, 53))).toBe('');185expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 53))).toEqual([[notebook.cellAt(2), new Range(0, 0, 0, 0)]]);186expect(altDocSnapshot.fromAltRange(new Range(1, 0, 1, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 0, 0)]]);187expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(53, 53)]);188189expect(altDocSnapshot.getText(new OffsetRange(53, 59))).toBe('import');190expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 59))).toEqual([[notebook.cellAt(2), new Range(0, 0, 0, 6)]]);191expect(altDocSnapshot.fromAltRange(new Range(1, 0, 1, 6))).toEqual([[notebook.cellAt(2), new Range(0, 0, 0, 6)]]);192expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(53, 59)]);193194expect(altDocSnapshot.getText(new OffsetRange(53, 64))).toBe('import sys\n');195expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 64))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 0)]]);196expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 0)]]);197expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 0)])).toEqual([new OffsetRange(53, 64)]);198199expect(altDocSnapshot.getText(new OffsetRange(53, 73))).toBe('import sys\nimport os');200expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 73))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);201expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 9))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);202expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(53, 73)]);203204expect(altDocSnapshot.getText(new OffsetRange(53, 74))).toBe('import sys\nimport os\n');205expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 74))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);206expect(altDocSnapshot.fromAltRange(new Range(1, 0, 3, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);207expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(53, 73)]);208209// Translating alt text range across cells will only return contents of one cell.210expect(altDocSnapshot.getText(new OffsetRange(53, 140))).toBe('import sys\nimport os\n#%% vscode.cell [id=#VSC-53ab90bb] [language=python]\nimport pandas');211expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 140))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)], [notebook.cellAt(4), new Range(0, 0, 0, 13)]]);212expect(altDocSnapshot.fromAltRange(new Range(1, 0, 4, 13))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)], [notebook.cellAt(4), new Range(0, 0, 0, 13)]]);213214expect(altDocSnapshot.getText(new OffsetRange(71, 73))).toBe('os');215expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(71, 73))).toEqual([[notebook.cellAt(2), new Range(1, 7, 1, 9)]]);216expect(altDocSnapshot.fromAltRange(new Range(2, 7, 2, 9))).toEqual([[notebook.cellAt(2), new Range(1, 7, 1, 9)]]);217expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(1, 7, 1, 9)])).toEqual([new OffsetRange(71, 73)]);218219expect(altDocSnapshot.getText(new OffsetRange(127, 127))).toBe('');220expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(127, 127))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 0)]]);221expect(altDocSnapshot.fromAltRange(new Range(4, 0, 4, 0))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 0)]]);222expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(127, 127)]);223224expect(altDocSnapshot.getText(new OffsetRange(127, 133))).toBe('import');225expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(127, 133))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 6)]]);226expect(altDocSnapshot.fromAltRange(new Range(4, 0, 4, 6))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 6)]]);227expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(127, 133)]);228229expect(altDocSnapshot.getText(new OffsetRange(134, 258))).toBe('pandas\nimport requests\n#%% vscode.cell [id=#VSC-749a8f95] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar');230expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(134, 258))).toEqual([231[notebook.cellAt(4), new Range(0, 7, 1, 15)],232[notebook.cellAt(5), new Range(0, 0, 2, 10)],233]);234expect(altDocSnapshot.fromAltRange(new Range(4, 7, 9, 10))).toEqual([235[notebook.cellAt(4), new Range(0, 7, 1, 15)],236[notebook.cellAt(5), new Range(0, 0, 2, 10)],237]);238239expect(altDocSnapshot.getText(new OffsetRange(134, 156))).toBe('pandas\nimport requests');240expect(notebook.cellAt(4).document.getText(new Range(0, 7, 1, 15))).toBe('pandas\nimport requests');241expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 7, 1, 15)])).toEqual([new OffsetRange(134, 156)]);242expect(altDocSnapshot.getText(new OffsetRange(210, 258))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');243expect(notebook.cellAt(5).document.getText(new Range(0, 0, 2, 10))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');244expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(5), [new Range(0, 0, 2, 10)])).toEqual([new OffsetRange(210, 258)]);245246expect(altDocSnapshot.getText(new OffsetRange(210, 265))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n');247expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(210, 265))).toEqual([[notebook.cellAt(5), new Range(0, 0, 2, 16)]]);248expect(altDocSnapshot.fromAltRange(new Range(7, 0, 10, 0))).toEqual([[notebook.cellAt(5), new Range(0, 0, 2, 16)]]);249expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(5), [new Range(0, 0, 2, 16)])).toEqual([new OffsetRange(210, 264)]);250251expect(altDocSnapshot.getText(new OffsetRange(318, 358))).toBe('print(sys.executable)\nprint(sys.version)');252expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(318, 358))).toEqual([[notebook.cellAt(6), new Range(0, 0, 1, 18)]]);253expect(altDocSnapshot.fromAltRange(new Range(11, 0, 12, 18))).toEqual([[notebook.cellAt(6), new Range(0, 0, 1, 18)]]);254expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(6), [new Range(0, 0, 1, 18)])).toEqual([new OffsetRange(318, 358)]);255256expect(altDocSnapshot.getText(new OffsetRange(60, 349))).toBe('sys\nimport os\n#%% vscode.cell [id=#VSC-53ab90bb] [language=python]\nimport pandas\nimport requests\n#%% vscode.cell [id=#VSC-749a8f95] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n#%% vscode.cell [id=#VSC-d2139a72] [language=python]\nprint(sys.executable)\nprint(sys');257expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(60, 349))).toEqual([258[notebook.cellAt(2), new Range(0, 7, 1, 9)],259[notebook.cellAt(4), new Range(0, 0, 1, 15)],260[notebook.cellAt(5), new Range(0, 0, 2, 16)],261[notebook.cellAt(6), new Range(0, 0, 1, 9)]262]);263expect(altDocSnapshot.fromAltRange(new Range(1, 7, 12, 9))).toEqual([264[notebook.cellAt(2), new Range(0, 7, 1, 9)],265[notebook.cellAt(4), new Range(0, 0, 1, 15)],266[notebook.cellAt(5), new Range(0, 0, 2, 16)],267[notebook.cellAt(6), new Range(0, 0, 1, 9)]268]);269});270test(`All cells have same EOL (with MD cells included)`, async () => {271const cells = [272new NotebookCellData(NotebookCellKind.Markup, '# This is a sample notebook', 'markdown'),273new NotebookCellData(NotebookCellKind.Markup, '## Header\n### Sub Heading', 'markdown'),274new NotebookCellData(NotebookCellKind.Code, 'import sys\nimport os', 'python'),275new NotebookCellData(NotebookCellKind.Markup, 'Comments', 'markdown'),276new NotebookCellData(NotebookCellKind.Code, 'import pandas\nimport requests', 'python'),277new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")', 'python'),278new NotebookCellData(NotebookCellKind.Code, 'print(sys.executable)\nprint(sys.version)', 'python'),279];280const { notebook, altDocSnapshot } = createNotebook(cells, true);281282expect(altDocSnapshot.getText(new OffsetRange(59, 59))).toBe('');283expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(59, 59))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 0)]]);284expect(altDocSnapshot.fromAltRange(new Range(2, 0, 2, 0))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 0)]]);285expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(59, 59)]);286287expect(altDocSnapshot.getText(new OffsetRange(59, 65))).toBe('# This');288expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(59, 65))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);289expect(altDocSnapshot.fromAltRange(new Range(2, 0, 2, 6))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);290expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(59, 65)]);291292expect(altDocSnapshot.getText(new OffsetRange(233, 244))).toBe('import sys\n');293expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(233, 244))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 0)]]);294expect(altDocSnapshot.fromAltRange(new Range(10, 0, 11, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 0)]]);295expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 0)])).toEqual([new OffsetRange(233, 244)]);296297expect(altDocSnapshot.getText(new OffsetRange(233, 253))).toBe('import sys\nimport os');298expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(233, 253))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);299expect(altDocSnapshot.fromAltRange(new Range(10, 0, 11, 9))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);300expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(233, 253)]);301302expect(altDocSnapshot.getText(new OffsetRange(233, 254))).toBe('import sys\nimport os\n');303expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(233, 254))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);304expect(altDocSnapshot.fromAltRange(new Range(10, 0, 12, 0))).toEqual([[notebook.cellAt(2), new Range(0, 0, 1, 9)]]);305expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(233, 253)]);306307// Translating alt text range across cells will only return contents of one cell.308expect(altDocSnapshot.getText(new OffsetRange(53, 254))).toBe(']\n"""\n# This is a sample notebook\n"""\n#%% vscode.cell [id=#VSC-bdb3864a] [language=markdown]\n"""\n## Header\n### Sub Heading\n"""\n#%% vscode.cell [id=#VSC-8862d4f3] [language=python]\nimport sys\nimport os\n');309expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 254))).toEqual([310[notebook.cellAt(0), new Range(0, 0, 0, 27)],311[notebook.cellAt(1), new Range(0, 0, 1, 15)],312[notebook.cellAt(2), new Range(0, 0, 1, 9)]313]);314expect(altDocSnapshot.fromAltRange(new Range(1, 0, 11, 13))).toEqual([315[notebook.cellAt(0), new Range(0, 0, 0, 27)],316[notebook.cellAt(1), new Range(0, 0, 1, 15)],317[notebook.cellAt(2), new Range(0, 0, 1, 9)]318]);319320expect(altDocSnapshot.getText(new OffsetRange(251, 253))).toBe('os');321expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(251, 253))).toEqual([[notebook.cellAt(2), new Range(1, 7, 1, 9)]]);322expect(altDocSnapshot.fromAltRange(new Range(11, 7, 11, 9))).toEqual([[notebook.cellAt(2), new Range(1, 7, 1, 9)]]);323expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(1, 7, 1, 9)])).toEqual([new OffsetRange(251, 253)]);324325expect(altDocSnapshot.getText(new OffsetRange(379, 379))).toBe('');326expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(379, 379))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 0)]]);327expect(altDocSnapshot.fromAltRange(new Range(17, 0, 17, 0))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 0)]]);328expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 0, 0, 0)])).toEqual([new OffsetRange(379, 379)]);329330expect(altDocSnapshot.getText(new OffsetRange(379, 385))).toBe('import');331expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(379, 385))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 6)]]);332expect(altDocSnapshot.fromAltRange(new Range(17, 0, 17, 6))).toEqual([[notebook.cellAt(4), new Range(0, 0, 0, 6)]]);333expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(379, 385)]);334335expect(altDocSnapshot.getText(new OffsetRange(386, 510))).toBe('pandas\nimport requests\n#%% vscode.cell [id=#VSC-749a8f95] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar');336expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(386, 510))).toEqual([337[notebook.cellAt(4), new Range(0, 7, 1, 15)],338[notebook.cellAt(5), new Range(0, 0, 2, 10)],339]);340expect(altDocSnapshot.fromAltRange(new Range(17, 7, 22, 10))).toEqual([341[notebook.cellAt(4), new Range(0, 7, 1, 15)],342[notebook.cellAt(5), new Range(0, 0, 2, 10)],343]);344345expect(altDocSnapshot.getText(new OffsetRange(386, 408))).toBe('pandas\nimport requests');346expect(notebook.cellAt(4).document.getText(new Range(0, 7, 1, 15))).toBe('pandas\nimport requests');347expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(4), [new Range(0, 7, 1, 15)])).toEqual([new OffsetRange(386, 408)]);348expect(altDocSnapshot.getText(new OffsetRange(462, 510))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');349expect(notebook.cellAt(5).document.getText(new Range(0, 0, 2, 10))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');350expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(5), [new Range(0, 0, 2, 10)])).toEqual([new OffsetRange(462, 510)]);351352expect(altDocSnapshot.getText(new OffsetRange(462, 517))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n');353expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(462, 517))).toEqual([[notebook.cellAt(5), new Range(0, 0, 2, 16)]]);354expect(altDocSnapshot.fromAltRange(new Range(20, 0, 23, 0))).toEqual([[notebook.cellAt(5), new Range(0, 0, 2, 16)]]);355expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(5), [new Range(0, 0, 2, 16)])).toEqual([new OffsetRange(462, 516)]);356357expect(altDocSnapshot.getText(new OffsetRange(570, 610))).toBe('print(sys.executable)\nprint(sys.version)');358expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(570, 610))).toEqual([[notebook.cellAt(6), new Range(0, 0, 1, 18)]]);359expect(altDocSnapshot.fromAltRange(new Range(24, 0, 25, 18))).toEqual([[notebook.cellAt(6), new Range(0, 0, 1, 18)]]);360expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(6), [new Range(0, 0, 1, 18)])).toEqual([new OffsetRange(570, 610)]);361362expect(altDocSnapshot.getText(new OffsetRange(240, 601))).toBe('sys\nimport os\n#%% vscode.cell [id=#VSC-e07487cb] [language=markdown]\n"""\nComments\n"""\n#%% vscode.cell [id=#VSC-53ab90bb] [language=python]\nimport pandas\nimport requests\n#%% vscode.cell [id=#VSC-749a8f95] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n#%% vscode.cell [id=#VSC-d2139a72] [language=python]\nprint(sys.executable)\nprint(sys');363expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(240, 601))).toEqual([364[notebook.cellAt(2), new Range(0, 7, 1, 9)],365[notebook.cellAt(3), new Range(0, 0, 0, 8)],366[notebook.cellAt(4), new Range(0, 0, 1, 15)],367[notebook.cellAt(5), new Range(0, 0, 2, 16)],368[notebook.cellAt(6), new Range(0, 0, 1, 9)]369]);370expect(altDocSnapshot.fromAltRange(new Range(10, 7, 25, 9))).toEqual([371[notebook.cellAt(2), new Range(0, 7, 1, 9)],372[notebook.cellAt(3), new Range(0, 0, 0, 8)],373[notebook.cellAt(4), new Range(0, 0, 1, 15)],374[notebook.cellAt(5), new Range(0, 0, 2, 16)],375[notebook.cellAt(6), new Range(0, 0, 1, 9)]376]);377378expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(106, 177))).toEqual([[notebook.cellAt(1), new Range(0, 0, 1, 15)]]);379expect(altDocSnapshot.fromAltRange(new Range(24, 0, 25, 18))).toEqual([[notebook.cellAt(6), new Range(0, 0, 1, 18)]]);380expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(6), [new Range(0, 0, 1, 18)])).toEqual([new OffsetRange(570, 610)]);381382});383test(`All Cells have different EOLs`, async () => {384const cells = [385new NotebookCellData(NotebookCellKind.Code, 'import sys\nimport os', 'python'),386new NotebookCellData(NotebookCellKind.Code, 'import pandas\r\nimport requests', 'python'),387new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\r\nprint("Foo Bar")\r\nprint("Bar Baz")', 'python'),388new NotebookCellData(NotebookCellKind.Code, 'print(sys.executable)\nprint(sys.version)', 'python'),389];390const { notebook, altDocSnapshot } = createNotebook(cells);391392393expect(altDocSnapshot.getText(new OffsetRange(53, 59))).toBe('import');394expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 59))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);395expect(altDocSnapshot.fromAltRange(new Range(1, 0, 1, 6))).toEqual([[notebook.cellAt(0), new Range(0, 0, 0, 6)]]);396expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 0, 6)])).toEqual([new OffsetRange(53, 59)]);397398expect(altDocSnapshot.getText(new OffsetRange(53, 64))).toBe('import sys\n');399expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 64))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 0)]]);400expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 0))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 0)]]);401expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 1, 0)])).toEqual([new OffsetRange(53, 64)]);402403expect(altDocSnapshot.getText(new OffsetRange(53, 74))).toBe('import sys\nimport os\n');404expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 74))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);405expect(altDocSnapshot.fromAltRange(new Range(1, 0, 2, 9))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)]]);406expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(0, 0, 1, 9)])).toEqual([new OffsetRange(53, 73)]);407408// Translating alt text range across cells will only return contents of one cell.409expect(altDocSnapshot.getText(new OffsetRange(53, 140))).toBe('import sys\nimport os\n#%% vscode.cell [id=#VSC-bdb3864a] [language=python]\nimport pandas');410expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(53, 140))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)], [notebook.cellAt(1), new Range(0, 0, 0, 13)]]);411expect(altDocSnapshot.fromAltRange(new Range(0, 0, 4, 13))).toEqual([[notebook.cellAt(0), new Range(0, 0, 1, 9)], [notebook.cellAt(1), new Range(0, 0, 0, 13)]]);412413expect(altDocSnapshot.getText(new OffsetRange(71, 73))).toBe('os');414expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(71, 73))).toEqual([[notebook.cellAt(0), new Range(1, 7, 1, 9)]]);415expect(altDocSnapshot.fromAltRange(new Range(2, 7, 2, 9))).toEqual([[notebook.cellAt(0), new Range(1, 7, 1, 9)]]);416expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(0), [new Range(1, 7, 1, 9)])).toEqual([new OffsetRange(71, 73)]);417418expect(altDocSnapshot.getText(new OffsetRange(134, 258))).toBe('pandas\nimport requests\n#%% vscode.cell [id=#VSC-8862d4f3] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar');419expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(134, 258))).toEqual([420[notebook.cellAt(1), new Range(0, 7, 1, 15)],421[notebook.cellAt(2), new Range(0, 0, 2, 10)],422]);423expect(altDocSnapshot.fromAltRange(new Range(4, 7, 9, 10))).toEqual([424[notebook.cellAt(1), new Range(0, 7, 1, 15)],425[notebook.cellAt(2), new Range(0, 0, 2, 10)],426]);427428expect(altDocSnapshot.getText(new OffsetRange(134, 156))).toBe('pandas\nimport requests');429expect(notebook.cellAt(1).document.getText(new Range(0, 7, 1, 15))).toBe('pandas\r\nimport requests');430expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(1), [new Range(0, 7, 1, 15)])).toEqual([new OffsetRange(134, 156)]);431expect(altDocSnapshot.getText(new OffsetRange(210, 258))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar');432expect(notebook.cellAt(2).document.getText(new Range(0, 0, 2, 10))).toBe('print("Hello World")\r\nprint("Foo Bar")\r\nprint("Bar');433expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 2, 10)])).toEqual([new OffsetRange(210, 258)]);434435expect(altDocSnapshot.getText(new OffsetRange(210, 265))).toBe('print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n');436expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(210, 265))).toEqual([[notebook.cellAt(2), new Range(0, 0, 2, 16)]]);437expect(altDocSnapshot.fromAltRange(new Range(7, 0, 9, 16))).toEqual([[notebook.cellAt(2), new Range(0, 0, 2, 16)]]);438expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(2), [new Range(0, 0, 2, 16)])).toEqual([new OffsetRange(210, 264)]);439440expect(altDocSnapshot.getText(new OffsetRange(318, 358))).toBe('print(sys.executable)\nprint(sys.version)');441expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(318, 358))).toEqual([[notebook.cellAt(3), new Range(0, 0, 1, 18)]]);442expect(altDocSnapshot.fromAltRange(new Range(11, 0, 12, 18))).toEqual([[notebook.cellAt(3), new Range(0, 0, 1, 18)]]);443expect(altDocSnapshot.toAltOffsetRange(notebook.cellAt(3), [new Range(0, 0, 1, 18)])).toEqual([new OffsetRange(318, 358)]);444445expect(altDocSnapshot.getText(new OffsetRange(60, 349))).toBe('sys\nimport os\n#%% vscode.cell [id=#VSC-bdb3864a] [language=python]\nimport pandas\nimport requests\n#%% vscode.cell [id=#VSC-8862d4f3] [language=python]\nprint("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\n#%% vscode.cell [id=#VSC-e07487cb] [language=python]\nprint(sys.executable)\nprint(sys');446expect(altDocSnapshot.fromAltOffsetRange(new OffsetRange(60, 349))).toEqual([447[notebook.cellAt(0), new Range(0, 7, 1, 9)],448[notebook.cellAt(1), new Range(0, 0, 1, 15)],449[notebook.cellAt(2), new Range(0, 0, 2, 16)],450[notebook.cellAt(3), new Range(0, 0, 1, 9)]451]);452expect(altDocSnapshot.fromAltRange(new Range(1, 7, 12, 9))).toEqual([453[notebook.cellAt(0), new Range(0, 7, 1, 9)],454[notebook.cellAt(1), new Range(0, 0, 1, 15)],455[notebook.cellAt(2), new Range(0, 0, 2, 16)],456[notebook.cellAt(3), new Range(0, 0, 1, 9)]457]);458459});460});461describe('Cell Content Changes', () => {462describe('Cell with 1 line', () => {463const cells = [464new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")', 'python'),465];466let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;467let altDoc: IAlternativeNotebookDocument;468let notebook: NotebookDocument;469beforeEach(() => {470({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));471});472function getUpdatedAltText(e: TextDocumentChangeEvent): string {473const newDoc = altDocSnapshot.withCellChanges(e.document, e.contentChanges);474const edit = toAltNotebookCellChangeEdit(altDocSnapshot, e.document, e.contentChanges);475const updatedAltText = newDoc.getText();476altDoc.applyCellChanges(e.document, e.contentChanges);477478// Verify the alt text is updated correctly479expect(updatedAltText).toBe(edit!.apply(altDocSnapshot.getText()));480expect(updatedAltText).toBe(altDoc.getText());481482return updatedAltText;483}484test(`replace line`, async () => {485expect(getUpdatedAltText({486document: notebook.cellAt(0).document,487reason: undefined,488detailedReason: {489source: 'cursor',490metadata: {}491},492contentChanges: [{493range: new Range(0, 0, 0, 20),494rangeOffset: 0,495rangeLength: 20,496text: '# Top level imports',497}]498})).toMatchSnapshot();499});500test(`replace text with smaller text`, async () => {501expect(getUpdatedAltText({502document: notebook.cellAt(0).document,503reason: undefined,504detailedReason: {505source: 'cursor',506metadata: {}507},508contentChanges: [{509range: new Range(0, 7, 0, 18),510rangeOffset: 7,511rangeLength: 11,512text: 'Foo Bar',513}]514})).toMatchSnapshot();515});516test(`replace text with larger text`, async () => {517expect(getUpdatedAltText({518document: notebook.cellAt(0).document,519reason: undefined,520detailedReason: {521source: 'cursor',522metadata: {}523},524contentChanges: [{525range: new Range(0, 7, 0, 18),526rangeOffset: 7,527rangeLength: 11,528text: 'This is a longer piece of text',529}]530})).toMatchSnapshot();531});532test(`replace while inserting a few lines`, async () => {533expect(getUpdatedAltText({534document: notebook.cellAt(0).document,535reason: undefined,536detailedReason: {537source: 'cursor',538metadata: {}539},540contentChanges: [{541range: new Range(0, 7, 0, 20),542rangeOffset: 7,543rangeLength: 13,544text: 'Foo Bar")\nprint("Another line")\nprint("Yet another line")',545}]546})).toMatchSnapshot();547});548test(`insert a few lines`, async () => {549expect(getUpdatedAltText({550document: notebook.cellAt(0).document,551reason: undefined,552detailedReason: {553source: 'cursor',554metadata: {}555},556contentChanges: [{557range: new Range(0, 20, 0, 20),558rangeOffset: 20,559rangeLength: 0,560text: '\nprint("Another line")\nprint("Yet another line")',561}]562})).toMatchSnapshot();563});564});565describe('Cell with multiple line (crlf)', () => {566const cells = [567new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\r\nprint("Foo Bar")\r\nprint("Bar Baz")\r\nprint("Something Else")', 'python'),568];569let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;570let altDoc: IAlternativeNotebookDocument;571let notebook: NotebookDocument;572beforeEach(() => {573({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));574});575function getUpdatedAltText(e: TextDocumentChangeEvent): string {576const newDoc = altDocSnapshot.withCellChanges(e.document, e.contentChanges);577const edit = toAltNotebookCellChangeEdit(altDocSnapshot, e.document, e.contentChanges);578const updatedAltText = newDoc.getText();579altDoc.applyCellChanges(e.document, e.contentChanges);580581// Verify the alt text is updated correctly582expect(updatedAltText).toBe(edit!.apply(altDocSnapshot.getText()));583expect(updatedAltText).toBe(altDoc.getText());584return updatedAltText;585}586test(`replace line`, async () => {587expect(getUpdatedAltText({588document: notebook.cellAt(0).document,589reason: undefined,590detailedReason: {591source: 'cursor',592metadata: {}593},594contentChanges: [{595range: new Range(0, 0, 0, 20),596rangeOffset: 0,597rangeLength: 20,598text: '# Top level imports',599}]600})).toMatchSnapshot();601});602test(`replace multiple lines`, async () => {603expect(getUpdatedAltText({604document: notebook.cellAt(0).document,605reason: undefined,606detailedReason: {607source: 'cursor',608metadata: {}609},610contentChanges: [{611range: new Range(1, 7, 1, 14),612rangeOffset: 29,613rangeLength: 7,614text: 'Say Something',615}, {616range: new Range(0, 0, 0, 20),617rangeOffset: 0,618rangeLength: 20,619text: '# Top level print statements',620}]621})).toMatchSnapshot();622});623test(`replace text with smaller text`, async () => {624expect(getUpdatedAltText({625document: notebook.cellAt(0).document,626reason: undefined,627detailedReason: {628source: 'cursor',629metadata: {}630},631contentChanges: [{632range: new Range(0, 7, 0, 18),633rangeOffset: 7,634rangeLength: 11,635text: 'Foo Bar',636}]637})).toMatchSnapshot();638});639test(`replace text with larger text`, async () => {640expect(getUpdatedAltText({641document: notebook.cellAt(0).document,642reason: undefined,643detailedReason: {644source: 'cursor',645metadata: {}646},647contentChanges: [{648range: new Range(0, 7, 0, 18),649rangeOffset: 7,650rangeLength: 11,651text: 'This is a longer piece of text',652}]653})).toMatchSnapshot();654});655test(`replace while inserting a few lines`, async () => {656expect(getUpdatedAltText({657document: notebook.cellAt(0).document,658reason: undefined,659detailedReason: {660source: 'cursor',661metadata: {}662},663contentChanges: [{664range: new Range(0, 7, 0, 20),665rangeOffset: 7,666rangeLength: 13,667text: 'Foo Bar")\r\nprint("Another line")\r\nprint("Yet another line")',668}]669})).toMatchSnapshot();670});671test(`insert a few lines`, async () => {672expect(getUpdatedAltText({673document: notebook.cellAt(0).document,674reason: undefined,675detailedReason: {676source: 'cursor',677metadata: {}678},679contentChanges: [{680range: new Range(0, 20, 0, 20),681rangeOffset: 20,682rangeLength: 0,683text: '\nprint("Another line")\nprint("Yet another line")',684}]685})).toMatchSnapshot();686});687test(`remove a line`, async () => {688expect(getUpdatedAltText({689document: notebook.cellAt(0).document,690reason: undefined,691detailedReason: {692source: 'cursor',693metadata: {}694},695contentChanges: [{696range: new Range(0, 20, 1, 16),697rangeOffset: 20,698rangeLength: 18,699text: '',700}]701})).toMatchSnapshot();702});703test(`remove two lines`, async () => {704expect(getUpdatedAltText({705document: notebook.cellAt(0).document,706reason: undefined,707detailedReason: {708source: 'cursor',709metadata: {}710},711contentChanges: [{712range: new Range(0, 20, 2, 16),713rangeOffset: 20,714rangeLength: 36,715text: '',716}]717})).toMatchSnapshot();718});719test(`merge two lines`, async () => {720expect(getUpdatedAltText({721document: notebook.cellAt(0).document,722reason: undefined,723detailedReason: {724source: 'cursor',725metadata: {}726},727contentChanges: [{728range: new Range(0, 20, 1, 0),729rangeOffset: 20,730rangeLength: 2,731text: '',732}]733})).toMatchSnapshot();734});735});736describe('Cell with multiple line (lf)', () => {737const cells = [738new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\nprint("Foo Bar")\nprint("Bar Baz")\nprint("Something Else")', 'python'),739];740let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;741let altDoc: IAlternativeNotebookDocument;742let notebook: NotebookDocument;743beforeEach(() => {744({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));745});746function getUpdatedAltText(e: TextDocumentChangeEvent): string {747const newDoc = altDocSnapshot.withCellChanges(e.document, e.contentChanges);748const edit = toAltNotebookCellChangeEdit(altDocSnapshot, e.document, e.contentChanges);749altDoc.applyCellChanges(e.document, e.contentChanges);750751const updatedAltText = newDoc.getText();752753// Verify the alt text is updated correctly754expect(updatedAltText).toBe(edit!.apply(altDocSnapshot.getText()));755756return updatedAltText;757}758test(`replace line`, async () => {759expect(getUpdatedAltText({760document: notebook.cellAt(0).document,761reason: undefined,762detailedReason: {763source: 'cursor',764metadata: {}765},766contentChanges: [{767range: new Range(0, 0, 0, 20),768rangeOffset: 0,769rangeLength: 20,770text: '# Top level imports',771}]772})).toMatchSnapshot();773});774test(`replace multiple lines`, async () => {775expect(getUpdatedAltText({776document: notebook.cellAt(0).document,777reason: undefined,778detailedReason: {779source: 'cursor',780metadata: {}781},782contentChanges: [{783range: new Range(1, 7, 1, 14),784rangeOffset: 28,785rangeLength: 7,786text: 'Say Something',787}, {788range: new Range(0, 0, 0, 20),789rangeOffset: 0,790rangeLength: 20,791text: '# Top level print statements',792}]793})).toMatchSnapshot();794});795test(`replace text with smaller text`, async () => {796expect(getUpdatedAltText({797document: notebook.cellAt(0).document,798reason: undefined,799detailedReason: {800source: 'cursor',801metadata: {}802},803contentChanges: [{804range: new Range(0, 7, 0, 18),805rangeOffset: 7,806rangeLength: 11,807text: 'Foo Bar',808}]809})).toMatchSnapshot();810});811test(`replace text with larger text`, async () => {812expect(getUpdatedAltText({813document: notebook.cellAt(0).document,814reason: undefined,815detailedReason: {816source: 'cursor',817metadata: {}818},819contentChanges: [{820range: new Range(0, 7, 0, 18),821rangeOffset: 7,822rangeLength: 11,823text: 'This is a longer piece of text',824}]825})).toMatchSnapshot();826});827test(`replace while inserting a few lines`, async () => {828expect(getUpdatedAltText({829document: notebook.cellAt(0).document,830reason: undefined,831detailedReason: {832source: 'cursor',833metadata: {}834},835contentChanges: [{836range: new Range(0, 7, 0, 20),837rangeOffset: 7,838rangeLength: 13,839text: 'Foo Bar")\nprint("Another line")\nprint("Yet another line")',840}]841})).toMatchSnapshot();842});843test(`insert a few lines`, async () => {844expect(getUpdatedAltText({845document: notebook.cellAt(0).document,846reason: undefined,847detailedReason: {848source: 'cursor',849metadata: {}850},851contentChanges: [{852range: new Range(0, 20, 0, 20),853rangeOffset: 20,854rangeLength: 0,855text: '\nprint("Another line")\nprint("Yet another line")',856}]857})).toMatchSnapshot();858});859test(`remove a line`, async () => {860expect(getUpdatedAltText({861document: notebook.cellAt(0).document,862reason: undefined,863detailedReason: {864source: 'cursor',865metadata: {}866},867contentChanges: [{868range: new Range(0, 20, 1, 16),869rangeOffset: 20,870rangeLength: 17,871text: '',872}]873})).toMatchSnapshot();874});875test(`remove two lines`, async () => {876expect(getUpdatedAltText({877document: notebook.cellAt(0).document,878reason: undefined,879detailedReason: {880source: 'cursor',881metadata: {}882},883contentChanges: [{884range: new Range(0, 20, 2, 16),885rangeOffset: 20,886rangeLength: 34,887text: '',888}]889})).toMatchSnapshot();890});891test(`merge two lines`, async () => {892expect(getUpdatedAltText({893document: notebook.cellAt(0).document,894reason: undefined,895detailedReason: {896source: 'cursor',897metadata: {}898},899contentChanges: [{900range: new Range(0, 20, 1, 0),901rangeOffset: 20,902rangeLength: 1,903text: '',904}]905})).toMatchSnapshot();906});907});908describe('Cells with multiple line (lf)', () => {909const cells = [910new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),911new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),912new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\nprint("Foo Bar2")\nprint("Bar Baz2")\nprint("Something Else")', 'python'),913];914let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;915let altDoc: IAlternativeNotebookDocument;916let notebook: NotebookDocument;917beforeEach(() => {918({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));919});920function getUpdatedAltText(e: TextDocumentChangeEvent): string {921const newDoc = altDocSnapshot.withCellChanges(e.document, e.contentChanges);922const edit = toAltNotebookCellChangeEdit(altDocSnapshot, e.document, e.contentChanges);923const updatedAltText = newDoc.getText();924altDoc.applyCellChanges(e.document, e.contentChanges);925926// Verify the alt text is updated correctly927expect(updatedAltText).toBe(edit!.apply(altDocSnapshot.getText()));928expect(updatedAltText).toBe(altDoc.getText());929930return updatedAltText;931}932test(`replace text in last cell`, async () => {933expect(getUpdatedAltText({934document: notebook.cellAt(2).document,935reason: undefined,936detailedReason: {937source: 'cursor',938metadata: {}939},940contentChanges: [{941range: new Range(0, 7, 0, 18),942rangeOffset: 7,943rangeLength: 11,944text: 'Bye bye World',945}]946})).toMatchSnapshot();947});948// test(`replace multiple lines`, async () => {949// expect(getUpdatedAltText({950// document: notebook.cellAt(0).document,951// reason: undefined,952// detailedReason: {953// source: 'cursor',954// metadata: {}955// },956// contentChanges: [{957// range: new Range(1, 7, 1, 14),958// rangeOffset: 28,959// rangeLength: 7,960// text: 'Say Something',961// }, {962// range: new Range(0, 0, 0, 20),963// rangeOffset: 0,964// rangeLength: 20,965// text: '# Top level print statements',966// }]967// })).toMatchSnapshot();968// });969// test(`replace text with smaller text`, async () => {970// expect(getUpdatedAltText({971// document: notebook.cellAt(0).document,972// reason: undefined,973// detailedReason: {974// source: 'cursor',975// metadata: {}976// },977// contentChanges: [{978// range: new Range(0, 7, 0, 18),979// rangeOffset: 7,980// rangeLength: 11,981// text: 'Foo Bar',982// }]983// })).toMatchSnapshot();984// });985// test(`replace text with larger text`, async () => {986// expect(getUpdatedAltText({987// document: notebook.cellAt(0).document,988// reason: undefined,989// detailedReason: {990// source: 'cursor',991// metadata: {}992// },993// contentChanges: [{994// range: new Range(0, 7, 0, 18),995// rangeOffset: 7,996// rangeLength: 11,997// text: 'This is a longer piece of text',998// }]999// })).toMatchSnapshot();1000// });1001// test(`replace while inserting a few lines`, async () => {1002// expect(getUpdatedAltText({1003// document: notebook.cellAt(0).document,1004// reason: undefined,1005// detailedReason: {1006// source: 'cursor',1007// metadata: {}1008// },1009// contentChanges: [{1010// range: new Range(0, 7, 0, 20),1011// rangeOffset: 7,1012// rangeLength: 13,1013// text: 'Foo Bar")\nprint("Another line")\nprint("Yet another line")',1014// }]1015// })).toMatchSnapshot();1016// });1017// test(`insert a few lines`, async () => {1018// expect(getUpdatedAltText({1019// document: notebook.cellAt(0).document,1020// reason: undefined,1021// detailedReason: {1022// source: 'cursor',1023// metadata: {}1024// },1025// contentChanges: [{1026// range: new Range(0, 20, 0, 20),1027// rangeOffset: 20,1028// rangeLength: 0,1029// text: '\nprint("Another line")\nprint("Yet another line")',1030// }]1031// })).toMatchSnapshot();1032// });1033// test(`remove a line`, async () => {1034// expect(getUpdatedAltText({1035// document: notebook.cellAt(0).document,1036// reason: undefined,1037// detailedReason: {1038// source: 'cursor',1039// metadata: {}1040// },1041// contentChanges: [{1042// range: new Range(0, 20, 1, 16),1043// rangeOffset: 20,1044// rangeLength: 17,1045// text: '',1046// }]1047// })).toMatchSnapshot();1048// });1049// test(`remove two lines`, async () => {1050// expect(getUpdatedAltText({1051// document: notebook.cellAt(0).document,1052// reason: undefined,1053// detailedReason: {1054// source: 'cursor',1055// metadata: {}1056// },1057// contentChanges: [{1058// range: new Range(0, 20, 2, 16),1059// rangeOffset: 20,1060// rangeLength: 34,1061// text: '',1062// }]1063// })).toMatchSnapshot();1064// });1065// test(`merge two lines`, async () => {1066// expect(getUpdatedAltText({1067// document: notebook.cellAt(0).document,1068// reason: undefined,1069// detailedReason: {1070// source: 'cursor',1071// metadata: {}1072// },1073// contentChanges: [{1074// range: new Range(0, 20, 1, 0),1075// rangeOffset: 20,1076// rangeLength: 1,1077// text: '',1078// }]1079// })).toMatchSnapshot();1080// });1081});1082});1083describe('Cell Add/Delete', () => {1084describe('Cell with 1 line', () => {1085const cells = [1086new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")', 'python'),1087];1088let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;1089let altDoc: IAlternativeNotebookDocument;1090let notebook: NotebookDocument;1091beforeEach(() => {1092({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));1093});1094function getUpdatedAltText(e: NotebookDocumentContentChange[]): string {1095const originalText = altDocSnapshot.getText();1096const newDoc = altDocSnapshot.withNotebookChanges(e);1097const edit = toAltNotebookChangeEdit(altDocSnapshot, e);1098const updatedAltText = newDoc.getText();1099altDoc.applyNotebookChanges(e);1100if (edit) {1101// Verify the edit is generated correctly1102expect(edit.apply(originalText)).toBe(updatedAltText);1103}1104expect(altDoc.getText()).toBe(updatedAltText);1105return updatedAltText;1106}1107test(`remove cell`, async () => {1108expect(getUpdatedAltText([{1109addedCells: [],1110range: new NotebookRange(0, 1),1111removedCells: [notebook.cellAt(0)],1112}])).toMatchSnapshot();1113});1114test(`insert cell below`, async () => {1115const { notebook } = createNotebook(cells.concat([1116new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1117]));1118expect(getUpdatedAltText([{1119addedCells: [notebook.cellAt(1)],1120range: new NotebookRange(1, 1),1121removedCells: [],1122}])).toMatchSnapshot();1123});1124test(`insert a code cell and markdown cell`, async () => {1125const { notebook } = createNotebook(cells.concat([1126new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1127new NotebookCellData(NotebookCellKind.Markup, '# Foo Bar', 'markdown'),1128]));1129expect(getUpdatedAltText([{1130addedCells: [notebook.cellAt(1)],1131range: new NotebookRange(1, 1),1132removedCells: [],1133}])).toMatchSnapshot();1134});1135test(`insert a markdown cell`, async () => {1136const { notebook } = createNotebook(cells.concat([1137new NotebookCellData(NotebookCellKind.Markup, '# Foo Bar', 'markdown'),1138]));1139expect(getUpdatedAltText([{1140addedCells: [notebook.cellAt(1)],1141range: new NotebookRange(1, 1),1142removedCells: [],1143}])).toMatchSnapshot();1144});1145test(`insert cell above`, async () => {1146const { notebook } = createNotebook(cells.concat([1147new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1148]));1149expect(getUpdatedAltText([{1150addedCells: [notebook.cellAt(1)],1151range: new NotebookRange(0, 0),1152removedCells: [],1153}])).toMatchSnapshot();1154});1155test(`insert cells above`, async () => {1156const { notebook } = createNotebook(cells.concat([1157new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1158new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1159]));1160expect(getUpdatedAltText([{1161addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1162range: new NotebookRange(0, 0),1163removedCells: [],1164}])).toMatchSnapshot();1165});1166test(`insert cells`, async () => {1167const { notebook } = createNotebook(cells.concat([1168new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1169new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1170]));1171expect(getUpdatedAltText([{1172addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1173range: new NotebookRange(1, 1),1174removedCells: [],1175}])).toMatchSnapshot();1176});1177test(`remove and insert cell`, async () => {1178const { notebook } = createNotebook(cells.concat([1179new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1180]));1181expect(getUpdatedAltText([{1182addedCells: [notebook.cellAt(1)],1183range: new NotebookRange(0, 1),1184removedCells: [notebook.cellAt(0)],1185}])).toMatchSnapshot();1186});1187test(`remove and insert cells`, async () => {1188const { notebook } = createNotebook(cells.concat([1189new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1190new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1191]));1192expect(getUpdatedAltText([{1193addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1194range: new NotebookRange(0, 1),1195removedCells: [notebook.cellAt(0)],1196}])).toMatchSnapshot();1197});1198});1199describe('Cell with multiple line (crlf)', () => {1200const cells = [1201new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")', 'python'),1202new NotebookCellData(NotebookCellKind.Code, 'print("Hello World")\r\nprint("Foo Bar")\r\nprint("Bar Baz")\r\nprint("Something Else")', 'python'),1203];1204let altDocSnapshot: IAlternativeNotebookDocumentSnapshot;1205let altDoc: IAlternativeNotebookDocument;1206let notebook: NotebookDocument;1207beforeEach(() => {1208({ altDocSnapshot, altDoc, notebook } = createNotebook(cells));1209});1210function getUpdatedAltText(e: NotebookDocumentContentChange[]): string {1211const originalText = altDocSnapshot.getText();1212const newDoc = altDocSnapshot.withNotebookChanges(e);1213const edit = toAltNotebookChangeEdit(altDocSnapshot, e);1214altDoc.applyNotebookChanges(e);1215const updatedAltText = newDoc.getText();1216if (edit) {1217// Verify the edit is generated correctly1218expect(edit.apply(originalText)).toBe(updatedAltText);1219}1220expect(altDoc.getText()).toBe(updatedAltText);1221return updatedAltText;1222}1223test(`remove first cell`, async () => {1224expect(getUpdatedAltText([{1225addedCells: [],1226range: new NotebookRange(0, 1),1227removedCells: [notebook.cellAt(0)],1228}])).toMatchSnapshot();1229});1230test(`insert cell below`, async () => {1231const { notebook } = createNotebook(cells.concat([1232new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1233]));1234expect(getUpdatedAltText([{1235addedCells: [notebook.cellAt(2)],1236range: new NotebookRange(2, 2),1237removedCells: [],1238}])).toMatchSnapshot();1239});1240test(`insert cell middle`, async () => {1241const { notebook } = createNotebook(cells.concat([1242new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1243]));1244expect(getUpdatedAltText([{1245addedCells: [notebook.cellAt(2)],1246range: new NotebookRange(1, 1),1247removedCells: [],1248}])).toMatchSnapshot();1249});1250test(`insert cells middle`, async () => {1251const { notebook } = createNotebook(cells.concat([1252new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1253new NotebookCellData(NotebookCellKind.Code, '# Another Cell', 'python'),1254]));1255expect(getUpdatedAltText([{1256addedCells: [notebook.cellAt(2), notebook.cellAt(3)],1257range: new NotebookRange(1, 1),1258removedCells: [],1259}])).toMatchSnapshot();1260});1261test(`insert cell above`, async () => {1262const { notebook } = createNotebook(cells.concat([1263new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1264]));1265expect(getUpdatedAltText([{1266addedCells: [notebook.cellAt(1)],1267range: new NotebookRange(0, 0),1268removedCells: [],1269}])).toMatchSnapshot();1270});1271test(`insert cells above`, async () => {1272const { notebook } = createNotebook(cells.concat([1273new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1274new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1275]));1276expect(getUpdatedAltText([{1277addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1278range: new NotebookRange(0, 0),1279removedCells: [],1280}])).toMatchSnapshot();1281});1282test(`insert cells`, async () => {1283const { notebook } = createNotebook(cells.concat([1284new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1285new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1286]));1287expect(getUpdatedAltText([{1288addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1289range: new NotebookRange(1, 1),1290removedCells: [],1291}])).toMatchSnapshot();1292});1293test(`remove and insert cell`, async () => {1294const { notebook } = createNotebook(cells.concat([1295new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1296]));1297expect(getUpdatedAltText([{1298addedCells: [notebook.cellAt(1)],1299range: new NotebookRange(0, 1),1300removedCells: [notebook.cellAt(0)],1301}])).toMatchSnapshot();1302});1303test(`remove and insert cells`, async () => {1304const { notebook } = createNotebook(cells.concat([1305new NotebookCellData(NotebookCellKind.Code, 'print("Foo Bar")', 'python'),1306new NotebookCellData(NotebookCellKind.Code, 'print("Bar Baz")', 'python'),1307]));1308expect(getUpdatedAltText([{1309addedCells: [notebook.cellAt(1), notebook.cellAt(2)],1310range: new NotebookRange(0, 1),1311removedCells: [notebook.cellAt(0)],1312}])).toMatchSnapshot();1313});1314});1315});1316});131713181319