diff --git a/tests/test.d b/tests/test.d new file mode 100755 index 0000000..43f50d1 --- /dev/null +++ b/tests/test.d @@ -0,0 +1,103 @@ +#!/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") != "test")) + { + 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).split : []) ~ + [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."