@@ -33,13 +33,13 @@ class TestVisitor : ASTVisitor
3333 File outFile;
3434 ubyte [] sourceCode;
3535 string moduleName;
36- string [] attributes ;
36+ VisitorConfig config ;
3737
38- this (File outFile, ubyte [] sourceCode, string [] attributes )
38+ this (File outFile, ubyte [] sourceCode, VisitorConfig config )
3939 {
4040 this .outFile = outFile;
4141 this .sourceCode = sourceCode;
42- this .attributes = attributes ;
42+ this .config = config ;
4343 }
4444
4545 alias visit = ASTVisitor.visit;
@@ -56,6 +56,15 @@ class TestVisitor : ASTVisitor
5656 moduleName = outFile.name.replace(" .d" , " " ).replace(dirSeparator, " ." ).replace(" .package" , " " );
5757 }
5858 m.accept(this );
59+ // -betterC doesn't run unittests out of the box
60+ if (config.betterCOutput)
61+ {
62+ outFile.writeln(q{extern (C ) void main()
63+ {
64+ static foreach (u; __traits (getUnitTests, __traits(parent, main)))
65+ u();
66+ }});
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 }
@@ -133,7 +145,7 @@ private:
133145 }
134146}
135147
136- void parseFile (File inFile, File outFile, string [] attributes )
148+ void parseFile (File inFile, File outFile, VisitorConfig visitorConfig )
137149{
138150 import dparse.lexer;
139151 import dparse.parser : parseModule;
@@ -151,11 +163,11 @@ void parseFile(File inFile, File outFile, string[] attributes)
151163
152164 RollbackAllocator rba;
153165 auto m = parseModule(tokens.array, inFile.name, &rba);
154- auto visitor = new TestVisitor(outFile, sourceCode, attributes );
166+ auto visitor = new TestVisitor(outFile, sourceCode, visitorConfig );
155167 visitor.visit(m);
156168}
157169
158- void parseFileDir (string inputDir, string fileName, string outputDir, string [] attributes )
170+ void parseFileDir (string inputDir, string fileName, string outputDir, VisitorConfig visitorConfig )
159171{
160172 import std.path : buildPath, dirSeparator, buildNormalizedPath;
161173
@@ -172,7 +184,13 @@ void parseFileDir(string inputDir, string fileName, string outputDir, string[] a
172184 // convert the file path to a nice output file, e.g. std/uni.d -> std_uni.d
173185 string outName = fileNameNormalized.replace(dirSeparator, " _" );
174186
175- parseFile(File (fileName), File (buildPath(outputDir, outName), " w" ), attributes);
187+ parseFile(File (fileName), File (buildPath(outputDir, outName), " w" ), visitorConfig);
188+ }
189+
190+ struct VisitorConfig
191+ {
192+ string [] attributes; // / List of attributes to extract;
193+ bool betterCOutput; // / Add custom extern(C) main method for running D's unittests
176194}
177195
178196void main (string [] args)
@@ -185,12 +203,14 @@ void main(string[] args)
185203 string ignoredFilesStr;
186204 string modulePrefix;
187205 string attributesStr;
206+ VisitorConfig visitorConfig;
188207
189208 auto helpInfo = getopt(args, config.required,
190209 " inputdir|i" , " Folder to start the recursive search for unittest blocks (can be a single file)" , &inputDir,
191210 " outputdir|o" , " Folder to which the extracted test files should be saved (stdout for a single file)" , &outputDir,
192211 " ignore" , " Comma-separated list of files to exclude (partial matching is supported)" , &ignoredFilesStr,
193212 " attributes|a" , " Comma-separated list of UDAs that the unittest should have" , &attributesStr,
213+ " betterC" , " Add custom extern(C) main method for running D's unittests" , &visitorConfig.betterCOutput,
194214 );
195215
196216 if (helpInfo.helpWanted)
@@ -205,7 +225,7 @@ to in the output directory.
205225
206226 inputDir = inputDir.asNormalizedPath.array;
207227 Algebraic! (string , File ) outputLocation = cast (string ) outputDir.asNormalizedPath.array;
208- auto attributes = attributesStr.split(" ," );
228+ visitorConfig. attributes = attributesStr.split(" ," );
209229
210230 if (! exists(outputDir))
211231 mkdir(outputDir);
@@ -240,8 +260,8 @@ to in the output directory.
240260 {
241261 stderr.writeln(" parsing " , file);
242262 outputLocation.visit! (
243- (string outputFolder) => parseFileDir(inputDir, file, outputFolder, attributes ),
244- (File outputFile) => parseFile(File (file.name, " r" ), outputFile, attributes ),
263+ (string outputFolder) => parseFileDir(inputDir, file, outputFolder, visitorConfig ),
264+ (File outputFile) => parseFile(File (file.name, " r" ), outputFile, visitorConfig ),
245265 );
246266 }
247267 else
0 commit comments