Path: blob/main/tests/unit/mapped-strings/mapped-text.test.ts
6451 views
/*1* mapped-text.test.ts2*3* Copyright (C) 2021-2022 Posit Software, PBC4*5*/6import { unitTest } from "../../test.ts";7import { assert, assertEquals } from "testing/asserts";8import {9asMappedString,10mappedDiff,11mappedString,12} from "../../../src/core/mapped-text.ts";13import {14mappedSubstring,15mappedTrim,16mappedTrimEnd,17mappedTrimStart,18} from "../../../src/core/lib/mapped-text.ts";1920// deno-lint-ignore require-await21unitTest("mapped-text - mappedString()", async () => {22const source = `---23title: foo24echo: false25---26Here's some text.2728\`\`\`{python}29#| echo: true30#| code-fold: true31# and some python32import time33print(time.time())34\`\`\`3536`;3738const yamlFrontMatterRangedS = mappedSubstring(source, 4, 27);39const pythonChunkS = mappedString(source, [40{ start: 62, end: 144 },41]);4243// this tests composition of ranged strings44const chunkMetadataS = mappedString(pythonChunkS, [45{ start: 3, end: 14 },46{ start: 17, end: 33 },47]);4849// deno-lint-ignore no-explicit-any50function allMatch(a: any[], b: any[]) {51return a.every((v, i) => v === b[i]);52}5354assert(55allMatch(56[0, 22, -1, 23].map((n) => yamlFrontMatterRangedS.map(n)?.index),57[4, 26, undefined, undefined],58),59"range map 1",60);61assert(62allMatch(63[0, 144 - 62 - 1, 144 - 62].map((n) => pythonChunkS.map(n)?.index),64[62, 143, undefined],65),66"range map 2",67);68assert(69allMatch(70[0, 14 - 3 - 1, 14 - 3, 14 - 3 + (33 - 17 - 1), 14 - 3 + (33 - 17)].map(71(n) => chunkMetadataS.map(n)?.index,72),73[65, 75, 79, 94, undefined],74),75"composed range map",76);7778// now we compose ranged strings with injected newlines, for extra havoc79const chunkMetadata2S = mappedString(pythonChunkS, [80{ start: 3, end: 13 },81"\n",82{ start: 17, end: 32 },83"\n",84]);85const chunkMetadata3S = mappedString(source, [86{ start: 65, end: 75 },87"\n",88{ start: 79, end: 94 },89"\n",90]);91assert(92allMatch(93[0, 9, 10, 11].map((n) => chunkMetadata2S.map(n)?.index),94[65, 74, 0, 79],95),96"composed range map 2",97);98assert(99allMatch(100[0, 9, 10, 11].map((n) => chunkMetadata2S.map(n, true)?.index),101[65, 74, 0, 79],102),103"composed range map 3",104);105assert(106allMatch(107[0, 9, 10, 11].map((n) => chunkMetadata3S.map(n)?.index),108[65, 74, 0, 79],109),110"range map 3",111);112assert(113allMatch(114[0, 9, 10, 11].map((n) => chunkMetadata3S.map(n, true)?.index),115[65, 74, 0, 79],116),117"range map 4",118);119});120121// deno-lint-ignore require-await122unitTest("mapped-text - mappedDiff()", async () => {123const text1 = `---124title: "ojs syntax error"125format: html126---127128## Let's add some knitr line number interference129130This should make it harder for the lines to come out right:131132\`\`\`{r}133rnorm(100)134\`\`\`135136## Syntax Error here137138\`\`\`{ojs}139// Let's forget this is JS to force a syntax error140viewof x = Inputs.range([0, 100], label = "hello!", value = 20)141\`\`\`142`;143144const text2 = `---145title: "ojs syntax error"146format: html147---148149## Let's add some knitr line number interference150151This should make it harder for the lines to come out right:152153::: {.cell}154155\`\`\`{.r .cell-code}156rnorm(100)157\`\`\`158159::: {.cell-output-stdout}160\`\`\`161## [1] -0.717725302 -0.242773543 -0.278330877 -0.295613695 -0.123735080162## [6] 0.232292643 -0.489511306 -2.408335922 0.905536173 0.865255767163## [11] -0.198943605 0.015560360 0.655278593 0.019608002 -0.894545892164## [16] 0.614554271 -0.002447532 -1.873361215 1.109782136 -0.984856650165## [21] 0.626415126 0.304848855 1.423643404 -0.006210320 -1.366947113166## [26] 0.143371793 1.207872196 0.925073210 1.280760236 1.074683915167## [31] -1.362349941 -0.071914857 2.213405782 0.314567108 0.447236991168## [36] -1.473838506 -1.747889158 -0.401329546 0.690835240 1.073928009169## [41] -1.647715834 -1.277902617 -1.845625083 1.597834481 -0.995791270170## [46] 0.267281987 -1.566991308 -0.816110546 0.277625032 1.142689151171## [51] -0.982363252 0.862736694 -0.046169092 -0.004287121 0.232999659172## [56] -0.318900321 -0.491032649 -0.168216245 -0.091973320 -0.978739524173## [61] -0.270792788 0.726650048 -1.001422491 -0.621582296 0.816793861174## [66] -1.433459384 -0.787385931 -0.258746719 -0.672616331 0.272171651175## [71] 1.047042398 -0.768357307 0.110871645 -0.896096933 -0.460021901176## [76] -0.383200018 -0.902422165 0.865603287 0.701839145 0.267261820177## [81] 0.197888901 -0.290371774 1.782868793 0.051206937 0.866067094178## [86] 0.491884009 0.430615289 0.842136765 -1.350299928 0.518278232179## [91] 0.619646456 -1.350406731 -0.136478983 0.005902266 -0.670544605180## [96] 0.602516438 -0.789907293 1.294085153 -1.100722511 0.143690310181\`\`\`182:::183:::184185## Syntax Error here186187\`\`\`{ojs}188// Let's forget this is JS to force a syntax error189viewof x = Inputs.range([0, 100], label = "hello!", value = 20)190\`\`\`191`;192193mappedDiff(asMappedString(text1), text2);194});195196// deno-lint-ignore require-await197unitTest("mapped-text - mappedTrim{,Start,End}()", async () => {198const whitespace = "\u000A\u000D\u2028\u2029\u0009\u000B\u000C\uFEFF \t";199const content = "a \n";200for (let i = 0; i < 1000; ++i) {201const startTrimLength = Math.random() * 10;202const endTrimLength = Math.random() * 10;203const contentLength = Math.random() * 10;204const strContent = [];205for (let j = 0; j < startTrimLength; ++j) {206strContent.push(whitespace[~~(Math.random() * whitespace.length)]);207}208for (let j = 0; j < contentLength; ++j) {209strContent.push(content[~~(Math.random() * content.length)]);210}211for (let j = 0; j < endTrimLength; ++j) {212strContent.push(whitespace[~~(Math.random() * whitespace.length)]);213}214const mappedStr = asMappedString(strContent.join(""));215assertEquals(mappedTrim(mappedStr).value, mappedStr.value.trim());216assertEquals(mappedTrimStart(mappedStr).value, mappedStr.value.trimStart());217assertEquals(mappedTrimEnd(mappedStr).value, mappedStr.value.trimEnd());218}219});220221222