Merge: make nitunit more colorful (and useful?)
authorJean Privat <jean@pryen.org>
Thu, 26 May 2016 13:06:39 +0000 (09:06 -0400)
committerJean Privat <jean@pryen.org>
Thu, 26 May 2016 13:06:39 +0000 (09:06 -0400)
This series move more information in the UnitTest class, this allow specific and unified way of displaying the test results.

See the asciinema: https://asciinema.org/a/108jd2a3tkfifg3wzoacg0a65

Comments? Needs? Ideas?

Pull-Request: #2121
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

src/testing/testing_base.nit
src/testing/testing_doc.nit
src/testing/testing_suite.nit
tests/sav/nitunit_args1.res
tests/sav/nitunit_args4.res
tests/sav/nitunit_args5.res
tests/sav/nitunit_args6.res
tests/sav/nitunit_args7.res
tests/sav/nitunit_args8.res
tests/sav/nitunit_args9.res
tests/test_nitunit.nit

index 4249df5..88651ef 100644 (file)
@@ -18,6 +18,7 @@ module testing_base
 import modelize
 private import parser_util
 import html
+import console
 
 redef class ToolContext
        # opt --full
@@ -93,22 +94,101 @@ 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.
+       #
+       # Note that 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
+       fun show_unit_status(name: String, tests: SequenceRead[UnitTest], more_message: nullable String)
+       do
+               var esc = 27.code_point.to_s
+               var line = "\r{esc}[K* {name} ["
+               var done = tests.length
+               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
+                       end
+               end
+               line += "] {done}/{tests.length}"
+               if more_message != null then
+                       line += " " + more_message
+               end
+               printn "{line}"
+       end
+
 end
 
-# A unit test is an elementary test discovered, run and reported bu nitunit.
+# A unit test is an elementary test discovered, run and reported by nitunit.
 #
 # This class factorizes `DocUnit` and `TestCase`.
 abstract class UnitTest
+       # The name of the unit to show in messages
+       fun full_name: String is abstract
+
+       # The location of the unit test to show in messages.
+       fun location: Location is abstract
 
-       # Error occurred during test-case execution.
+       # Flag that indicates if the unit test was compiled/run.
+       var is_done: Bool = false is writable
+
+       # Error message occurred during test-case execution (or compilation).
+       #
+       # e.g.: `Runtime Error`
        var error: nullable String = null is writable
 
        # Was the test case executed at least once?
+       #
+       # This will indicate the status of the test (failture or error)
        var was_exec = false is writable
 
-       # Return the `TestCase` in XML format compatible with Jenkins.
+       # The raw output of the execution (or compilation)
        #
-       # See to_xml
+       # It merges the standard output and error output
+       var raw_output: nullable String = null is writable
+
+       # The location where the error occurred, if it makes sense.
+       var error_location: nullable Location = null is writable
+
+       # A colorful `[OK]` or `[KO]`.
+       fun status_tag: String do
+               if not is_done then
+                       return "[  ]"
+               else if error != null then
+                       return "[KO]".red.bold
+               else
+                       return "[OK]".green.bold
+               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
+               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")}"
+                       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}"
+                       if more_message != null then res += more_message
+               end
+               return res
+       end
+
+       # Return a `<testcase>` XML node in format compatible with Jenkins unit tests.
        fun to_xml: HTMLTag do
                var tc = new HTMLTag("testcase")
                tc.attr("classname", xml_classname)
@@ -116,11 +196,14 @@ abstract class UnitTest
                var error = self.error
                if error != null then
                        if was_exec then
-                               tc.open("error").append("Runtime Error")
+                               tc.open("error").append(error)
                        else
-                               tc.open("failure").append("Compilation Error")
+                               tc.open("failure").append(error)
                        end
-                       tc.open("system-err").append(error.trunc(8192).filter_nonprintable)
+               end
+               var output = self.raw_output
+               if output != null then
+                       tc.open("system-err").append(output.trunc(8192).filter_nonprintable)
                end
                return tc
        end
@@ -128,6 +211,8 @@ abstract class UnitTest
        # The `classname` attribute of the XML format.
        #
        # NOTE: jenkins expects a '.' in the classname attr
+       #
+       # See to_xml
        fun xml_classname: String is abstract
 
        # The `name` attribute of the XML format.
index 1ea2cf7..2465d37 100644 (file)
@@ -36,6 +36,9 @@ class NitUnitExecutor
        # The XML node associated to the module
        var testsuite: HTMLTag
 
+       # The name of the suite
+       var name: String
+
        # Markdown processor used to parse markdown comments and extract code.
        var mdproc = new MarkdownProcessor
 
@@ -70,20 +73,37 @@ class NitUnitExecutor
 
                # Populate `blocks` from the markdown decorator
                mdproc.process(mdoc.content.join("\n"))
-
-               toolcontext.check_errors
        end
 
        # All extracted docunits
        var docunits = new Array[DocUnit]
 
+       fun show_status(more_message: nullable String)
+       do
+               toolcontext.show_unit_status(name, docunits, more_message)
+       end
+
+       fun mark_done(du: DocUnit)
+       do
+               du.is_done = true
+               show_status(du.full_name + " " + du.status_tag)
+       end
+
        # Execute all the docunits
        fun run_tests
        do
+               if docunits.is_empty then
+                       return
+               end
+
                var simple_du = new Array[DocUnit]
+               show_status
                for du in docunits do
                        # Skip existing errors
-                       if du.error != null then continue
+                       if du.error != null then
+                               mark_done(du)
+                               continue
+                       end
 
                        var ast = toolcontext.parse_something(du.block)
                        if ast isa AExpr then
@@ -95,6 +115,13 @@ class NitUnitExecutor
 
                test_simple_docunits(simple_du)
 
+               show_status
+               print ""
+
+               for du in docunits do
+                       print du.to_screen
+               end
+
                for du in docunits do
                        testsuite.add du.to_xml
                end
@@ -149,16 +176,16 @@ class NitUnitExecutor
                        i += 1
                        toolcontext.info("Execute doc-unit {du.full_name} in {file} {i}", 1)
                        var res2 = toolcontext.safe_exec("{file.to_program_name}.bin {i} >'{file}.out1' 2>&1 </dev/null")
+                       du.was_exec = true
 
                        var content = "{file}.out1".to_path.read_all
-                       var msg = content.trunc(8192).filter_nonprintable
+                       du.raw_output = content
 
                        if res2 != 0 then
-                               du.error = content
-                               toolcontext.warning(du.location, "error", "ERROR: {du.full_name} (in {file}): Runtime error\n{msg}")
+                               du.error = "Runtime error in {file} with argument {i}"
                                toolcontext.modelbuilder.failed_entities += 1
                        end
-                       toolcontext.check_errors
+                       mark_done(du)
                end
        end
 
@@ -182,20 +209,20 @@ class NitUnitExecutor
                var res2 = 0
                if res == 0 then
                        res2 = toolcontext.safe_exec("{file.to_program_name}.bin >'{file}.out1' 2>&1 </dev/null")
+                       du.was_exec = true
                end
 
                var content = "{file}.out1".to_path.read_all
-               var msg = content.trunc(8192).filter_nonprintable
+               du.raw_output = content
 
                if res != 0 then
-                       du.error = content
-                       toolcontext.warning(du.location, "failure", "FAILURE: {du.full_name} (in {file}):\n{msg}")
+                       du.error = "Compilation error in {file}"
                        toolcontext.modelbuilder.failed_entities += 1
                else if res2 != 0 then
-                       toolcontext.warning(du.location, "error", "ERROR: {du.full_name} (in {file}):\n{msg}")
+                       du.error = "Runtime error in {file}"
                        toolcontext.modelbuilder.failed_entities += 1
                end
-               toolcontext.check_errors
+               mark_done(du)
        end
 
        # Create and fill the header of a unit file `file`.
@@ -287,12 +314,11 @@ private class NitunitDecorator
                                message = "Error: Invalid Nit code."
                        end
 
-                       executor.toolcontext.warning(location, "invalid-block", "{message} To suppress this message, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).")
-                       executor.toolcontext.modelbuilder.failed_entities += 1
-
                        var du = new_docunit
                        du.block += code
-                       du.error = "{location}: {message}"
+                       du.error_location = location
+                       du.error = message
+                       executor.toolcontext.modelbuilder.failed_entities += 1
                        return
                end
 
@@ -350,11 +376,13 @@ class DocUnit
        # The numbering of self in mdoc (starting with 0)
        var number: Int
 
-       # The name of the unit to show in messages
-       fun full_name: String do
+       redef fun full_name do
                var mentity = mdoc.original_mentity
-               if mentity != null then return mentity.full_name
-               return xml_classname + "." + xml_name
+               if mentity != null then
+                       return mentity.full_name
+               else
+                       return xml_classname + "." + xml_name
+               end
        end
 
        # The text of the code to execute.
@@ -376,7 +404,7 @@ class DocUnit
        #
        # If `self` is made of multiple code-blocks, then the location
        # starts at the first code-books and finish at the last one, thus includes anything between.
-       var location: Location is lazy do
+       redef var location is lazy do
                return new Location(mdoc.location.file, lines.first, lines.last+1, columns.first+1, 0)
        end
 
@@ -442,7 +470,7 @@ redef class ModelBuilder
 
                var prefix = toolcontext.test_dir
                prefix = prefix.join_path(mmodule.to_s)
-               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts)
+               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of module {mmodule.full_name}")
 
                do
                        total_entities += 1
@@ -496,7 +524,7 @@ redef class ModelBuilder
 
                var prefix = toolcontext.test_dir
                prefix = prefix.join_path(mgroup.to_s)
-               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts)
+               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of group {mgroup.full_name}")
 
                total_entities += 1
                var mdoc = mgroup.mdoc
@@ -522,7 +550,7 @@ redef class ModelBuilder
                ts.attr("package", file)
 
                var prefix = toolcontext.test_dir / "file"
-               var d2m = new NitUnitExecutor(toolcontext, prefix, null, ts)
+               var d2m = new NitUnitExecutor(toolcontext, prefix, null, ts, "Docunits of file {file}")
 
                total_entities += 1
                doc_entities += 1
index ee2701f..bbe9372 100644 (file)
@@ -132,8 +132,14 @@ class TestSuite
        # Test to be executed after the whole test suite.
        var after_module: nullable TestCase = null
 
+       fun show_status(more_message: nullable String)
+       do
+               toolcontext.show_unit_status("Test-suite of module " + mmodule.full_name, test_cases, more_message)
+       end
+
        # Execute the test suite
        fun run do
+               show_status
                if not toolcontext.test_dir.file_exists then
                        toolcontext.test_dir.mkdir
                end
@@ -142,9 +148,19 @@ class TestSuite
                toolcontext.info("Execute test-suite {mmodule.name}", 1)
                var before_module = self.before_module
                if not before_module == null then before_module.run
-               for case in test_cases do case.run
+               for case in test_cases do
+                       case.run
+                       show_status(case.full_name + " " + case.status_tag)
+               end
+
+               show_status
+               print ""
+
                var after_module = self.after_module
                if not after_module == null then after_module.run
+               for case in test_cases do
+                       print case.to_screen
+               end
        end
 
        # Write the test unit for `self` in a nit compilable file.
@@ -222,6 +238,10 @@ class TestCase
        # Test method to be compiled and tested.
        var test_method: MMethodDef
 
+       redef fun full_name do return test_method.full_name
+
+       redef fun location do return test_method.location
+
        # `ToolContext` to use to display messages and find `nitc` bin.
        var toolcontext: ToolContext
 
@@ -250,17 +270,13 @@ class TestCase
                var test_file = test_suite.test_file
                var res_name = "{test_file}_{method_name.escape_to_c}"
                var res = toolcontext.safe_exec("{test_file}.bin {method_name} > '{res_name}.out1' 2>&1 </dev/null")
-               var f = new FileReader.open("{res_name}.out1")
-               var msg = f.read_all
-               f.close
+               self.raw_output = "{res_name}.out1".to_path.read_all
                # set test case result
-               var loc = test_method.location
                if res != 0 then
-                       error = msg
-                       toolcontext.warning(loc, "failure",
-                          "ERROR: {method_name} (in file {test_file}.nit): {msg}")
+                       error = "Runtime Error in file {test_file}.nit"
                        toolcontext.modelbuilder.failed_tests += 1
                else
+                       # no error, check with res file, if any.
                        var mmodule = test_method.mclassdef.mmodule
                        var file = mmodule.filepath
                        if file != null then
@@ -269,10 +285,8 @@ class TestCase
                                        toolcontext.info("Diff output with {sav}", 1)
                                        res = toolcontext.safe_exec("diff -u --label 'expected:{sav}' --label 'got:{res_name}.out1' '{sav}' '{res_name}.out1' > '{res_name}.diff' 2>&1 </dev/null")
                                        if res != 0 then
-                                               msg = "Diff\n" + "{res_name}.diff".to_path.read_all
-                                               error = msg
-                                               toolcontext.warning(loc, "failure",
-                                               "ERROR: {method_name} (in file {test_file}.nit): {msg}")
+                                               self.raw_output = "Diff\n" + "{res_name}.diff".to_path.read_all
+                                               error = "Difference with expected output: diff -u {sav} {res_name}.out1"
                                                toolcontext.modelbuilder.failed_tests += 1
                                        end
                                else
@@ -280,7 +294,7 @@ class TestCase
                                end
                        end
                end
-               toolcontext.check_errors
+               is_done = true
        end
 
        redef fun xml_classname do
index 48642c1..cbfe0bc 100644 (file)
@@ -1,19 +1,43 @@
-test_nitunit.nit:21,7--22,0: ERROR: test_nitunit$X (in .nitunit/test_nitunit-2.nit):
-Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
+\r\e[K* Docunits of module test_nitunit::test_nitunit [    ] 0/4\r\e[K* Docunits of module test_nitunit::test_nitunit [   \e[1m\e[31mX\e[m\e[m] 1/4 test_nitunit$X$foo1 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_nitunit::test_nitunit [\e[1m\e[32m.\e[m\e[m  \e[1m\e[31mX\e[m\e[m] 2/4 test_nitunit::test_nitunit \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_nitunit::test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m \e[1m\e[31mX\e[m\e[m] 3/4 test_nitunit$X \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_nitunit::test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 4/4 test_nitunit$X$foo \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_nitunit::test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 4/4
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit::test_nitunit
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit$X
+     \e[33mtest_nitunit.nit:21,7--22,0\e[m: Runtime error in .nitunit/test_nitunit-2.nit
+       #     \e[1;31massert false\e[0m
+             ^
+     Output
+       Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
 
-test_nitunit.nit:24,8--25,0: FAILURE: test_nitunit$X$foo (in .nitunit/test_nitunit-3.nit):
-.nitunit/test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit$X$foo
+     \e[33mtest_nitunit.nit:24,8--25,0\e[m: Compilation error in .nitunit/test_nitunit-3.nit
+               #     \e[1;31massert undefined_identifier\e[0m
+                     ^
+     Output
+       .nitunit/test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
 
-test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/gen_test_test_nitunit.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit$X$foo1
+     \e[33mtest_nitunit.nit:28,15\e[m: Syntax Error: unexpected operator '!'.
+               #     assert \e[1;31m!\e[0m@#$%^&*()
+                            ^
+\r\e[K* Test-suite of module test_test_nitunit::test_test_nitunit [   ] 0/3\r\e[K* Test-suite of module test_test_nitunit::test_test_nitunit [\e[1m\e[32m.\e[m\e[m  ] 1/3 test_test_nitunit$TestX$test_foo \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Test-suite of module test_test_nitunit::test_test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m ] 2/3 test_test_nitunit$TestX$test_foo1 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Test-suite of module test_test_nitunit::test_test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3 test_test_nitunit$TestX$test_foo2 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Test-suite of module test_test_nitunit::test_test_nitunit [\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3
+\e[1m\e[32m[OK]\e[m\e[m test_test_nitunit$TestX$test_foo
+\e[1m\e[31m[KO]\e[m\e[m test_test_nitunit$TestX$test_foo1
+     \e[33mtest_test_nitunit.nit:36,2--40,4\e[m: Runtime Error in file .nitunit/gen_test_test_nitunit.nit
+               \e[1;31m# will fail\e[0m
+               ^
+     Output
+       Runtime error: Assert failed (test_test_nitunit.nit:39)
 
+\e[1m\e[32m[OK]\e[m\e[m test_test_nitunit$TestX$test_foo2
 DocUnits:
-Entities: 27; Documented ones: 3; With nitunits: 3; Failures: 2
+Entities: 27; Documented ones: 4; With nitunits: 4; Failures: 3
 
 TestSuites:
 Class suites: 1; Test Cases: 3; Failures: 1
-<testsuites><testsuite package="test_nitunit::test_nitunit"><testcase classname="nitunit.test_nitunit::test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-out>assert true
-</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-out>assert false
-</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><failure>Compilation Error</failure><system-err>.nitunit&#47;test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
+<testsuites><testsuite package="test_nitunit::test_nitunit"><testcase classname="nitunit.test_nitunit::test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
+</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="&lt;class&gt;"><error>Runtime error in .nitunit&#47;test_nitunit-2.nit</error><system-err>Runtime error: Assert failed (.nitunit&#47;test_nitunit-2.nit:5)
+</system-err><system-out>assert false
+</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><failure>Compilation error in .nitunit&#47;test_nitunit-3.nit</failure><system-err>.nitunit&#47;test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
 </system-err><system-out>assert undefined_identifier
-</system-out></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><error>Runtime Error</error><system-err>Runtime error: Assert failed (test_test_nitunit.nit:39)
-</system-err></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"></testcase></testsuite></testsuites>
\ No newline at end of file
+</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo1"><failure>Syntax Error: unexpected operator &#39;!&#39;.</failure><system-out>assert !@#$%^&amp;*()
+</system-out></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><error>Runtime Error in file .nitunit&#47;gen_test_test_nitunit.nit</error><system-err>Runtime error: Assert failed (test_test_nitunit.nit:39)
+</system-err></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err></testcase></testsuite></testsuites>
\ No newline at end of file
index 4cb3aaa..95b3751 100644 (file)
@@ -1,3 +1,7 @@
+\r\e[K* Docunits of module test_nitunit2::test_nitunit2 [   ] 0/3\r\e[K* Docunits of module test_nitunit2::test_nitunit2 [\e[1m\e[32m.\e[m\e[m  ] 1/3 test_nitunit2::test_nitunit2$core::Sys$foo1 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_nitunit2::test_nitunit2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m ] 2/3 test_nitunit2::test_nitunit2$core::Sys$bar2 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_nitunit2::test_nitunit2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3 test_nitunit2::test_nitunit2$core::Sys$foo3 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_nitunit2::test_nitunit2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit2::test_nitunit2$core::Sys$foo1
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit2::test_nitunit2$core::Sys$bar2
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit2::test_nitunit2$core::Sys$foo3
 DocUnits:
 DocUnits Success
 Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
@@ -5,17 +9,17 @@ Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_nitunit2::test_nitunit2"><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::foo1"><system-out>if true then
+<testsuites><testsuite package="test_nitunit2::test_nitunit2"><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::foo1"><system-err></system-err><system-out>if true then
 
    assert true
 
 end
-</system-out></testcase><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::bar2"><system-out>if true then
+</system-out></testcase><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::bar2"><system-err></system-err><system-out>if true then
 
     assert true
 
 end
-</system-out></testcase><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::foo3"><system-out>var a = 1
+</system-out></testcase><testcase classname="nitunit.test_nitunit2::test_nitunit2.core::Sys" name="test_nitunit2::test_nitunit2::Sys::foo3"><system-err></system-err><system-out>var a = 1
 assert a == 1
 assert a == 1
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index 8fa1c3c..f161044 100644 (file)
@@ -1,3 +1,7 @@
+\r\e[K* Docunits of module test_doc2::test_doc2 [   ] 0/3\r\e[K* Docunits of module test_doc2::test_doc2 [\e[1m\e[32m.\e[m\e[m  ] 1/3 test_doc2::test_doc2$core::Sys$foo1 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_doc2::test_doc2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m ] 2/3 test_doc2::test_doc2$core::Sys$foo2 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_doc2::test_doc2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3 test_doc2::test_doc2$core::Sys$foo3 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_doc2::test_doc2 [\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[32m.\e[m\e[m] 3/3
+\e[1m\e[32m[OK]\e[m\e[m test_doc2::test_doc2$core::Sys$foo1
+\e[1m\e[32m[OK]\e[m\e[m test_doc2::test_doc2$core::Sys$foo2
+\e[1m\e[32m[OK]\e[m\e[m test_doc2::test_doc2$core::Sys$foo3
 DocUnits:
 DocUnits Success
 Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
@@ -5,7 +9,7 @@ Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_doc2::test_doc2"><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo1"><system-out>assert true # tested
-</system-out></testcase><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo2"><system-out>assert true # tested
-</system-out></testcase><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo3"><system-out>assert true # tested
+<testsuites><testsuite package="test_doc2::test_doc2"><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo1"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo2"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2::test_doc2.core::Sys" name="test_doc2::test_doc2::Sys::foo3"><system-err></system-err><system-out>assert true # tested
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index ca7ee6a..13ff875 100644 (file)
@@ -1,16 +1,27 @@
-test_nitunit3/README.md:7,3--5: Syntax Error: unexpected malformed character '\]. To suppress this message, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).
-test_nitunit3/README.md:4,2--15,0: ERROR: test_nitunit3> (in .nitunit/test_nitunit3-0.nit): Runtime error
-Runtime error: Assert failed (.nitunit/test_nitunit3-0.nit:7)
+\r\e[K* Docunits of group test_nitunit3> [  ] 0/2\r\e[K* Docunits of group test_nitunit3> [ \e[1m\e[31mX\e[m\e[m] 1/2 test_nitunit3> \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of group test_nitunit3> [\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 2/2 test_nitunit3> \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of group test_nitunit3> [\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 2/2
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit3>
+     \e[33mtest_nitunit3/README.md:4,2--15,0\e[m: Runtime error in .nitunit/test_nitunit3-0.nit with argument 1
+       ~\e[1;31m~\e[0m
+        ^
+     Output
+       Runtime error: Assert failed (.nitunit/test_nitunit3-0.nit:7)
 
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit3>
+     \e[33mtest_nitunit3/README.md:7,3--5\e[m: Syntax Error: unexpected malformed character '\].
+       ~~\e[1;31m~
+;\e[0m
+         ^
+\r\e[K* Docunits of module test_nitunit3::test_nitunit3 [ ] 0/1\r\e[K* Docunits of module test_nitunit3::test_nitunit3 [\e[1m\e[32m.\e[m\e[m] 1/1 test_nitunit3::test_nitunit3 \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Docunits of module test_nitunit3::test_nitunit3 [\e[1m\e[32m.\e[m\e[m] 1/1
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit3::test_nitunit3
 DocUnits:
 Entities: 2; Documented ones: 2; With nitunits: 3; Failures: 2
 
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_nitunit3&gt;"><testcase classname="nitunit.test_nitunit3&gt;" name="&lt;group&gt;"><failure>Compilation Error</failure><system-err>Runtime error: Assert failed (.nitunit&#47;test_nitunit3-0.nit:7)
+<testsuites><testsuite package="test_nitunit3&gt;"><testcase classname="nitunit.test_nitunit3&gt;" name="&lt;group&gt;"><error>Runtime error in .nitunit&#47;test_nitunit3-0.nit with argument 1</error><system-err>Runtime error: Assert failed (.nitunit&#47;test_nitunit3-0.nit:7)
 </system-err><system-out>assert false
 assert true
-</system-out></testcase><testcase classname="nitunit.test_nitunit3&gt;" name="&lt;group&gt;+1"><failure>Compilation Error</failure><system-err>test_nitunit3&#47;README.md:7,3--5: Syntax Error: unexpected malformed character &#39;\].</system-err><system-out>;&#39;\][]
-</system-out></testcase></testsuite><testsuite package="test_nitunit3::test_nitunit3"><testcase classname="nitunit.test_nitunit3::test_nitunit3.&lt;module&gt;" name="&lt;module&gt;"><system-out>assert true
+</system-out></testcase><testcase classname="nitunit.test_nitunit3&gt;" name="&lt;group&gt;+1"><failure>Syntax Error: unexpected malformed character &#39;\].</failure><system-out>;&#39;\][]
+</system-out></testcase></testsuite><testsuite package="test_nitunit3::test_nitunit3"><testcase classname="nitunit.test_nitunit3::test_nitunit3.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index 0888b04..bf0c504 100644 (file)
@@ -1,5 +1,10 @@
-test_nitunit_md.md:4,2--16,0: ERROR: nitunit.<file>.test_nitunit_md.md:1,0--15,0 (in .nitunit/file-0.nit): Runtime error
-Runtime error: Assert failed (.nitunit/file-0.nit:8)
+\r\e[K* Docunits of file test_nitunit_md.md:1,0--15,0 [ ] 0/1\r\e[K* Docunits of file test_nitunit_md.md:1,0--15,0 [\e[1m\e[31mX\e[m\e[m] 1/1 nitunit.<file>.test_nitunit_md.md:1,0--15,0 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of file test_nitunit_md.md:1,0--15,0 [\e[1m\e[31mX\e[m\e[m] 1/1
+\e[1m\e[31m[KO]\e[m\e[m nitunit.<file>.test_nitunit_md.md:1,0--15,0
+     \e[33mtest_nitunit_md.md:4,2--16,0\e[m: Runtime error in .nitunit/file-0.nit with argument 1
+       ~\e[1;31m~\e[0m
+        ^
+     Output
+       Runtime error: Assert failed (.nitunit/file-0.nit:8)
 
 DocUnits:
 Entities: 1; Documented ones: 1; With nitunits: 1; Failures: 1
@@ -7,7 +12,7 @@ Entities: 1; Documented ones: 1; With nitunits: 1; Failures: 1
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_nitunit_md.md:1,0--15,0"><testcase classname="nitunit.&lt;file&gt;" name="test_nitunit_md.md:1,0--15,0"><failure>Compilation Error</failure><system-err>Runtime error: Assert failed (.nitunit&#47;file-0.nit:8)
+<testsuites><testsuite package="test_nitunit_md.md:1,0--15,0"><testcase classname="nitunit.&lt;file&gt;" name="test_nitunit_md.md:1,0--15,0"><error>Runtime error in .nitunit&#47;file-0.nit with argument 1</error><system-err>Runtime error: Assert failed (.nitunit&#47;file-0.nit:8)
 </system-err><system-out>var a = 1
 assert 1 == 1
 assert false
index afa1ac3..c3e9bf7 100644 (file)
@@ -1,13 +1,23 @@
-test_doc3.nit:17,9--15: Syntax Error: unexpected identifier 'garbage'. To suppress this message, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).
-test_doc3.nit:23,4--10: Syntax Error: unexpected identifier 'garbage'. To suppress this message, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).
-test_doc3.nit:30,4--10: Syntax Error: unexpected identifier 'garbage'. To suppress this message, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).
+\r\e[K* Docunits of module test_doc3::test_doc3 [   ] 0/3\r\e[K* Docunits of module test_doc3::test_doc3 [\e[1m\e[31mX\e[m\e[m  ] 1/3 test_doc3::test_doc3$core::Sys$foo1 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_doc3::test_doc3 [\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m ] 2/3 test_doc3::test_doc3$core::Sys$foo2 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_doc3::test_doc3 [\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 3/3 test_doc3::test_doc3$core::Sys$foo3 \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Docunits of module test_doc3::test_doc3 [\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m\e[1m\e[31mX\e[m\e[m] 3/3
+\e[1m\e[31m[KO]\e[m\e[m test_doc3::test_doc3$core::Sys$foo1
+     \e[33mtest_doc3.nit:17,9--15\e[m: Syntax Error: unexpected identifier 'garbage'.
+       #      *\e[1;31mgarbage\e[0m*
+               ^
+\e[1m\e[31m[KO]\e[m\e[m test_doc3::test_doc3$core::Sys$foo2
+     \e[33mtest_doc3.nit:23,4--10\e[m: Syntax Error: unexpected identifier 'garbage'.
+       # *\e[1;31mgarbage\e[0m*
+          ^
+\e[1m\e[31m[KO]\e[m\e[m test_doc3::test_doc3$core::Sys$foo3
+     \e[33mtest_doc3.nit:30,4--10\e[m: Syntax Error: unexpected identifier 'garbage'.
+       # *\e[1;31mgarbage\e[0m*
+          ^
 DocUnits:
 Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 3
 
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_doc3::test_doc3"><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo1"><failure>Compilation Error</failure><system-err>test_doc3.nit:17,9--15: Syntax Error: unexpected identifier &#39;garbage&#39;.</system-err><system-out> *garbage*
-</system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo2"><failure>Compilation Error</failure><system-err>test_doc3.nit:23,4--10: Syntax Error: unexpected identifier &#39;garbage&#39;.</system-err><system-out>*garbage*
-</system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo3"><failure>Compilation Error</failure><system-err>test_doc3.nit:30,4--10: Syntax Error: unexpected identifier &#39;garbage&#39;.</system-err><system-out>*garbage*
+<testsuites><testsuite package="test_doc3::test_doc3"><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo1"><failure>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out> *garbage*
+</system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo2"><failure>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out>*garbage*
+</system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo3"><failure>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out>*garbage*
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index 27d74a9..5806e40 100644 (file)
@@ -1,16 +1,28 @@
-test_nitunit4/test_nitunit4.nit:22,2--26,4: ERROR: test_foo (in file .nitunit/gen_test_nitunit4.nit): Before Test
-Tested method
-After Test
-Runtime error: Assert failed (test_nitunit4/test_nitunit4_base.nit:31)
+\r\e[K* Test-suite of module test_nitunit4::test_nitunit4 [   ] 0/3\r\e[K* Test-suite of module test_nitunit4::test_nitunit4 [\e[1m\e[31mX\e[m\e[m  ] 1/3 test_nitunit4$TestTestSuite$test_foo \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Test-suite of module test_nitunit4::test_nitunit4 [\e[1m\e[31mX\e[m\e[m\e[1m\e[32m.\e[m\e[m ] 2/3 test_nitunit4$TestTestSuite$test_bar \e[1m\e[32m[OK]\e[m\e[m\r\e[K* Test-suite of module test_nitunit4::test_nitunit4 [\e[1m\e[31mX\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m] 3/3 test_nitunit4$TestTestSuite$test_baz \e[1m\e[31m[KO]\e[m\e[m\r\e[K* Test-suite of module test_nitunit4::test_nitunit4 [\e[1m\e[31mX\e[m\e[m\e[1m\e[32m.\e[m\e[m\e[1m\e[31mX\e[m\e[m] 3/3
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit4$TestTestSuite$test_foo
+     \e[33mtest_nitunit4/test_nitunit4.nit:22,2--26,4\e[m: Runtime Error in file .nitunit/gen_test_nitunit4.nit
+               \e[1;31mfun test_foo do\e[0m
+               ^
+     Output
+       Before Test
+       Tested method
+       After Test
+       Runtime error: Assert failed (test_nitunit4/test_nitunit4_base.nit:31)
 
-test_nitunit4/test_nitunit4.nit:32,2--34,4: ERROR: test_baz (in file .nitunit/gen_test_nitunit4.nit): Diff
---- expected:test_nitunit4/test_nitunit4.sav/test_baz.res
-+++ got:.nitunit/gen_test_nitunit4_test_baz.out1
-@@ -1 +1,3 @@
--Bad result file
-+Before Test
-+Tested method
-+After Test
+\e[1m\e[32m[OK]\e[m\e[m test_nitunit4$TestTestSuite$test_bar
+\e[1m\e[31m[KO]\e[m\e[m test_nitunit4$TestTestSuite$test_baz
+     \e[33mtest_nitunit4/test_nitunit4.nit:32,2--34,4\e[m: Difference with expected output: diff -u test_nitunit4/test_nitunit4.sav/test_baz.res .nitunit/gen_test_nitunit4_test_baz.out1
+               \e[1;31mfun test_baz do\e[0m
+               ^
+     Output
+       Diff
+       --- expected:test_nitunit4/test_nitunit4.sav/test_baz.res
+       +++ got:.nitunit/gen_test_nitunit4_test_baz.out1
+       @@ -1 +1,3 @@
+       -Bad result file
+       +Before Test
+       +Tested method
+       +After Test
 
 DocUnits:
 No doc units found
@@ -18,11 +30,14 @@ Entities: 12; Documented ones: 0; With nitunits: 0; Failures: 0
 
 TestSuites:
 Class suites: 1; Test Cases: 3; Failures: 2
-<testsuites><testsuite package="test_nitunit4&gt;"></testsuite><testsuite package="test_nitunit4::nitunit4"></testsuite><testsuite package="test_nitunit4"><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_foo"><error>Runtime Error</error><system-err>Before Test
+<testsuites><testsuite package="test_nitunit4&gt;"></testsuite><testsuite package="test_nitunit4::nitunit4"></testsuite><testsuite package="test_nitunit4"><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_foo"><error>Runtime Error in file .nitunit&#47;gen_test_nitunit4.nit</error><system-err>Before Test
 Tested method
 After Test
 Runtime error: Assert failed (test_nitunit4&#47;test_nitunit4_base.nit:31)
-</system-err></testcase><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_bar"></testcase><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_baz"><error>Runtime Error</error><system-err>Diff
+</system-err></testcase><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_bar"><system-err>Before Test
+Tested method
+After Test
+</system-err></testcase><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_baz"><error>Difference with expected output: diff -u test_nitunit4&#47;test_nitunit4.sav&#47;test_baz.res .nitunit&#47;gen_test_nitunit4_test_baz.out1</error><system-err>Diff
 --- expected:test_nitunit4&#47;test_nitunit4.sav&#47;test_baz.res
 +++ got:.nitunit&#47;gen_test_nitunit4_test_baz.out1
 @@ -1 +1,3 @@
index b583197..d260cd1 100644 (file)
@@ -24,6 +24,8 @@ class X
        #     assert undefined_identifier
        fun foo do end
 
+       # a 'failure' unit test (does not parse)
+       #     assert !@#$%^&*()
        fun foo1(a, b: Int) do end
 
        private fun foo2: Bool do return true