X-Git-Url: http://nitlanguage.org diff --git a/src/testing/testing_base.nit b/src/testing/testing_base.nit index 62bf57e..e035c9e 100644 --- a/src/testing/testing_base.nit +++ b/src/testing/testing_base.nit @@ -31,11 +31,13 @@ redef class ToolContext var opt_noact = new OptionBool("Does not compile and run tests", "--no-act") # opt --nitc var opt_nitc = new OptionString("nitc compiler to use", "--nitc") + # opt --no-time + var opt_no_time = new OptionBool("Disable time information in XML", "--no-time") # Working directory for testing. fun test_dir: String do var dir = opt_dir.value - if dir == null then return ".nitunit" + if dir == null then return "nitunit.out" return dir end @@ -62,8 +64,8 @@ redef class ToolContext return nitc end - var nit_dir = nit_dir - nitc = nit_dir/"bin/nitc" + var nit_dir = nit_dir or else "." + nitc = nit_dir / "bin/nitc" if not nitc.file_exists then fatal_error(null, "Error: cannot find nitc. Set envvar NIT_DIR or NITC or use the --nitc option.") abort @@ -94,6 +96,83 @@ ulimit -t {{{ulimit_usertime}}} 2> /dev/null # # Default: 10 CPU minute var ulimit_usertime = 600 is writable + + # Show a single-line status to use as a progression. + # + # If `has_progress_bar` is true, then the output is a progress bar. + # The printed the line starts with `'\r'` and is not ended by a `'\n'`. + # So it is expected that: + # * no other output is printed between two calls + # * the last `show_unit_status` is followed by a new-line + # + # If `has_progress_bar` is false, then only the first and last state is shown + fun show_unit_status(name: String, tests: SequenceRead[UnitTest]) + do + var line = "\r\x1B[K==== {name} [" + var done = tests.length + var fails = 0 + for t in tests do + if not t.is_done then + line += " " + done -= 1 + else if t.error == null then + line += ".".green.bold + else + line += "X".red.bold + fails += 1 + end + end + + if not has_progress_bar then + if done == 0 then + print "==== {name} | tests: {tests.length}" + end + return + end + + if done < tests.length then + line += "] {done}/{tests.length}" + else + line += "] tests: {tests.length} " + if fails == 0 then + line += "OK".green.bold + else + line += "KO: {fails}".red.bold + end + end + printn "{line}" + end + + # Is a progress bar printed? + # + # true if color (because and non-verbose mode + # (because verbose mode messes up with the progress bar). + fun has_progress_bar: Bool + do + return not opt_no_color.value and opt_verbose.value <= 0 + end + + # Clear the line if `has_progress_bar` (no-op else) + fun clear_progress_bar + do + if has_progress_bar then printn "\r\x1B[K" + end + + # Show the full description of the test-case. + # + # The output honors `--no-color`. + # + # `more message`, if any, is added after the error message. + fun show_unit(test: UnitTest, more_message: nullable String) do + print test.to_screen(more_message, not opt_no_color.value) + end + + # Set the `NIT_TESTING_PATH` environment variable with `path`. + # + # If `path == null` then `NIT_TESTING_PATH` is set with the empty string. + fun set_testing_path(path: nullable String) do + "NIT_TESTING_PATH".setenv(path or else "") + end end # A unit test is an elementary test discovered, run and reported by nitunit. @@ -127,34 +206,54 @@ abstract class UnitTest # The location where the error occurred, if it makes sense. var error_location: nullable Location = null is writable + # Additional noteworthy information when a test success. + var info: nullable String = null + + # Time for the execution, in seconds + var real_time: Float = 0.0 is writable + # A colorful `[OK]` or `[KO]`. - fun status_tag: String do + fun status_tag(color: nullable Bool): String do + color = color or else true if not is_done then return "[ ]" else if error != null then - return "[KO]".red.bold + var res = "[KO]" + if color then res = res.red.bold + return res else - return "[OK]".green.bold + var res = "[OK]" + if color then res = res.green.bold + return res end end # The full (color) description of the test-case. # # `more message`, if any, is added after the error message. - fun to_screen(more_message: nullable String): String do + fun to_screen(more_message: nullable String, color: nullable Bool): String do + color = color or else true var res var error = self.error if error != null then if more_message != null then error += " " + more_message var loc = error_location or else location - res = "{status_tag} {full_name}\n {loc.to_s.yellow}: {error}\n{loc.colored_line("1;31")}" + if color then + res = "{status_tag(color)} {full_name}\n {loc.to_s.yellow}: {error}\n{loc.colored_line("1;31")}" + else + res = "{status_tag(color)} {full_name}\n {loc}: {error}" + end var output = self.raw_output if output != null then res += "\n Output\n\t{output.chomp.replace("\n", "\n\t")}\n" end else - res = "{status_tag} {full_name}" + res = "{status_tag(color)} {full_name}" if more_message != null then res += more_message + var info = self.info + if info != null then + res += "\n {info}" + end end return res end @@ -164,17 +263,23 @@ abstract class UnitTest var tc = new HTMLTag("testcase") tc.attr("classname", xml_classname) tc.attr("name", xml_name) + tc.attr("time", real_time.to_s) + + var output = self.raw_output + if output != null then output = output.trunc(8192).filter_nonprintable var error = self.error if error != null then + var node if was_exec then - tc.open("error").append(error) + node = tc.open("error").attr("message", error) else - tc.open("failure").append(error) + node = tc.open("failure").attr("message", error) end - end - var output = self.raw_output - if output != null then - tc.open("system-err").append(output.trunc(8192).filter_nonprintable) + if output != null then + node.append(output) + end + else if output != null then + tc.open("system-err").append(output) end return tc end