1020304050607080901001101201301401501601701801902002102202302402502602702802903003103203303403503613703803904004104204304404504604704804905005105205305405505605715805916006106206306416516616706806907007107207307407507607707807908008108208308408510862087108808909009109211931194095119609711981199010011101111020103010401050106010701080109011001110112011301140115111611170118111911201121112201232124012533126012710128101290130013121320 /++ A module containing the ProgressReporter This is an example of how this reporter looks <script type="text/javascript" src="https://asciinema.org/a/a3aspcv8cw5l04l59xw9vbtqa.js" id="asciicast-a3aspcv8cw5l04l59xw9vbtqa" async></script> Copyright: © 2017 Szabo Bogdan License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Szabo Bogdan +/ module trial.reporters.progress; import std.stdio; import std.array; import std.conv; import std.datetime; import std.string; import std.algorithm; import trial.interfaces; import trial.reporters.writer; /// struct ProgressGlyphs { version(Windows) { string empty = "."; string fill = "#"; } else { string empty = "░"; string fill = "▓"; } } /// string progressGlyphsToCode(ProgressGlyphs glyphs) { return "ProgressGlyphs(`" ~ glyphs.empty ~ "`,`" ~ glyphs.fill ~ "`)"; } /// The “progress” reporter implements a simple progress-bar class ProgressReporter : ITestCaseLifecycleListener, ILifecycleListener { private { ReportWriter writer; ProgressGlyphs glyphs; ulong testCount; ulong currentTest; bool success = true; } this(ProgressGlyphs glyphs) { writer = defaultWriter; this.glyphs = glyphs; } this(ReportWriter writer) { this.writer = writer; } void begin(ulong testCount) { this.testCount = testCount; writer.writeln(""); draw; } void update() { } void end(SuiteResult[]) { } void begin(string suite, ref TestResult test) { } void end(string suite, ref TestResult test) { currentTest++; success = success && test.status == TestResult.Status.success; draw; } private void draw() { int size = min((writer.width / 4) * 3, testCount); size_t position = ((cast(double) currentTest / cast(double) testCount) * size).to!size_t; writer.goTo(1); writer.write(currentTest.to!string ~ "/" ~ testCount.to!string ~ " ", success ? ReportWriter.Context.active : ReportWriter.Context.danger); writer.write(glyphs.fill.replicate(position), ReportWriter.Context.active); writer.writeln(glyphs.empty.replicate(size - position), ReportWriter.Context.inactive); } } version (unittest) { version(Have_fluent_asserts) { import fluent.asserts; } } @("it should print 10 success tests") unittest { auto writer = new BufferedWriter; auto reporter = new ProgressReporter(writer); auto suite = SuiteResult("some suite"); auto test = new TestResult("some test"); test.status = TestResult.Status.success; reporter.begin(10); writer.buffer.should.equal("0/10 ░░░░░░░░░░\n"); foreach (i; 0 .. 10) { reporter.begin("some suite", test); reporter.end("some suite", test); } writer.buffer.should.equal("10/10 ▓▓▓▓▓▓▓▓▓▓\n"); }
/++ A module containing the ProgressReporter This is an example of how this reporter looks <script type="text/javascript" src="https://asciinema.org/a/a3aspcv8cw5l04l59xw9vbtqa.js" id="asciicast-a3aspcv8cw5l04l59xw9vbtqa" async></script> Copyright: © 2017 Szabo Bogdan License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Szabo Bogdan +/ module trial.reporters.progress; import std.stdio; import std.array; import std.conv; import std.datetime; import std.string; import std.algorithm; import trial.interfaces; import trial.reporters.writer; /// struct ProgressGlyphs { version(Windows) { string empty = "."; string fill = "#"; } else { string empty = "░"; string fill = "▓"; } } /// string progressGlyphsToCode(ProgressGlyphs glyphs) { return "ProgressGlyphs(`" ~ glyphs.empty ~ "`,`" ~ glyphs.fill ~ "`)"; } /// The “progress” reporter implements a simple progress-bar class ProgressReporter : ITestCaseLifecycleListener, ILifecycleListener { private { ReportWriter writer; ProgressGlyphs glyphs; ulong testCount; ulong currentTest; bool success = true; } this(ProgressGlyphs glyphs) { writer = defaultWriter; this.glyphs = glyphs; } this(ReportWriter writer) { this.writer = writer; } void begin(ulong testCount) { this.testCount = testCount; writer.writeln(""); draw; } void update() { } void end(SuiteResult[]) { } void begin(string suite, ref TestResult test) { } void end(string suite, ref TestResult test) { currentTest++; success = success && test.status == TestResult.Status.success; draw; } private void draw() { int size = min((writer.width / 4) * 3, testCount); size_t position = ((cast(double) currentTest / cast(double) testCount) * size).to!size_t; writer.goTo(1); writer.write(currentTest.to!string ~ "/" ~ testCount.to!string ~ " ", success ? ReportWriter.Context.active : ReportWriter.Context.danger); writer.write(glyphs.fill.replicate(position), ReportWriter.Context.active); writer.writeln(glyphs.empty.replicate(size - position), ReportWriter.Context.inactive); } } version (unittest) { version(Have_fluent_asserts) { import fluent.asserts; } } @("it should print 10 success tests") unittest { auto writer = new BufferedWriter; auto reporter = new ProgressReporter(writer); auto suite = SuiteResult("some suite"); auto test = new TestResult("some test"); test.status = TestResult.Status.success; reporter.begin(10); writer.buffer.should.equal("0/10 ░░░░░░░░░░\n"); foreach (i; 0 .. 10) { reporter.begin("some suite", test); reporter.end("some suite", test); } writer.buffer.should.equal("10/10 ▓▓▓▓▓▓▓▓▓▓\n"); }