import re from conftest import Book, Doc PY = """def read_book(path): if path: return path.read_text(encoding="utf-8") # <utf-8> \treturn None""" def fenced_blocks(text: str) -> list[tuple[str, str]]: return re.findall(r"^(`{3,})([\w+-]*)\n(.*?)\n\1$", text, re.M | re.S) def test_python_indentation_and_special_chars(convert): body = f'
{PY}'
run = convert(Book(docs=[Doc("c.xhtml", body)]))
blocks = fenced_blocks(run.chapter("001"))
assert len(blocks) == 1
fence, lang, code = blocks[0]
assert lang == "python"
assert code == PY.replace("<", "<").replace(">", ">")
assert "<" not in code
def test_shell_code_with_pipes_backslashes_and_dollar(convert):
shell = "$ cat datei.txt | grep -v '^#' \\\n | sort && echo \"$HOME\" > out.txt"
body = f"{shell}"
run = convert(Book(docs=[Doc("c.xhtml", body)]))
(_, lang, code), = fenced_blocks(run.chapter("001"))
assert code == "$ cat datei.txt | grep -v '^#' \\\n | sort && echo \"$HOME\" > out.txt"
assert lang == "" # no reliable language signal -> no label
def test_backticks_in_code_get_longer_fence(convert):
body = "echo ```nested``` and `x`" run = convert(Book(docs=[Doc("c.xhtml", body)])) (fence, _, code), = fenced_blocks(run.chapter("001")) assert fence == "````" assert code == "echo ```nested``` and `x`" def test_br_lines_and_highlight_spans_in_pre(convert): body = ('
#include <stdio.h>
' 'int main(void) {
printf("Hallo\\n");
}
1a = 1' run = convert(Book(docs=[Doc("c.xhtml", body)])) (_, _, code), = fenced_blocks(run.chapter("001")) assert code == "a = 1\nb = 2" def test_inline_code_variants(convert): body = ('
2b = 2
Nutze a*b_c, x | y und `tick` '
'sowie Strg.
Ein normaler Absatz mit Leerzeichen.
" run = convert(Book(docs=[Doc("c.xhtml", body)])) assert "```" not in run.chapter("001") assert "Ein normaler Absatz mit Leerzeichen." in run.chapter("001") def test_unlabeled_code_is_reported(convert): run = convert(Book(docs=[Doc("c.xhtml", "foo bar")])) assert run.report["code_blocks"]["languages"] == {"(keine)": 1} def test_code_language_option_fills_only_unlabeled_blocks(convert): body = "
x = compute()
#include <stdio.h>\nint main(void) { return 0; }"
run = convert(Book(docs=[Doc("c.xhtml", body)]), "--code-language", "py")
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))]
assert langs == ["python", "c"]
by = {item["language"]: item["detected_by"] for item in run.report["code_blocks"]["items"]}
assert by == {"python": "option", "c": "content"}
def test_code_language_option_rejects_unknown_values(convert):
run = convert(Book(docs=[Doc("c.xhtml", "x")]), "--code-language", "quatsch") assert run.rc == 1 assert "quatsch" in run.stderr def test_print_wrap_markers_are_joined(convert): body = ("
return (s * (s -\n ↪ distance(a, b)) *\n s)\n"
"x = ['a', 'b',\n↪ 'c']")
run = convert(Book(docs=[Doc("c.xhtml", body)]))
(_, _, code), = fenced_blocks(run.chapter("001"))
assert code == " return (s * (s - distance(a, b)) *\n s)\nx = ['a', 'b', 'c']"
item = run.report["code_blocks"]["items"][0]
assert item["wrap_lines_joined"] == 2
def test_print_wrap_markers_can_be_kept(convert):
body = "a = (1,\n↪ 2)" run = convert(Book(docs=[Doc("c.xhtml", body)]), "--keep-wrap-markers") (_, _, code), = fenced_blocks(run.chapter("001")) assert code == "a = (1,\n↪ 2)" def test_printed_line_numbers_do_not_hide_the_language(convert): listing = ("00 // Kapitel1/hallo.c\n01 #include <stdio.h>\n \n02 int main(void) {\n" "03 printf(\"Hallo\\n\");\n04 return 0;\n05 }") run = convert(Book(docs=[Doc("c.xhtml", f"
{listing}")]))
(_, lang, code), = fenced_blocks(run.chapter("001"))
assert lang == "c"
assert code.startswith("00 // Kapitel1/hallo.c\n01 #include {b}" for b in blocks)
run = convert(Book(docs=[Doc("c.xhtml", body)]))
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))]
assert langs == ["python", "python", "python", "", "", ""]
def test_weak_signals_follow_the_book_language(convert):
c_listing = "#include <stdio.h>\nint main(void) { return 0; }"
snippets = ["char ch = 65; // 'A'", "if (a || b) {\n x();\n}", "int remove(const char *pathname);",
"struct node {\n int value;\n};", "Ergebnis: 12345", "|00003.14|", "gcc -Wall -o prog prog.c",
"Dezimal: 65; Zeichen: A"]
body = "{c_listing}" for _ in range(5))
body += "".join(f"{s}" for s in snippets)
run = convert(Book(docs=[Doc("c.xhtml", body)]))
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))][5:]
assert langs == ["c", "c", "c", "c", "", "", "", ""]
by = [item["detected_by"] for item in run.report["code_blocks"]["items"]][5:9]
assert by == ["book-context"] * 4
def test_python_book_labels_assignments_but_not_output(convert):
py = "def f(x):\n return x"
snippets = ["foo = decorate(foo)", "random.sample(population, k)", "[x * x for x in range(5)]",
"True", "('A', 'B', 'C')", "Hallo Welt", "4\n3\nnohtyP", "Jane\n42\nPerson(name='Jane')"]
body = "{py}" for _ in range(5))
body += "".join(f"{s}" for s in snippets)
run = convert(Book(docs=[Doc("c.xhtml", body)]))
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))][5:]
assert langs == ["python", "python", "python", "", "", "", "", ""]
def test_mixed_book_gets_no_context_labels(convert):
body = "def f(x):\n return x" * 3 body += "
#include <stdio.h>\nint main(void) { return 0; }" * 3 + "x = compute();" run = convert(Book(docs=[Doc("c.xhtml", body)])) assert fenced_blocks(run.chapter("001"))[-1][1] == ""