Skip to content

Commit f939852

Browse files
authored
Merge pull request #2046 from wilzbach/improve-doc-tester
Improve dspec_tester.d
2 parents 904d0ae + 2ca27b7 commit f939852

File tree

7 files changed

+268
-68
lines changed

7 files changed

+268
-68
lines changed

dspec_tester.d

100755100644
Lines changed: 140 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,82 @@ struct Config {
2424
string dmdBinPath = "dmd";
2525
bool printLineNumbers; // whether line numbers should be shown on errors
2626
}
27-
Config config;
27+
shared Config config;
28+
29+
// a range until the next ')', nested () are ignored
30+
auto untilClosingParentheses(R)(R rs)
31+
{
32+
struct State
33+
{
34+
uint rightParensCount = 1;
35+
bool inCodeBlock;
36+
uint dashCount;
37+
}
38+
return rs.cumulativeFold!((state, r){
39+
if (r == '-')
40+
{
41+
state.dashCount++;
42+
}
43+
else
44+
{
45+
if (state.dashCount >= 3)
46+
state.inCodeBlock = !state.inCodeBlock;
47+
state.dashCount = 0;
48+
}
49+
switch(r)
50+
{
51+
case '-':
52+
break;
53+
case '(':
54+
if (!state.inCodeBlock)
55+
state.rightParensCount++;
56+
break;
57+
case ')':
58+
if (!state.inCodeBlock)
59+
state.rightParensCount--;
60+
break;
61+
default:
62+
}
63+
return state;
64+
})(State()).zip(rs).until!(e => e[0].rightParensCount == 0).map!(e => e[1]);
65+
}
66+
67+
unittest
68+
{
69+
import std.algorithm.comparison : equal;
70+
assert("aa $(foo $(bar)foobar)".untilClosingParentheses.equal("aa $(foo $(bar)foobar)"));
71+
}
72+
73+
auto findDdocMacro(R)(R text, string ddocKey)
74+
{
75+
return text.splitter(ddocKey).map!untilClosingParentheses.dropOne;
76+
}
77+
78+
auto ddocMacroToCode(R)(R text)
79+
{
80+
import std.ascii : newline;
81+
import std.conv : to;
82+
return text.find("---")
83+
.findSplitAfter(newline)[1]
84+
.findSplitBefore("---")[0]
85+
.to!string;
86+
}
2887

2988
int main(string[] args)
3089
{
31-
import std.conv, std.file, std.getopt, std.path;
90+
import std.file, std.getopt, std.path;
3291
import std.parallelism : parallel;
3392
import std.process : environment;
93+
import std.typecons : Tuple;
3494

3595
auto specDir = __FILE_FULL_PATH__.dirName.buildPath("spec");
36-
config.dmdBinPath = environment.get("DMD", "dmd");
3796
bool hasFailed;
3897

98+
config.dmdBinPath = environment.get("DMD", "dmd");
3999
auto helpInformation = getopt(
40100
args,
41-
"l|lines", "Show the line numbers on errors", &config.printLineNumbers,
101+
"l|lines", "Show the line numbers on errors", cast(bool*) &config.printLineNumbers,
102+
"compiler", "D compiler to use", cast(string*) &config.dmdBinPath,
42103
);
43104

44105
if (helpInformation.helpWanted)
@@ -50,23 +111,22 @@ int main(string[] args)
50111
}
51112

52113
// Find all examples in the specification
53-
auto r = regex(`SPEC_RUNNABLE_EXAMPLE\n\s*---+\n[^-]*---+\n\s*\)`, "s");
114+
alias findExamples = (file, ddocKey) => file
115+
.readText
116+
.findDdocMacro(ddocKey)
117+
.map!ddocMacroToCode;
118+
119+
alias SpecType = Tuple!(string, "key", CompileConfig.TestMode, "mode");
120+
auto specTypes = [
121+
SpecType("$(SPEC_RUNNABLE_EXAMPLE_COMPILE", CompileConfig.TestMode.compile),
122+
SpecType("$(SPEC_RUNNABLE_EXAMPLE_RUN", CompileConfig.TestMode.run),
123+
SpecType("$(SPEC_RUNNABLE_EXAMPLE_FAIL", CompileConfig.TestMode.fail),
124+
];
54125
foreach (file; specDir.dirEntries("*.dd", SpanMode.depth).parallel(1))
55126
{
56-
import std.ascii : newline;
57-
import std.uni : isWhite;
58-
auto allTests =
59-
file
60-
.readText
61-
.matchAll(r)
62-
.map!(a => a[0])
63-
.map!(a => a
64-
.find("---")
65-
.findSplitAfter(newline)[1]
66-
.findSplitBefore("---")[0]
67-
.to!string)
68-
.map!compileAndCheck;
69-
127+
auto allTests = specTypes.map!(c => findExamples(file, c.key)
128+
.map!(e => compileAndCheck(e, CompileConfig(c.mode))))
129+
.joiner;
70130
if (!allTests.empty)
71131
{
72132
writefln("%s: %d examples found", file.baseName, allTests.walkLength);
@@ -77,6 +137,15 @@ int main(string[] args)
77137
return hasFailed;
78138
}
79139

140+
struct CompileConfig
141+
{
142+
enum TestMode { run, compile, fail }
143+
TestMode mode;
144+
string[] args;
145+
string expectedStdout;
146+
string expectedStderr;
147+
}
148+
80149
/**
81150
Executes source code with a D compiler (compile-only)
82151
@@ -85,13 +154,29 @@ Params:
85154
86155
Returns: the exit code of the compiler invocation.
87156
*/
88-
auto compileAndCheck(R)(R buffer)
157+
auto compileAndCheck(R)(R buffer, CompileConfig config)
89158
{
90159
import std.process;
91160
import std.uni : isWhite;
92161

93-
auto pipes = pipeProcess([config.dmdBinPath, "-c", "-o-", "-"],
94-
Redirect.stdin | Redirect.stdout | Redirect.stderr);
162+
string[] args = [.config.dmdBinPath];
163+
args ~= config.args;
164+
with (CompileConfig.TestMode)
165+
final switch (config.mode)
166+
{
167+
case run:
168+
args ~= ["-run"];
169+
break;
170+
case compile:
171+
args ~= ["-c", "-o-"];
172+
break;
173+
case fail:
174+
args ~= ["-c", "-o-"];
175+
break;
176+
}
177+
args ~= "-";
178+
179+
auto pipes = pipeProcess(args, Redirect.all);
95180

96181
static mainRegex = regex(`(void|int)\s+main`);
97182
const hasMain = !buffer.matchFirst(mainRegex).empty;
@@ -107,15 +192,27 @@ auto compileAndCheck(R)(R buffer)
107192
pipes.stdin.write(buffer);
108193
pipes.stdin.close;
109194
auto ret = wait(pipes.pid);
110-
if (ret != 0)
195+
if (config.mode == CompileConfig.TestMode.fail)
196+
{
197+
if (ret == 0)
198+
{
199+
stderr.writefln("Compilation should have failed for:\n%s", buffer);
200+
ret = 1;
201+
}
202+
else
203+
{
204+
ret = 0;
205+
}
206+
}
207+
else if (ret != 0)
111208
{
112-
stderr.writeln("--- ");
209+
stderr.writeln("---");
113210
int lineNumber = 1;
114211
buffer
115212
.splitter("\n")
116213
.each!((a) {
117214
const indent = hasMain ? " " : "";
118-
if (config.printLineNumbers)
215+
if (.config.printLineNumbers)
119216
stderr.writefln("%3d: %s%s", lineNumber++, indent, a);
120217
else
121218
stderr.writefln("%s%s", indent, a);
@@ -124,5 +221,23 @@ auto compileAndCheck(R)(R buffer)
124221
stderr.writeln("---");
125222
pipes.stderr.byLine.each!(e => stderr.writeln(e));
126223
}
224+
// check stdout or stderr
225+
static foreach (stream; ["stdout", "stderr"])
226+
{{
227+
import std.ascii : toUpper;
228+
import std.conv : to;
229+
mixin("auto expected = config.expected" ~ stream.front.toUpper.to!string ~ stream.dropOne~ ";");
230+
if (expected)
231+
{
232+
mixin("auto stream = pipes." ~ stream ~ ";");
233+
auto obs = appender!string;
234+
stream.byChunk(4096).each!(c => obs.put(c));
235+
scope(failure) {
236+
stderr.writefln("Expected: %s", expected);
237+
stderr.writefln("Observed: %s", obs.data);
238+
}
239+
assert(obs.data == expected);
240+
}
241+
}}
127242
return ret;
128243
}

ebook.ddoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ RUNNABLE_EXAMPLE=$0
5858
RUNNABLE_EXAMPLE_STDIN=
5959
RUNNABLE_EXAMPLE_ARGS=
6060
SPEC_RUNNABLE_EXAMPLE=$0
61+
SPEC_RUNNABLE_EXAMPLE_COMPILE=$0
62+
SPEC_RUNNABLE_EXAMPLE_RUN=$0
63+
SPEC_RUNNABLE_EXAMPLE_FAIL=$0
6164
SPEC_SUBNAV_NEXT=
6265
SPEC_SUBNAV_PREV_NEXT=
6366
SPEC_SUBNAV_PREV=

latex.ddoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ SHY=\-
263263
SINGLEQUOTE=`$0'
264264
SMALL=\small{$0}
265265
SPEC_RUNNABLE_EXAMPLE=$0
266+
SPEC_RUNNABLE_EXAMPLE_COMPILE=$0
267+
SPEC_RUNNABLE_EXAMPLE_RUN=$0
268+
SPEC_RUNNABLE_EXAMPLE_FAIL=$0
266269
SPEC_S=$(LAYOUT , $1, $(ARGS $+))
267270
SPEC_SUBNAV_NEXT=
268271
SPEC_SUBNAV_PREV=

posix.mak

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ include $(DMD_DIR)/src/osmodel.mak
145145

146146
# External binaries
147147
DMD=$(DMD_DIR)/generated/$(OS)/release/$(MODEL)/dmd
148+
PHOBOS_LIB=$(PHOBOS_DIR)/generated/$(OS)/release/$(MODEL)/dmd/libphobos2.a
148149

149150
# External directories
150151
DOC_OUTPUT_DIR:=$(PWD)/web
@@ -686,6 +687,9 @@ $W/phobos-prerelease/index.verbatim : verbatim.ddoc \
686687
mv $W/phobos-prerelease-verbatim/* $(dir $@)
687688
rm -r $W/phobos-prerelease-verbatim
688689

690+
$(PHOBOS_LIB): $(DMD)
691+
${MAKE} --directory=${PHOBOS_DIR} -f posix.mak lib
692+
689693
################################################################################
690694
# phobos and druntime, latest released build and current build (DDOX version)
691695
################################################################################
@@ -861,10 +865,9 @@ $(PHOBOS_LATEST_FILES_GENERATED): $(PHOBOS_LATEST_DIR_GENERATED)/%: $(PHOBOS_LAT
861865
# Style tests
862866
################################################################################
863867

864-
test_dspec: dspec_tester.d $(STABLE_DMD)
865-
# Temporarily allows failures, see https://github.com/dlang/dlang.org/pull/2006
868+
test_dspec: dspec_tester.d $(DMD) $(PHOBOS_LIB)
866869
@echo "Test the D Language specification"
867-
-DMD=$(DMD_LATEST) $(STABLE_RDMD) $<
870+
$(DMD) -run $< --compiler=$(DMD)
868871

869872
test: $(ASSERT_WRITELN_BIN)_test test_dspec test/next_version.sh all
870873
@echo "Searching for trailing whitespace"

0 commit comments

Comments
 (0)