From f6d9d04e4303dee71e85b2a346c05efcfd92d6a0 Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Mon, 23 May 2022 21:46:54 +0200 Subject: [PATCH 1/2] Port `test.sh` to platform independent D. This executes also way faster by not spawning GNU diff. --- tests/test.d | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.sh | 2 + 2 files changed, 106 insertions(+) create mode 100755 tests/test.d diff --git a/tests/test.d b/tests/test.d new file mode 100755 index 0000000..e4d70d4 --- /dev/null +++ b/tests/test.d @@ -0,0 +1,104 @@ +#!/usr/bin/env rdmd +/** +Platform independent port of `test.sh`. Runs the tests in this directory. + +Ignores differences in line endings, unless the test uses `--end_of_line`. +**/ +import std.algorithm, std.array, std.conv, std.file, std.path, std.process; +import std.stdio, std.string, std.typecons, std.range, std.uni; + +version (Windows) + enum dfmt = `..\bin\dfmt.exe`; +else + enum dfmt = `../bin/dfmt`; + +int main() +{ + foreach (braceStyle; ["allman", "otbs", "knr"]) + foreach (entry; dirEntries(".", "*.d", SpanMode.shallow). + filter!(e => e.baseName(".d") != thisExePath.baseName(".exe"))) + { + const source = entry.baseName; + const outFileName = buildPath(braceStyle, source ~ ".out"); + const refFileName = buildPath(braceStyle, source ~ ".ref"); + const argsFile = source.stripExtension ~ ".args"; + const dfmtCommand = + [dfmt, "--brace_style=" ~ braceStyle] ~ + (argsFile.exists ? readText(argsFile).splitter!isWhite.filter!(a => a.length).array : []) ~ + [source]; + writeln(dfmtCommand.join(" ")); + if (const result = spawnProcess(dfmtCommand, stdin, File(outFileName, "w")).wait) + return result; + + // As long as dfmt defaults to LF line endings (issue #552), we'll have to default to ignore + // the line endings in our verification with the reference. + const keepTerminator = dfmtCommand.any!(a => a.canFind("--end_of_line")).to!(Flag!"keepTerminator"); + const outText = outFileName.readText; + const refText = refFileName.readText; + const outLines = outText.splitLines(keepTerminator); + const refLines = refText.splitLines(keepTerminator); + foreach (i; 0 .. min(refLines.length, outLines.length)) + if (outLines[i] != refLines[i]) + { + writeln("Found difference between ", outFileName, " and ", refFileName, " on line ", i + 1, ":"); + writefln("out: %(%s%)", [outLines[i]]); // Wrapping in array shows line endings. + writefln("ref: %(%s%)", [refLines[i]]); + return 1; + } + if (outLines.length < refLines.length) + { + writeln("Line ", outLines.length + 1, " in ", refFileName, " not found in ", outFileName, ":"); + writefln("%(%s%)", [refLines[outLines.length]]); + return 1; + } + if (outLines.length > refLines.length) + { + writeln("Line ", outLines.length + 1, " in ", outFileName, " not present in ", refFileName, ":"); + writefln("%(%s%)", [outLines[refLines.length]]); + return 1; + } + + // As long as dfmt defaults to LF line endings (issue #552) we need an explicit trailing newline check. + // because a) splitLines gives the same number of lines regardless whether the last line ends with a newline, + // and b) when line endings are ignored the trailing endline is of course also ignored. + if (outText.endsWithNewline) + { + if (!refText.endsWithNewline) + { + writeln(outFileName, " ends with a newline, but ", refFileName, " does not."); + return 1; + } + } + else + { + if (refText.endsWithNewline) + { + writeln(refFileName, " ends with a newline, but ", outFileName, " does not."); + return 1; + } + } + } + + foreach (entry; dirEntries("expected_failures", "*.d", SpanMode.shallow)) + if (execute([dfmt, entry]).status == 0) + { + stderr.writeln("Expected failure on test ", entry, " but passed."); + return 1; + } + + writeln("All tests succeeded."); + return 0; +} + +bool endsWithNewline(string text) pure +{ + // Same criteria as https://dlang.org/phobos/std_string.html#.lineSplitter + return + text.endsWith('\n') || + text.endsWith('\r') || + text.endsWith(lineSep) || + text.endsWith(paraSep) || + text.endsWith('\u0085') || + text.endsWith('\v') || + text.endsWith('\f'); +} diff --git a/tests/test.sh b/tests/test.sh index da44e97..88df227 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -26,3 +26,5 @@ do exit 1 fi done + +echo "This script is superseded by test.d." From b8da7c5cd494d19d4baf678054d0cd83bb51f477 Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Fri, 27 May 2022 19:20:57 +0200 Subject: [PATCH 2/2] Refactor courtesy WebFreak001. Co-authored-by: Jan Jurzitza --- tests/test.d | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test.d b/tests/test.d index e4d70d4..43f50d1 100755 --- a/tests/test.d +++ b/tests/test.d @@ -15,8 +15,7 @@ else int main() { foreach (braceStyle; ["allman", "otbs", "knr"]) - foreach (entry; dirEntries(".", "*.d", SpanMode.shallow). - filter!(e => e.baseName(".d") != thisExePath.baseName(".exe"))) + foreach (entry; dirEntries(".", "*.d", SpanMode.shallow).filter!(e => e.baseName(".d") != "test")) { const source = entry.baseName; const outFileName = buildPath(braceStyle, source ~ ".out"); @@ -24,7 +23,7 @@ int main() const argsFile = source.stripExtension ~ ".args"; const dfmtCommand = [dfmt, "--brace_style=" ~ braceStyle] ~ - (argsFile.exists ? readText(argsFile).splitter!isWhite.filter!(a => a.length).array : []) ~ + (argsFile.exists ? readText(argsFile).split : []) ~ [source]; writeln(dfmtCommand.join(" ")); if (const result = spawnProcess(dfmtCommand, stdin, File(outFileName, "w")).wait)