Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/unit/mapped-strings/mapped-text.test.ts
6451 views
1
/*
2
* mapped-text.test.ts
3
*
4
* Copyright (C) 2021-2022 Posit Software, PBC
5
*
6
*/
7
import { unitTest } from "../../test.ts";
8
import { assert, assertEquals } from "testing/asserts";
9
import {
10
asMappedString,
11
mappedDiff,
12
mappedString,
13
} from "../../../src/core/mapped-text.ts";
14
import {
15
mappedSubstring,
16
mappedTrim,
17
mappedTrimEnd,
18
mappedTrimStart,
19
} from "../../../src/core/lib/mapped-text.ts";
20
21
// deno-lint-ignore require-await
22
unitTest("mapped-text - mappedString()", async () => {
23
const source = `---
24
title: foo
25
echo: false
26
---
27
Here's some text.
28
29
\`\`\`{python}
30
#| echo: true
31
#| code-fold: true
32
# and some python
33
import time
34
print(time.time())
35
\`\`\`
36
37
`;
38
39
const yamlFrontMatterRangedS = mappedSubstring(source, 4, 27);
40
const pythonChunkS = mappedString(source, [
41
{ start: 62, end: 144 },
42
]);
43
44
// this tests composition of ranged strings
45
const chunkMetadataS = mappedString(pythonChunkS, [
46
{ start: 3, end: 14 },
47
{ start: 17, end: 33 },
48
]);
49
50
// deno-lint-ignore no-explicit-any
51
function allMatch(a: any[], b: any[]) {
52
return a.every((v, i) => v === b[i]);
53
}
54
55
assert(
56
allMatch(
57
[0, 22, -1, 23].map((n) => yamlFrontMatterRangedS.map(n)?.index),
58
[4, 26, undefined, undefined],
59
),
60
"range map 1",
61
);
62
assert(
63
allMatch(
64
[0, 144 - 62 - 1, 144 - 62].map((n) => pythonChunkS.map(n)?.index),
65
[62, 143, undefined],
66
),
67
"range map 2",
68
);
69
assert(
70
allMatch(
71
[0, 14 - 3 - 1, 14 - 3, 14 - 3 + (33 - 17 - 1), 14 - 3 + (33 - 17)].map(
72
(n) => chunkMetadataS.map(n)?.index,
73
),
74
[65, 75, 79, 94, undefined],
75
),
76
"composed range map",
77
);
78
79
// now we compose ranged strings with injected newlines, for extra havoc
80
const chunkMetadata2S = mappedString(pythonChunkS, [
81
{ start: 3, end: 13 },
82
"\n",
83
{ start: 17, end: 32 },
84
"\n",
85
]);
86
const chunkMetadata3S = mappedString(source, [
87
{ start: 65, end: 75 },
88
"\n",
89
{ start: 79, end: 94 },
90
"\n",
91
]);
92
assert(
93
allMatch(
94
[0, 9, 10, 11].map((n) => chunkMetadata2S.map(n)?.index),
95
[65, 74, 0, 79],
96
),
97
"composed range map 2",
98
);
99
assert(
100
allMatch(
101
[0, 9, 10, 11].map((n) => chunkMetadata2S.map(n, true)?.index),
102
[65, 74, 0, 79],
103
),
104
"composed range map 3",
105
);
106
assert(
107
allMatch(
108
[0, 9, 10, 11].map((n) => chunkMetadata3S.map(n)?.index),
109
[65, 74, 0, 79],
110
),
111
"range map 3",
112
);
113
assert(
114
allMatch(
115
[0, 9, 10, 11].map((n) => chunkMetadata3S.map(n, true)?.index),
116
[65, 74, 0, 79],
117
),
118
"range map 4",
119
);
120
});
121
122
// deno-lint-ignore require-await
123
unitTest("mapped-text - mappedDiff()", async () => {
124
const text1 = `---
125
title: "ojs syntax error"
126
format: html
127
---
128
129
## Let's add some knitr line number interference
130
131
This should make it harder for the lines to come out right:
132
133
\`\`\`{r}
134
rnorm(100)
135
\`\`\`
136
137
## Syntax Error here
138
139
\`\`\`{ojs}
140
// Let's forget this is JS to force a syntax error
141
viewof x = Inputs.range([0, 100], label = "hello!", value = 20)
142
\`\`\`
143
`;
144
145
const text2 = `---
146
title: "ojs syntax error"
147
format: html
148
---
149
150
## Let's add some knitr line number interference
151
152
This should make it harder for the lines to come out right:
153
154
::: {.cell}
155
156
\`\`\`{.r .cell-code}
157
rnorm(100)
158
\`\`\`
159
160
::: {.cell-output-stdout}
161
\`\`\`
162
## [1] -0.717725302 -0.242773543 -0.278330877 -0.295613695 -0.123735080
163
## [6] 0.232292643 -0.489511306 -2.408335922 0.905536173 0.865255767
164
## [11] -0.198943605 0.015560360 0.655278593 0.019608002 -0.894545892
165
## [16] 0.614554271 -0.002447532 -1.873361215 1.109782136 -0.984856650
166
## [21] 0.626415126 0.304848855 1.423643404 -0.006210320 -1.366947113
167
## [26] 0.143371793 1.207872196 0.925073210 1.280760236 1.074683915
168
## [31] -1.362349941 -0.071914857 2.213405782 0.314567108 0.447236991
169
## [36] -1.473838506 -1.747889158 -0.401329546 0.690835240 1.073928009
170
## [41] -1.647715834 -1.277902617 -1.845625083 1.597834481 -0.995791270
171
## [46] 0.267281987 -1.566991308 -0.816110546 0.277625032 1.142689151
172
## [51] -0.982363252 0.862736694 -0.046169092 -0.004287121 0.232999659
173
## [56] -0.318900321 -0.491032649 -0.168216245 -0.091973320 -0.978739524
174
## [61] -0.270792788 0.726650048 -1.001422491 -0.621582296 0.816793861
175
## [66] -1.433459384 -0.787385931 -0.258746719 -0.672616331 0.272171651
176
## [71] 1.047042398 -0.768357307 0.110871645 -0.896096933 -0.460021901
177
## [76] -0.383200018 -0.902422165 0.865603287 0.701839145 0.267261820
178
## [81] 0.197888901 -0.290371774 1.782868793 0.051206937 0.866067094
179
## [86] 0.491884009 0.430615289 0.842136765 -1.350299928 0.518278232
180
## [91] 0.619646456 -1.350406731 -0.136478983 0.005902266 -0.670544605
181
## [96] 0.602516438 -0.789907293 1.294085153 -1.100722511 0.143690310
182
\`\`\`
183
:::
184
:::
185
186
## Syntax Error here
187
188
\`\`\`{ojs}
189
// Let's forget this is JS to force a syntax error
190
viewof x = Inputs.range([0, 100], label = "hello!", value = 20)
191
\`\`\`
192
`;
193
194
mappedDiff(asMappedString(text1), text2);
195
});
196
197
// deno-lint-ignore require-await
198
unitTest("mapped-text - mappedTrim{,Start,End}()", async () => {
199
const whitespace = "\u000A\u000D\u2028\u2029\u0009\u000B\u000C\uFEFF \t";
200
const content = "a \n";
201
for (let i = 0; i < 1000; ++i) {
202
const startTrimLength = Math.random() * 10;
203
const endTrimLength = Math.random() * 10;
204
const contentLength = Math.random() * 10;
205
const strContent = [];
206
for (let j = 0; j < startTrimLength; ++j) {
207
strContent.push(whitespace[~~(Math.random() * whitespace.length)]);
208
}
209
for (let j = 0; j < contentLength; ++j) {
210
strContent.push(content[~~(Math.random() * content.length)]);
211
}
212
for (let j = 0; j < endTrimLength; ++j) {
213
strContent.push(whitespace[~~(Math.random() * whitespace.length)]);
214
}
215
const mappedStr = asMappedString(strContent.join(""));
216
assertEquals(mappedTrim(mappedStr).value, mappedStr.value.trim());
217
assertEquals(mappedTrimStart(mappedStr).value, mappedStr.value.trimStart());
218
assertEquals(mappedTrimEnd(mappedStr).value, mappedStr.value.trimEnd());
219
}
220
});
221
222