Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/unit/percent-format.test.ts
6449 views
1
/*
2
* percent-format.test.ts
3
*
4
* Tests for the Jupyter percent format script parsing
5
*
6
* Copyright (C) 2020-2024 Posit Software, PBC
7
*/
8
import { assertEquals, assert } from "testing/asserts";
9
import { unitTest } from "../test.ts";
10
import { docs } from "../utils.ts";
11
import {
12
isJupyterPercentScript,
13
markdownFromJupyterPercentScript,
14
kJupyterPercentScriptExtensions,
15
kLanguageExtensions,
16
} from "../../src/core/jupyter/percent.ts";
17
18
// Test that the language extensions mapping is correct
19
unitTest("percent-format - kLanguageExtensions mapping", async () => {
20
assertEquals(kLanguageExtensions[".py"], "python");
21
assertEquals(kLanguageExtensions[".jl"], "julia");
22
assertEquals(kLanguageExtensions[".r"], "r");
23
assertEquals(kLanguageExtensions[".q"], "q");
24
});
25
26
// Test that all extensions in kJupyterPercentScriptExtensions have a language mapping
27
unitTest("percent-format - all extensions have language mappings", async () => {
28
for (const ext of kJupyterPercentScriptExtensions) {
29
assert(
30
kLanguageExtensions[ext] !== undefined,
31
`Extension ${ext} has no language mapping`,
32
);
33
}
34
});
35
36
// Test isJupyterPercentScript for Python
37
unitTest("percent-format - isJupyterPercentScript detects Python percent script", async () => {
38
const result = isJupyterPercentScript(docs("percent-format/test-python.py"));
39
assertEquals(result, true, "Should detect Python percent script");
40
});
41
42
// Test isJupyterPercentScript for q/kdb
43
unitTest("percent-format - isJupyterPercentScript detects q percent script", async () => {
44
const result = isJupyterPercentScript(docs("percent-format/test-q.q"));
45
assertEquals(result, true, "Should detect q percent script");
46
});
47
48
// Test isJupyterPercentScript for Julia
49
unitTest("percent-format - isJupyterPercentScript detects Julia percent script", async () => {
50
const result = isJupyterPercentScript(docs("percent-format/test-julia.jl"));
51
assertEquals(result, true, "Should detect Julia percent script");
52
});
53
54
// Test isJupyterPercentScript for R
55
unitTest("percent-format - isJupyterPercentScript detects R percent script", async () => {
56
const result = isJupyterPercentScript(docs("percent-format/test-r.r"));
57
assertEquals(result, true, "Should detect R percent script");
58
});
59
60
// Test that non-percent scripts are not detected
61
unitTest("percent-format - isJupyterPercentScript rejects non-percent Python", async () => {
62
const result = isJupyterPercentScript(docs("percent-format/not-percent.py"));
63
assertEquals(result, false, "Should not detect non-percent Python file");
64
});
65
66
unitTest("percent-format - isJupyterPercentScript rejects non-percent q", async () => {
67
const result = isJupyterPercentScript(docs("percent-format/not-percent.q"));
68
assertEquals(result, false, "Should not detect non-percent q file");
69
});
70
71
// Test isJupyterPercentScript rejects unsupported extensions
72
unitTest("percent-format - isJupyterPercentScript rejects unsupported extensions", async () => {
73
// Create a temp file with unsupported extension - use a non-existent path
74
// The function checks extension first, so it won't try to read the file
75
const result = isJupyterPercentScript("/fake/path/file.txt");
76
assertEquals(result, false, "Should reject unsupported extension");
77
});
78
79
// Test markdownFromJupyterPercentScript for Python
80
unitTest("percent-format - markdownFromJupyterPercentScript converts Python", async () => {
81
const markdown = markdownFromJupyterPercentScript(
82
docs("percent-format/test-python.py"),
83
);
84
85
// Check that it contains python code blocks
86
assert(markdown.includes("```{python}"), "Should contain python code block");
87
assert(markdown.includes("```"), "Should contain closing code fence");
88
89
// Check that markdown content is extracted
90
assert(
91
markdown.includes("This is a markdown cell"),
92
"Should contain markdown content",
93
);
94
95
// Check that code content is present
96
assert(
97
markdown.includes('print("Hello from Python")'),
98
"Should contain Python code",
99
);
100
});
101
102
// Test markdownFromJupyterPercentScript for q/kdb
103
unitTest("percent-format - markdownFromJupyterPercentScript converts q", async () => {
104
const markdown = markdownFromJupyterPercentScript(
105
docs("percent-format/test-q.q"),
106
);
107
108
// Check that it contains q code blocks
109
assert(markdown.includes("```{q}"), "Should contain q code block");
110
assert(markdown.includes("```"), "Should contain closing code fence");
111
112
// Check that markdown content is extracted (without the / prefix)
113
assert(
114
markdown.includes("This is a markdown cell"),
115
"Should contain markdown content",
116
);
117
118
// Check that code content is present
119
assert(markdown.includes("1+1"), "Should contain q code");
120
assert(markdown.includes("x: 42"), "Should contain q code");
121
});
122
123
// Test markdownFromJupyterPercentScript for Julia
124
unitTest("percent-format - markdownFromJupyterPercentScript converts Julia", async () => {
125
const markdown = markdownFromJupyterPercentScript(
126
docs("percent-format/test-julia.jl"),
127
);
128
129
// Check that it contains julia code blocks
130
assert(markdown.includes("```{julia}"), "Should contain julia code block");
131
132
// Check that markdown content is extracted
133
assert(
134
markdown.includes("This is a markdown cell"),
135
"Should contain markdown content",
136
);
137
138
// Check that code content is present
139
assert(
140
markdown.includes('println("Hello from Julia")'),
141
"Should contain Julia code",
142
);
143
});
144
145
// Test markdownFromJupyterPercentScript for R
146
unitTest("percent-format - markdownFromJupyterPercentScript converts R", async () => {
147
const markdown = markdownFromJupyterPercentScript(
148
docs("percent-format/test-r.r"),
149
);
150
151
// Check that it contains r code blocks
152
assert(markdown.includes("```{r}"), "Should contain r code block");
153
154
// Check that markdown content is extracted
155
assert(
156
markdown.includes("This is a markdown cell"),
157
"Should contain markdown content",
158
);
159
160
// Check that code content is present
161
assert(
162
markdown.includes('print("Hello from R")'),
163
"Should contain R code",
164
);
165
});
166
167
// =============================================================================
168
// Regression tests for regex bug fix
169
// The original regex had incorrect alternation: \[markdown|raw\] which matches
170
// "[markdown" OR "raw]" instead of "[markdown]" OR "[raw]"
171
// =============================================================================
172
173
// Test that [raw] cells are detected (tests correct alternation grouping)
174
unitTest("percent-format - isJupyterPercentScript detects [raw] cells", async () => {
175
const result = isJupyterPercentScript(docs("percent-format/test-raw-cell.py"));
176
assertEquals(result, true, "Should detect percent script with [raw] cell");
177
});
178
179
// Test that markdown cells not at start of file are detected (tests multiline matching)
180
unitTest("percent-format - isJupyterPercentScript detects markdown cell not at file start", async () => {
181
const result = isJupyterPercentScript(docs("percent-format/test-markdown-not-first.py"));
182
assertEquals(result, true, "Should detect percent script with markdown cell not at start");
183
});
184
185
// Test that files containing "raw]" text are not falsely detected
186
// This was a bug where the regex would match "raw]" anywhere in the file
187
unitTest("percent-format - isJupyterPercentScript rejects file with raw] text", async () => {
188
const result = isJupyterPercentScript(docs("percent-format/false-positive-raw.py"));
189
assertEquals(result, false, "Should not detect file that merely contains 'raw]' text");
190
});
191
192