Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
211 lines (190 loc) · 7.08 KB
/
Copy pathMakefile
File metadata and controls
211 lines (190 loc) · 7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
PANDOC ?= pandoc
QUARTO ?= quarto pandoc
FILTER = container-writer.lua
STRIP_FILTER = container-strip.lua
UNWRAP_FILTER = container-unwrap.lua
# Filter chains
WRITE = --lua-filter=$(FILTER)
UNWRAP = --lua-filter=$(FILTER) --lua-filter=$(UNWRAP_FILTER)
STRIP = --lua-filter=$(STRIP_FILTER) --lua-filter=$(FILTER)
# html and markdown are here to pin the passthrough contract, not to test
# wrapping: html reaches an empty table entry, html5 reaches the same one
# through variant normalisation, and markdown is absent from the table
# altogether. Between them they cover every branch of the format lookup.
# jats_publishing pins the other half of that lookup: it must resolve to the
# jats entry and tag its raw blocks 'jats', since Pandoc discards blocks
# tagged with a variant name.
TEXT_FORMATS = latex context typst html html5 markdown jats jats_publishing
BIN_FORMATS = docx odt
# strip-*.md : run through container-strip, compared as markdown
# noop*.md : run through container-unwrap, output must be container-free
# everything else : the main suite
STRIP_INPUTS = $(wildcard test/input/strip-*.md)
UNWRAP_INPUTS = $(wildcard test/input/noop*.md)
MAIN_INPUTS = $(filter-out $(STRIP_INPUTS) $(UNWRAP_INPUTS), $(wildcard test/input/*.md))
TMP = /tmp/cw
# check LABEL EXPECTED-BASE ACTUAL-OUT ACTUAL-ERR
# Compares stdout against EXPECTED-BASE.out, and stderr against
# EXPECTED-BASE.err when that file exists (otherwise stderr must be empty).
# Sets `failed` on mismatch. Shared by every test target.
#
# Both sides are normalised first: a fenced div is the same construct with
# three colons or with four — the count only disambiguates nesting — and
# Pandoc changed which it emits between the versions the CI pins (3.1.3
# writes ::: where 3.10 writes ::::). Normalising both sides means a golden
# file stays valid whichever version generated it, and the diff printed on
# failure shows the real difference instead of a colon count.
define CHECK
failed=0; \
check() { \
label="$$1"; exp="$$2"; out="$$3"; err="$$4"; ok=1; \
sed 's/^::::*/:::/' "$$out" > "$$out.norm" 2>/dev/null; \
sed 's/^::::*/:::/' "$$exp.out" > "$$out.gold" 2>/dev/null || : > "$$out.gold"; \
if ! diff -q "$$out.norm" "$$out.gold" >/dev/null 2>&1; then \
echo "FAIL: $$label (stdout)"; diff "$$out.norm" "$$out.gold"; ok=0; \
fi; \
if [ -f "$$exp.err" ]; then \
if ! diff -q "$$err" "$$exp.err" >/dev/null 2>&1; then \
echo "FAIL: $$label (stderr)"; diff "$$err" "$$exp.err"; ok=0; \
fi; \
elif [ -s "$$err" ]; then \
echo "FAIL: $$label (unexpected stderr)"; cat "$$err"; ok=0; \
fi; \
if [ $$ok -eq 1 ]; then echo "PASS: $$label"; else failed=1; fi; \
};
endef
# styles ARCHIVE FORMAT
# Lists the paragraph and character styles applied in a docx/odt file,
# sorted and deduplicated. Binary output cannot be diffed directly, so
# this is what the docx/odt golden files record.
define STYLES
styles() { \
case "$$2" in \
docx) unzip -p "$$1" word/document.xml \
| grep -o 'w:[pr]Style w:val="[^"]*"';; \
odt) unzip -p "$$1" content.xml \
| grep -o 'text:style-name="[^"]*"';; \
esac | LC_ALL=C sort -u; \
};
endef
# generate EXPECTED-BASE COMMAND...
# Writes COMMAND's stdout to EXPECTED-BASE.out, and its stderr to
# EXPECTED-BASE.err only when non-empty.
define GENERATE
generate() { \
exp="$$1"; shift; \
"$$@" >"$$exp.out" 2>"$$exp.err.tmp"; \
if [ -s "$$exp.err.tmp" ]; then mv "$$exp.err.tmp" "$$exp.err"; \
else rm -f "$$exp.err.tmp" "$$exp.err"; fi; \
echo "Generated: $$exp"; \
};
endef
.PHONY: test test-main test-noop test-bin test-strip \
test-quarto test-quarto-strip \
generate-tests generate-noop-tests generate-bin-tests \
generate-strip-tests clean
# Runs every suite even when one of them fails, so a single broken format
# does not hide the state of the others, and fails if any of them did.
test:
@rc=0; \
$(MAKE) --no-print-directory test-main || rc=1; \
$(MAKE) --no-print-directory test-noop || rc=1; \
$(MAKE) --no-print-directory test-bin || rc=1; \
exit $$rc
test-main:
@$(CHECK) \
for f in $(MAIN_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(TEXT_FORMATS); do \
$(PANDOC) $(WRITE) $$f -t $$fmt \
>$(TMP)_$$name-$$fmt.out 2>$(TMP)_$$name-$$fmt.err; \
check "$$name ($$fmt)" test/expected/$$name-$$fmt \
$(TMP)_$$name-$$fmt.out $(TMP)_$$name-$$fmt.err; \
done; \
done; \
exit $$failed
test-noop:
@$(CHECK) \
for f in $(UNWRAP_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(TEXT_FORMATS); do \
$(PANDOC) $(UNWRAP) $$f -t $$fmt \
>$(TMP)_$$name-$$fmt.out 2>$(TMP)_$$name-$$fmt.err; \
check "$$name ($$fmt)" test/expected/$$name-$$fmt \
$(TMP)_$$name-$$fmt.out $(TMP)_$$name-$$fmt.err; \
done; \
done; \
exit $$failed
# docx/odt are zip archives — compare the applied styles, not the bytes.
test-bin:
@$(CHECK) $(STYLES) \
for f in $(MAIN_INPUTS) $(UNWRAP_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(BIN_FORMATS); do \
$(PANDOC) $(WRITE) $$f -t $$fmt -o $(TMP)_$$name.$$fmt \
2>$(TMP)_$$name-$$fmt.err; \
styles $(TMP)_$$name.$$fmt $$fmt >$(TMP)_$$name-$$fmt.out; \
check "$$name ($$fmt)" test/expected/$$name-$$fmt \
$(TMP)_$$name-$$fmt.out $(TMP)_$$name-$$fmt.err; \
done; \
done; \
exit $$failed
test-strip:
@$(CHECK) \
for f in $(STRIP_INPUTS); do \
name=$$(basename $$f .md); \
$(PANDOC) $(STRIP) $$f -t markdown \
>$(TMP)_$$name.out 2>$(TMP)_$$name.err; \
check "$$name" test/expected/$$name $(TMP)_$$name.out $(TMP)_$$name.err; \
done; \
exit $$failed
# Quarto tests — the same suites under Quarto's bundled Pandoc, to catch a
# version or a wrapper that behaves differently from a plain pandoc call.
# Delegating rather than repeating the loops means Quarto covers whatever the
# Pandoc targets cover: when docx and odt were added, the copies here were
# left behind and tested less than they appeared to.
test-quarto:
@$(MAKE) --no-print-directory test PANDOC="$(QUARTO)"
test-quarto-strip:
@$(MAKE) --no-print-directory test-strip PANDOC="$(QUARTO)"
generate-tests:
@mkdir -p test/expected
@$(GENERATE) \
for f in $(MAIN_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(TEXT_FORMATS); do \
generate test/expected/$$name-$$fmt \
$(PANDOC) $(WRITE) $$f -t $$fmt; \
done; \
done
generate-noop-tests:
@mkdir -p test/expected
@$(GENERATE) \
for f in $(UNWRAP_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(TEXT_FORMATS); do \
generate test/expected/$$name-$$fmt \
$(PANDOC) $(UNWRAP) $$f -t $$fmt; \
done; \
done
generate-bin-tests:
@mkdir -p test/expected
@$(STYLES) \
for f in $(MAIN_INPUTS) $(UNWRAP_INPUTS); do \
name=$$(basename $$f .md); \
for fmt in $(BIN_FORMATS); do \
$(PANDOC) $(WRITE) $$f -t $$fmt -o $(TMP)_$$name.$$fmt; \
styles $(TMP)_$$name.$$fmt $$fmt \
>test/expected/$$name-$$fmt.out; \
echo "Generated: test/expected/$$name-$$fmt"; \
done; \
done
generate-strip-tests:
@mkdir -p test/expected
@$(GENERATE) \
for f in $(STRIP_INPUTS); do \
name=$$(basename $$f .md); \
generate test/expected/$$name $(PANDOC) $(STRIP) $$f -t markdown; \
done
clean:
rm -f $(TMP)_*