@@ -177,7 +177,7 @@ private:
177177 Out fl;
178178}
179179
180- void parseString (Visitor)(ubyte [] sourceCode, string fileName, Visitor visitor)
180+ void parseString (Visitor)(ubyte [] sourceCode, Visitor visitor)
181181{
182182 import dparse.lexer;
183183 import dparse.parser : parseModule;
@@ -188,89 +188,36 @@ void parseString(Visitor)(ubyte[] sourceCode, string fileName, Visitor visitor)
188188 const (Token )[] tokens = getTokensForParser(sourceCode, config, &cache).array;
189189
190190 RollbackAllocator rba;
191- auto m = parseModule(tokens, fileName , &rba);
191+ auto m = parseModule(tokens, " magic.d " , &rba);
192192 visitor.visit(m);
193193}
194194
195- void parseFile (string fileName, string destFile )
195+ private auto assertWritelnModuleImpl (string fileText )
196196{
197- import std.array : uninitializedArray;
198-
199- auto inFile = File (fileName);
200- if (inFile.size == 0 )
201- warningf(" %s is empty" , inFile.name);
202-
203- ubyte [] sourceCode = uninitializedArray! (ubyte [])(to! size_t (inFile.size));
204- if (sourceCode.length == 0 )
205- return ;
206-
207- inFile.rawRead(sourceCode);
208- auto fl = FileLines(fileName, destFile);
197+ import std.string : representation;
198+ auto fl = FileLines(fileText);
209199 auto visitor = new TestVisitor! (typeof (fl))(fl);
210- parseString(sourceCode, fileName, visitor);
200+ // libdparse doesn't allow to work on immutable source code
201+ parseString(cast (ubyte []) fileText.representation, visitor);
211202 delete visitor;
203+ return fl;
212204}
213205
214- // Modify a path under oldBase to a new path with the same subpath under newBase.
215- // E.g.: `/foo/bar`.rebasePath(`/foo`, `/quux`) == `/quux/bar`
216- string rebasePath (string path, string oldBase, string newBase)
206+ auto assertWritelnModule (string fileText)
217207{
218- import std.path : absolutePath, buildPath, relativePath;
219- return buildPath (newBase, path.absolutePath.relativePath(oldBase.absolutePath));
208+ return assertWritelnModuleImpl (fileText).buildLines;
220209}
221-
222- version (unittest ) { void main(){} } else
223- void main (string [] args)
210+ auto assertWritelnBlock (string fileText)
224211{
225- import std.file ;
226- import std.getopt ;
227- import std.path ;
228-
229- string inputDir, outputDir;
230- string [] ignoredFiles;
231-
232- auto helpInfo = getopt(args, config.required,
233- " inputdir|i" , " Folder to start the recursive search for unittest blocks (can be a single file)" , &inputDir,
234- " outputdir|o" , " Alternative folder to use as output (can be a single file)" , &outputDir,
235- " ignore" , " List of files to exclude (partial matching is supported)" , &ignoredFiles);
236-
237- if (helpInfo.helpWanted)
238- {
239- return defaultGetoptPrinter (` assert_writeln_magic
240- Tries to lower EqualExpression in AssertExpressions of Unittest blocks to commented writeln calls.
241- ` , helpInfo.options);
242- }
243-
244- inputDir = inputDir.asNormalizedPath.array;
245-
246- DirEntry [] files;
247-
248- // inputDir as default output directory
249- if (! outputDir.length)
250- outputDir = inputDir;
251-
252- if (inputDir.isFile)
253- {
254- files = [DirEntry (inputDir)];
255- inputDir = " " ;
256- }
257- else
258- {
259- files = dirEntries(inputDir, SpanMode.depth).filter! (
260- a => a.name.endsWith(" .d" ) && ! a.name.canFind(" .git" )).array;
261- }
262-
263- foreach (file; files)
212+ auto source = " unittest{\n " ~ fileText ~ " }\n " ;
213+ auto fl = assertWritelnModuleImpl(source);
214+ auto app = appender! string ;
215+ foreach (line; fl.lines[1 .. $ - 2 ])
264216 {
265- if (! ignoredFiles.any! (x => file.name.canFind(x)))
266- {
267- // single files
268- if (inputDir.length == 0 )
269- parseFile(file.name, outputDir);
270- else
271- parseFile(file.name, file.name.rebasePath(inputDir, outputDir));
272- }
217+ app ~= line;
218+ app ~= " \n " ;
273219 }
220+ return app.data;
274221}
275222
276223/**
@@ -284,47 +231,26 @@ struct FileLines
284231
285232 string [] lines;
286233 string destFile;
287- bool overwriteInputFile;
288234 bool hasWrittenChanges;
289235
290- this (string inputFile, string destFile)
291- {
292- stderr.writefln(" %s -> %s" , inputFile, destFile);
293- this .overwriteInputFile = inputFile == destFile;
294- this .destFile = destFile;
295- lines = File (inputFile).byLineCopy.array;
296-
297- destFile.dirName.mkdirRecurse;
298- }
299-
300- // dumps all changes
301- ~this ()
236+ this (string inputText)
302237 {
303- if (overwriteInputFile)
304- {
305- if (hasWrittenChanges)
306- {
307- auto tmpFile = File (destFile ~ " .tmp" , " w" );
308- writeLinesToFile(tmpFile);
309- tmpFile.close;
310- tmpFile.name.rename(destFile);
311- }
312- }
313- else
314- {
315- writeLinesToFile(File (destFile, " w" ));
316- }
238+ lines = inputText.split(" \n " );
317239 }
318240
319241 // writes all changes to a random, temporary file
320- void writeLinesToFile (File outFile) {
242+ auto buildLines () {
243+ auto app = appender! string ;
321244 // dump file
322245 foreach (line; lines)
323- outFile.writeln(line);
246+ {
247+ app ~= line;
248+ app ~= " \n " ;
249+ }
324250 // within the docs we automatically inject std.stdio (hence we need to do the same here)
325251 // writeln needs to be @nogc, @safe, pure and nothrow (we just fake it)
326- outFile.writeln( " // \n private void writeln(T)(T l) { }" ) ;
327- outFile.flush ;
252+ app ~= " // \n private void writeln(T)(T l) { }" ;
253+ return app.data ;
328254 }
329255
330256 string opIndex (size_t i) { return lines[i]; }
@@ -349,7 +275,7 @@ version(unittest)
349275 import std.string : representation;
350276 auto mock = FileLinesMock(sourceCode.split(" \n " ));
351277 auto visitor = new TestVisitor! (typeof (mock))(mock);
352- parseString(sourceCode.representation.dup , " testmodule " , visitor);
278+ parseString(sourceCode.representation.dup , visitor);
353279 delete visitor;
354280 return mock;
355281 }
0 commit comments