Skip to content

Commit 7f09105

Browse files
committed
Add -betterC unittest output
1 parent ca5384d commit 7f09105

4 files changed

Lines changed: 78 additions & 14 deletions

File tree

posix.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ test_tests_extractor: $(ROOT)/tests_extractor
111111
$< -i "./test/tests_extractor/$${file}.d" | diff -p - "./test/tests_extractor/$${file}.d.ext"; \
112112
done
113113
$< -a betterc -i "./test/tests_extractor/attributes.d" | diff -p - "./test/tests_extractor/attributes.d.ext";
114+
$< --betterC -i "./test/tests_extractor/betterc.d" | diff -p - "./test/tests_extractor/betterc.d.ext";
114115

115116
RDMD_TEST_COMPILERS = $(DMD)
116117
RDMD_TEST_EXECUTABLE = $(ROOT)/rdmd

test/tests_extractor/betterc.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module betterc;
2+
3+
///
4+
unittest
5+
{
6+
int a = 1;
7+
assert(a == 2);
8+
}
9+
10+
///
11+
unittest
12+
{
13+
int b = 2;
14+
assert(b == 2);
15+
assert(b == 3);
16+
}

test/tests_extractor/betterc.d.ext

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# line 2
2+
void unittest_0()
3+
{
4+
import betterc;
5+
6+
int a = 1;
7+
assert(a == 2);
8+
}
9+
10+
# line 9
11+
void unittest_1()
12+
{
13+
import betterc;
14+
15+
int b = 2;
16+
assert(b == 2);
17+
assert(b == 3);
18+
}
19+
20+
extern(C) void main()
21+
{
22+
unittest_0();
23+
unittest_1();
24+
}

tests_extractor.d

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ class TestVisitor : ASTVisitor
3333
File outFile;
3434
ubyte[] sourceCode;
3535
string moduleName;
36-
string[] attributes;
36+
VisitorConfig config;
37+
int unittestCounter; // in betterC output mode, `void unittest_%d() {` are emitted instead of `unittest {
3738

38-
this(File outFile, ubyte[] sourceCode, string[] attributes)
39+
this(File outFile, ubyte[] sourceCode, VisitorConfig config)
3940
{
4041
this.outFile = outFile;
4142
this.sourceCode = sourceCode;
42-
this.attributes = attributes;
43+
this.config = config;
4344
}
4445

4546
alias visit = ASTVisitor.visit;
@@ -56,6 +57,14 @@ class TestVisitor : ASTVisitor
5657
moduleName = outFile.name.replace(".d", "").replace(dirSeparator, ".").replace(".package", "");
5758
}
5859
m.accept(this);
60+
// -betterC doesn't support running unittests yet
61+
if (config.betterCOutput)
62+
{
63+
outFile.writeln("extern(C) void main()\n{");
64+
scope(exit) outFile.writeln("}");
65+
foreach (i; 0 .. unittestCounter)
66+
outFile.writefln(" unittest_%d();", i);
67+
}
5968
}
6069

6170
override void visit(const Declaration decl)
@@ -70,7 +79,7 @@ private:
7079

7180
bool shouldIncludeUnittest(const Declaration decl)
7281
{
73-
if (!attributes.empty)
82+
if (!config.attributes.empty)
7483
return filterForUDAs(decl);
7584
else
7685
return hasDdocHeader(sourceCode, decl);
@@ -80,8 +89,11 @@ private:
8089
{
8190
foreach (attr; decl.attributes)
8291
{
92+
if (attr.atAttribute is null)
93+
continue;
94+
8395
// check for @myArg
84-
if (attributes.canFind(attr.atAttribute.identifier.text))
96+
if (config.attributes.canFind(attr.atAttribute.identifier.text))
8597
return true;
8698

8799
// support @("myArg") too
@@ -96,7 +108,7 @@ private:
96108
if (attribute.length >= 2)
97109
{
98110
attribute = attribute[1 .. $ - 1];
99-
if (attributes.canFind(attribute))
111+
if (config.attributes.canFind(attribute))
100112
return true;
101113
}
102114
}
@@ -116,7 +128,10 @@ private:
116128
outFile.writefln("# line %d", u.line > 2 ? u.line - 2 : 0);
117129

118130
// write the unittest block
119-
outFile.write("unittest\n{\n");
131+
if (config.betterCOutput)
132+
outFile.writef("void unittest_%d()\n{\n", unittestCounter++);
133+
else
134+
outFile.write("unittest\n{\n");
120135
scope(exit) outFile.writeln("}\n");
121136

122137
// add an import to the current module
@@ -133,7 +148,7 @@ private:
133148
}
134149
}
135150

136-
void parseFile(File inFile, File outFile, string[] attributes)
151+
void parseFile(File inFile, File outFile, VisitorConfig visitorConfig)
137152
{
138153
import dparse.lexer;
139154
import dparse.parser : parseModule;
@@ -151,11 +166,11 @@ void parseFile(File inFile, File outFile, string[] attributes)
151166

152167
RollbackAllocator rba;
153168
auto m = parseModule(tokens.array, inFile.name, &rba);
154-
auto visitor = new TestVisitor(outFile, sourceCode, attributes);
169+
auto visitor = new TestVisitor(outFile, sourceCode, visitorConfig);
155170
visitor.visit(m);
156171
}
157172

158-
void parseFileDir(string inputDir, string fileName, string outputDir, string[] attributes)
173+
void parseFileDir(string inputDir, string fileName, string outputDir, VisitorConfig visitorConfig)
159174
{
160175
import std.path : buildPath, dirSeparator, buildNormalizedPath;
161176

@@ -172,7 +187,13 @@ void parseFileDir(string inputDir, string fileName, string outputDir, string[] a
172187
// convert the file path to a nice output file, e.g. std/uni.d -> std_uni.d
173188
string outName = fileNameNormalized.replace(dirSeparator, "_");
174189

175-
parseFile(File(fileName), File(buildPath(outputDir, outName), "w"), attributes);
190+
parseFile(File(fileName), File(buildPath(outputDir, outName), "w"), visitorConfig);
191+
}
192+
193+
struct VisitorConfig
194+
{
195+
string[] attributes; /// List of attributes to extract;
196+
bool betterCOutput; /// Emit unittest functions and a custom main method compatible with -betterC"
176197
}
177198

178199
void main(string[] args)
@@ -185,12 +206,14 @@ void main(string[] args)
185206
string ignoredFilesStr;
186207
string modulePrefix;
187208
string attributesStr;
209+
VisitorConfig visitorConfig;
188210

189211
auto helpInfo = getopt(args, config.required,
190212
"inputdir|i", "Folder to start the recursive search for unittest blocks (can be a single file)", &inputDir,
191213
"outputdir|o", "Folder to which the extracted test files should be saved (stdout for a single file)", &outputDir,
192214
"ignore", "Comma-separated list of files to exclude (partial matching is supported)", &ignoredFilesStr,
193215
"attributes|a", "Comma-separated list of UDAs that the unittest should have", &attributesStr,
216+
"betterC", "Emit unittest functions and a custom main method compatible with -betterC", &visitorConfig.betterCOutput,
194217
);
195218

196219
if (helpInfo.helpWanted)
@@ -205,7 +228,7 @@ to in the output directory.
205228

206229
inputDir = inputDir.asNormalizedPath.array;
207230
Algebraic!(string, File) outputLocation = cast(string) outputDir.asNormalizedPath.array;
208-
auto attributes = attributesStr.split(",");
231+
visitorConfig.attributes = attributesStr.split(",");
209232

210233
if (!exists(outputDir))
211234
mkdir(outputDir);
@@ -240,8 +263,8 @@ to in the output directory.
240263
{
241264
stderr.writeln("parsing ", file);
242265
outputLocation.visit!(
243-
(string outputFolder) => parseFileDir(inputDir, file, outputFolder, attributes),
244-
(File outputFile) => parseFile(File(file.name, "r"), outputFile, attributes),
266+
(string outputFolder) => parseFileDir(inputDir, file, outputFolder, visitorConfig),
267+
(File outputFile) => parseFile(File(file.name, "r"), outputFile, visitorConfig),
245268
);
246269
}
247270
else

0 commit comments

Comments
 (0)