Merge: lib/core: Added `is_dir` function to `Path`
authorJean Privat <jean@pryen.org>
Thu, 26 May 2016 23:55:15 +0000 (19:55 -0400)
committerJean Privat <jean@pryen.org>
Thu, 26 May 2016 23:55:15 +0000 (19:55 -0400)
Quite self-explanatory, really it is just a simpler `Path::stat` followed by a `FileStat::is_dir`.

Pull-Request: #2128
Reviewed-by: Jean Privat <jean@pryen.org>

33 files changed:
contrib/nitrpg/src/test_helper.nit
lib/core/exec.nit
lib/popcorn/README.md
lib/popcorn/examples/middlewares/example_advanced_logger.nit
lib/popcorn/examples/middlewares/example_simple_logger.nit
lib/popcorn/pop_handlers.nit
lib/popcorn/popcorn.nit
lib/popcorn/tests/res/test_example_static_multiple.res
lib/popcorn/tests/test_example_advanced_logger.nit
lib/popcorn/tests/test_example_simple_logger.nit
share/man/nitdoc.md
share/man/nitunit.md
src/doc/doc_phases/doc_html.nit
src/model/model.nit
src/model/model_collect.nit
src/model/model_json.nit
src/model/model_visitor.nit
src/nitunit.nit
src/testing/testing_base.nit
src/testing/testing_doc.nit
src/testing/testing_suite.nit
src/toolcontext.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/sav/test_model_visitor_args2.res
tests/test_nitcorn.nit
tests/test_nitunit.nit
tests/tests.sh

index 1ac8314..904862c 100644 (file)
@@ -57,7 +57,8 @@ abstract class NitrpgTestHelper
 
        # Gen a test db with a random name (to avoid race conditions).
        fun gen_test_db: MongoDb do
-               var db_name = "test_nitrpg_{get_time}_{1000.rand}"
+               var testid = "NIT_TESTING_ID".environ.to_i
+               var db_name = "test_nitrpg_{testid}"
                var db = load_db(db_name)
                test_dbs.add db
                return db
index 10c5374..76d9d63 100644 (file)
@@ -324,6 +324,9 @@ redef class Sys
        do
                return command.to_cstring.system
        end
+
+       # The pid of the program
+       fun pid: Int `{ return getpid(); `}
 end
 
 redef class NativeString
index 4712faf..a136621 100644 (file)
@@ -428,6 +428,23 @@ receive a `404 Not found` error.
 * `res.send()` Send a response of various types.
 * `res.error()` Set the response status code and send its message as the response body.
 
+## Response cycle
+
+When the popcorn `App` receives a request, the response cycle is the following:
+
+1. `pre-middlewares` lookup matching middlewares registered with `use_before(pre_middleware)`:
+       1. execute matching middleware by registration order
+       2. if a middleware send a response then let the `pre-middlewares` loop continue
+          with the next middleware
+2. `response-handlers` lookup matching handlers registered with `use(handler)`:
+       1. execute matching middleware by registration order
+       2. if a middleware send a response then stop the `response-handlers` loop
+       3. if no hander matches or sends a response, generate a 404 response
+3. `post-middlewares` lookup matching handlers registered with `use_after(post_handler)`:
+       1. execute matching middleware by registration order
+       2. if a middleware send a response then let the `post-middlewares` loop continue
+          with the next middleware
+
 ## Middlewares
 
 ### Overview
@@ -465,7 +482,7 @@ end
 
 
 var app = new App
-app.use("/*", new MyLogger)
+app.use_before("/*", new MyLogger)
 app.use("/", new HelloHandler)
 app.listen("localhost", 3000)
 ~~~
@@ -474,8 +491,9 @@ By using the `MyLogger` handler to the route `/*` we ensure that every requests
 (even 404 ones) pass through the middleware handler.
 This handler just prints “Request Logged!” when a request is received.
 
-The order of middleware loading is important: middleware functions that are loaded first are also executed first.
-In the above example, `MyLogger` will be executed before `HelloHandler`.
+Be default, the order of middleware execution is that are loaded first are also executed first.
+To ensure our middleware `MyLogger` will be executed before all the other, we add it
+with the `use_before` method.
 
 ### Ultra cool, more advanced logger example
 
@@ -519,9 +537,9 @@ class HelloHandler
 end
 
 var app = new App
-app.use("/*", new RequestTimeHandler)
+app.use_before("/*", new RequestTimeHandler)
 app.use("/", new HelloHandler)
-app.use("/*", new LogHandler)
+app.use_after("/*", new LogHandler)
 app.listen("localhost", 3000)
 ~~~
 
@@ -530,9 +548,15 @@ Doing so we can access our data from all handlers that import our module, direct
 from the `req` parameter.
 
 We use the new middleware called `RequestTimeHandler` to initialize the request timer.
+Because of the `use_before` method, the `RequestTimeHandler` middleware will be executed
+before all the others.
+
+We then let the `HelloHandler` produce the response.
 
 Finally, our `LogHandler` will display a bunch of data and use the request `timer`
 to display the time it took to process the request.
+Because of the `use_after` method, the `LogHandler` middleware will be executed after
+all the others.
 
 The app now uses the `RequestTimeHandler` middleware for every requests received
 by the Popcorn app.
index 7f8e3b1..4ca9120 100644 (file)
@@ -48,7 +48,7 @@ class HelloHandler
 end
 
 var app = new App
-app.use("/*", new RequestTimeHandler)
+app.use_before("/*", new RequestTimeHandler)
 app.use("/", new HelloHandler)
-app.use("/*", new LogHandler)
+app.use_after("/*", new LogHandler)
 app.listen("localhost", 3000)
index 98be552..4052169 100644 (file)
@@ -30,6 +30,6 @@ end
 
 
 var app = new App
-app.use("/*", new LogHandler)
+app.use_before("/*", new LogHandler)
 app.use("/", new HelloHandler)
 app.listen("localhost", 3000)
index 2c85e15..1c20b67 100644 (file)
@@ -307,28 +307,71 @@ class Router
        # List of handlers to match with requests.
        private var handlers = new Map[AppRoute, Handler]
 
+       # List of handlers to match before every other.
+       private var pre_handlers = new Map[AppRoute, Handler]
+
+       # List of handlers to match after every other.
+       private var post_handlers = new Map[AppRoute, Handler]
+
        # Register a `handler` for a route `path`.
        #
        # Route paths are matched in registration order.
        fun use(path: String, handler: Handler) do
-               var route
-               if handler isa Router or handler isa StaticHandler then
-                       route = new AppGlobRoute(path)
-               else if path.has_suffix("*") then
-                       route = new AppGlobRoute(path)
-               else
-                       route = new AppParamRoute(path)
-               end
+               var route = build_route(handler, path)
                handlers[route] = handler
        end
 
+       # Register a pre-handler for a route `path`.
+       #
+       # Prehandlers are matched before every other handlers in registrastion order.
+       fun use_before(path: String, handler: Handler) do
+               var route = build_route(handler, path)
+               pre_handlers[route] = handler
+       end
+
+       # Register a post-handler for a route `path`.
+       #
+       # Posthandlers are matched after every other handlers in registrastion order.
+       fun use_after(path: String, handler: Handler) do
+               var route = build_route(handler, path)
+               post_handlers[route] = handler
+       end
+
        redef fun handle(route, uri, req, res) do
                if not route.match(uri) then return
+               handle_pre(route, uri, req, res)
+               handle_in(route, uri, req, res)
+               handle_post(route, uri, req, res)
+       end
+
+       private fun handle_pre(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse) do
+               for hroute, handler in pre_handlers do
+                       handler.handle(hroute, route.uri_root(uri), req, res)
+               end
+       end
+
+       private fun handle_in(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse) do
                for hroute, handler in handlers do
                        handler.handle(hroute, route.uri_root(uri), req, res)
                        if res.sent then break
                end
        end
+
+       private fun handle_post(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse) do
+               for hroute, handler in post_handlers do
+                       handler.handle(hroute, route.uri_root(uri), req, res)
+               end
+       end
+
+       private fun build_route(handler: Handler, path: String): AppRoute do
+               if handler isa Router or handler isa StaticHandler then
+                       return new AppGlobRoute(path)
+               else if path.has_suffix("*") then
+                       return new AppGlobRoute(path)
+               else
+                       return new AppParamRoute(path)
+               end
+       end
 end
 
 # Popcorn application.
index 887c122..64e4459 100644 (file)
@@ -48,12 +48,19 @@ redef class App
        redef fun answer(req, uri) do
                uri = uri.simplify_path
                var res = new HttpResponse(404)
+               for route, handler in pre_handlers do
+                       handler.handle(route, uri, req, res)
+               end
                for route, handler in handlers do
                        handler.handle(route, uri, req, res)
+                       if res.sent then break
                end
                if not res.sent then
                        res.send(error_tpl(res.status_code, res.status_message), 404)
                end
+               for route, handler in post_handlers do
+                       handler.handle(route, uri, req, res)
+               end
                res.session = req.session
                return res
        end
index 1b14f14..3a6692f 100644 (file)
@@ -28,13 +28,6 @@ alert("Hello World!");
 </html>
 
 [Client] curl -s localhost:*****/
-Warning: Headers already sent!
-<!DOCTYPE html>
-<html>
-       <body>
-               <h1>Another Index</h1>
-       </body>
-</html>
 <!DOCTYPE html>
 <html>
        <body>
index 41193d2..29b3fc2 100644 (file)
@@ -28,9 +28,9 @@ class TestClient
 end
 
 var app = new App
-app.use("/*", new RequestTimeHandler)
+app.use_before("/*", new RequestTimeHandler)
 app.use("/", new HelloHandler)
-app.use("/*", new LogHandler)
+app.use_after("/*", new LogHandler)
 
 var host = test_host
 var port = test_port
index 50f6af9..e8aab41 100644 (file)
@@ -28,7 +28,7 @@ class TestClient
 end
 
 var app = new App
-app.use("/*", new LogHandler)
+app.use_before("/*", new LogHandler)
 app.use("/", new HelloHandler)
 
 var host = test_host
index cd5472a..0b42d2f 100644 (file)
@@ -66,8 +66,8 @@ Also generate private API.
 
 ## CUSTOMIZATION
 
-### `--sharedir`
-Directory containing nitdoc assets.
+### `--share-dir`
+Directory containing tools assets.
 
 By default `$NIT_DIR/share/nitdoc/` is used.
 
index 0576201..e80e80e 100644 (file)
@@ -312,6 +312,29 @@ Only display the skeleton, do not write any file.
 
 Indicate the specific Nit compiler executable to use. See `--nitc`.
 
+### `NIT_TESTING`
+
+The environment variable `NIT_TESTING` is set to `true` during the execution of program tests.
+Some libraries of programs can use it to produce specific reproducible results; or just to exit their executions.
+
+Unit-tests may unset this environment variable to retrieve the original behavior of such piece of software.
+
+### `SRAND`
+
+In order to maximize reproducibility, `SRAND` is set to 0.
+This make the pseudo-random generator no random at all.
+See `Sys::srand` for details.
+
+To retrieve the randomness, unit-tests may unset this environment variable then call `srand`.
+
+### `NIT_TESTING_ID`
+
+Parallel executions can cause some race collisions on named resources (e.g. DB table names).
+To solve this issue, `NIT_TESTING_ID` is initialized with a distinct integer identifier that can be used to give unique names to resources.
+
+Note: `rand` is not a recommended way to get a distinct identifier because its randomness is disabled by default. See `SRAND`.
+
+
 # SEE ALSO
 
 The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
index c2ed988..a8d86b6 100644 (file)
@@ -31,9 +31,6 @@ redef class ToolContext
        var opt_source = new OptionString("Format to link source code (%f for filename, " +
                "%l for first line, %L for last line)", "--source")
 
-       # Directory where the CSS and JS is stored.
-       var opt_sharedir = new OptionString("Directory containing nitdoc assets", "--sharedir")
-
        # Use a shareurl instead of copy shared files.
        #
        # This is usefull if you don't want to store the Nitdoc templates with your
@@ -77,7 +74,7 @@ redef class ToolContext
                super
 
                option_context.add_option(
-                       opt_source, opt_sharedir, opt_shareurl, opt_custom_title,
+                       opt_source, opt_share_dir, opt_shareurl, opt_custom_title,
                        opt_custom_footer, opt_custom_intro, opt_custom_brand,
                        opt_github_upstream, opt_github_base_sha1, opt_github_gitdir,
                        opt_piwik_tracker, opt_piwik_site_id,
@@ -120,15 +117,7 @@ class RenderHTMLPhase
                var output_dir = ctx.output_dir
                if not output_dir.file_exists then output_dir.mkdir
                # locate share dir
-               var sharedir = ctx.opt_sharedir.value
-               if sharedir == null then
-                       var dir = ctx.nit_dir
-                       sharedir = dir/"share/nitdoc"
-                       if not sharedir.file_exists then
-                               print "Error: cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
-                               abort
-                       end
-               end
+               var sharedir = ctx.share_dir / "nitdoc"
                # copy shared files
                if ctx.opt_shareurl.value == null then
                        sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
index 9aefe19..e7c3b15 100644 (file)
@@ -30,6 +30,15 @@ import mdoc
 import ordered_tree
 private import more_collections
 
+redef class MEntity
+       # The visibility of the MEntity.
+       #
+       # MPackages, MGroups and MModules are always public.
+       # The visibility of `MClass` and `MProperty` is defined by the keyword used.
+       # `MClassDef` and `MPropDef` return the visibility of `MClass` and `MProperty`.
+       fun visibility: MVisibility do return public_visibility
+end
+
 redef class Model
        # All known classes
        var mclasses = new Array[MClass]
@@ -465,7 +474,7 @@ class MClass
 
        # The visibility of the class
        # In Nit, the visibility of a class cannot evolve in refinements
-       var visibility: MVisibility
+       redef var visibility
 
        init
        do
@@ -555,6 +564,8 @@ class MClass
 
        # Is `self` and abstract class?
        var is_abstract: Bool is lazy do return kind == abstract_kind
+
+       redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
 end
 
 
@@ -593,6 +604,8 @@ class MClassDef
 
        redef var location: Location
 
+       redef fun visibility do return mclass.visibility
+
        # Internal name combining the module and the class
        # Example: "mymodule$MyClass"
        redef var to_s is noinit
@@ -1963,6 +1976,8 @@ abstract class MProperty
 
        redef var location
 
+       redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
+
        # The canonical name of the property.
        #
        # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
@@ -1988,7 +2003,7 @@ abstract class MProperty
        end
 
        # The visibility of the property
-       var visibility: MVisibility
+       redef var visibility
 
        # Is the property usable as an initializer?
        var is_autoinit = false is writable
@@ -2255,6 +2270,8 @@ abstract class MPropDef
 
        redef var location: Location
 
+       redef fun visibility do return mproperty.visibility
+
        init
        do
                mclassdef.mpropdefs.add(self)
index 2590b0d..79970e5 100644 (file)
@@ -112,8 +112,6 @@ redef class MModule
                var mmodules = new HashSet[MModule]
                mmodules.add self
                mmodules.add_all collect_ancestors(view)
-               mmodules.add_all collect_parents(view)
-               mmodules.add_all collect_children(view)
                mmodules.add_all collect_descendants(view)
                return view.mmodules_poset(mmodules)
        end
@@ -220,6 +218,15 @@ redef class MClass
                return res
        end
 
+       # Build a class hierarchy poset for `self` based on its ancestors and descendants.
+       fun hierarchy_poset(mainmodule: MModule, view: ModelView): POSet[MClass] do
+               var mclasses = new HashSet[MClass]
+               mclasses.add self
+               mclasses.add_all collect_ancestors(view)
+               mclasses.add_all collect_descendants(view)
+               return view.mclasses_poset(mainmodule, mclasses)
+       end
+
        # Collect all mproperties introduced in 'self' with `visibility >= min_visibility`.
        fun collect_intro_mproperties(view: ModelView): Set[MProperty] do
                var set = new HashSet[MProperty]
index fc4b101..658e73d 100644 (file)
@@ -59,6 +59,8 @@ redef class MEntity
                obj["class_name"] = class_name
                obj["full_name"] = full_name
                obj["mdoc"] = mdoc_or_fallback
+               obj["visibility"] = visibility
+               obj["location"] = location
                var modifiers = new JsonArray
                for modifier in collect_modifiers do
                        modifiers.add modifier
@@ -114,7 +116,6 @@ redef class MPackage
 
        redef fun json do
                var obj = super
-               obj["visibility"] = public_visibility
                if ini != null then
                        obj["ini"] = new JsonObject.from(ini.as(not null).to_map)
                end
@@ -127,7 +128,6 @@ end
 redef class MGroup
        redef fun json do
                var obj = super
-               obj["visibility"] = public_visibility
                obj["is_root"] = is_root
                obj["mpackage"] = to_mentity_ref(mpackage)
                obj["default_mmodule"] = to_mentity_ref(default_mmodule)
@@ -141,8 +141,6 @@ end
 redef class MModule
        redef fun json do
                var obj = super
-               obj["location"] = location
-               obj["visibility"] = public_visibility
                obj["mpackage"] = to_mentity_ref(mpackage)
                obj["mgroup"] = to_mentity_ref(mgroup)
                obj["intro_mclasses"] = to_mentity_refs(intro_mclasses)
@@ -154,7 +152,6 @@ end
 redef class MClass
        redef fun json do
                var obj = super
-               obj["visibility"] = visibility
                var arr = new JsonArray
                for mparameter in mparameters do arr.add mparameter
                obj["mparameters"] = arr
@@ -169,8 +166,6 @@ end
 redef class MClassDef
        redef fun json do
                var obj = super
-               obj["visibility"] = mclass.visibility
-               obj["location"] = location
                obj["is_intro"] = is_intro
                var arr = new JsonArray
                for mparameter in mclass.mparameters do arr.add mparameter
@@ -186,7 +181,6 @@ end
 redef class MProperty
        redef fun json do
                var obj = super
-               obj["visibility"] = visibility
                obj["intro"] = to_mentity_ref(intro)
                obj["intro_mclassdef"] = to_mentity_ref(intro_mclassdef)
                obj["mpropdefs"] = to_mentity_refs(mpropdefs)
@@ -223,8 +217,6 @@ end
 redef class MPropDef
        redef fun json do
                var obj = super
-               obj["visibility"] = mproperty.visibility
-               obj["location"] = location
                obj["is_intro"] = is_intro
                obj["mclassdef"] = to_mentity_ref(mclassdef)
                obj["mproperty"] = to_mentity_ref(mproperty)
index da881a0..59d3e61 100644 (file)
@@ -144,7 +144,10 @@ redef class MEntity
        # See the specific implementation in the subclasses.
        fun visit_all(v: ModelVisitor) do end
 
-       private fun accept_visibility(min_visibility: nullable MVisibility): Bool do return true
+       private fun accept_visibility(min_visibility: nullable MVisibility): Bool do
+               if min_visibility == null then return true
+               return visibility >= min_visibility
+       end
 end
 
 redef class Model
@@ -183,13 +186,6 @@ redef class MModule
        end
 end
 
-redef class MClass
-       redef fun accept_visibility(min_visibility) do
-               if min_visibility == null then return true
-               return visibility >= min_visibility
-       end
-end
-
 redef class MClassDef
        # Visit all the classes and class definitions of the module.
        #
@@ -202,23 +198,4 @@ redef class MClassDef
                        v.enter_visit(x)
                end
        end
-
-       redef fun accept_visibility(min_visibility) do
-               if min_visibility == null then return true
-               return mclass.visibility >= min_visibility
-       end
-end
-
-redef class MProperty
-       redef fun accept_visibility(min_visibility) do
-               if min_visibility == null then return true
-               return visibility >= min_visibility
-       end
-end
-
-redef class MPropDef
-       redef fun accept_visibility(min_visibility) do
-               if min_visibility == null then return true
-               return mproperty.visibility >= min_visibility
-       end
 end
index 0d89dc6..878d3f2 100644 (file)
@@ -64,6 +64,8 @@ if toolcontext.opt_gen_unit.value then
 end
 
 "NIT_TESTING".setenv("true")
+"NIT_TESTING_ID".setenv(pid.to_s)
+"SRAND".setenv("0")
 
 var test_dir = toolcontext.test_dir
 test_dir.mkdir
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 4583868..de15aed 100644 (file)
@@ -374,6 +374,9 @@ class ToolContext
        # Option --nit-dir
        var opt_nit_dir = new OptionString("Base directory of the Nit installation", "--nit-dir")
 
+       # Option --share-dir
+       var opt_share_dir = new OptionString("Directory containing tools assets", "--share-dir")
+
        # Option --help
        var opt_help = new OptionBool("Show Help (This screen)", "-h", "-?", "--help")
 
@@ -542,6 +545,20 @@ The Nit language documentation and the source code of its tools and libraries ma
        # The identified root directory of the Nit package
        var nit_dir: String is noinit
 
+       # Shared files directory.
+       #
+       # Most often `nit/share/`.
+       var share_dir: String is lazy do
+               var sharedir = opt_share_dir.value
+               if sharedir == null then
+                       sharedir = nit_dir / "share"
+                       if not sharedir.file_exists then
+                               fatal_error(null, "Fatal Error: cannot locate shared files directory in {sharedir}. Uses --share-dir to define it's location.")
+                       end
+               end
+               return sharedir
+       end
+
        private fun compute_nit_dir: String
        do
                # the option has precedence
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 caad05a..445de88 100644 (file)
@@ -116,26 +116,26 @@ names::n3$::n1::P1        MClassDef       names/n3.nit:29,1--35,3 a refinement of a subclass
 names::n3$::n1::P1$A::a        MMethodDef      names/n3.nit:31,2--32,19        a refinement (3 distinct modules)
 names::n3$::n1::P1$::n0::P::p  MMethodDef      names/n3.nit:33,2--34,19        a refinement (3 distinct modules)
 names::n0      MModule names/n0.nit:15,1--67,3 Root module
-names::Object  MClass  names/n0.nit:20,1--22,3 
+names::Object  MClass  names/n0.nit:20,1--22,3 Root interface
 names$Object   MClassDef       names/n0.nit:20,1--22,3 Root interface
 names::Object::init    MMethod names/n0.nit:20,1--22,3 
 names$Object$init      MMethodDef      names/n0.nit:20,1--22,3 
-names::A       MClass  names/n0.nit:24,1--31,3 
+names::A       MClass  names/n0.nit:24,1--31,3 A public class
 names$A        MClassDef       names/n0.nit:24,1--31,3 A public class
-names::A::a    MMethod names/n0.nit:26,2--27,13        
+names::A::a    MMethod names/n0.nit:26,2--27,13        A public method in a public class
 names$A$a      MMethodDef      names/n0.nit:26,2--27,13        A public method in a public class
-names::n0::A::z        MMethod names/n0.nit:29,2--30,21        
+names::n0::A::z        MMethod names/n0.nit:29,2--30,21        A private method in a public class
 names$A$z      MMethodDef      names/n0.nit:29,2--30,21        A private method in a public class
-names::A0      MClass  names/n0.nit:33,1--46,3 
+names::A0      MClass  names/n0.nit:33,1--46,3 A public subclass in the same module
 names$A0       MClassDef       names/n0.nit:33,1--46,3 A public subclass in the same module
 names$A0$A::a  MMethodDef      names/n0.nit:38,2--39,19        Redefinition it the same module of a public method
 names$A0$::n0::A::z    MMethodDef      names/n0.nit:41,2--42,19        Redefinition it the same module of a private method
 names$A0$::n0::P::p    MMethodDef      names/n0.nit:44,2--45,19        Redefinition it the same module of a private method
-names::n0::P   MClass  names/n0.nit:48,1--52,3 
+names::n0::P   MClass  names/n0.nit:48,1--52,3 A private class
 names::n0$P    MClassDef       names/n0.nit:48,1--52,3 A private class
-names::n0::P::p        MMethod names/n0.nit:50,2--51,13        
+names::n0::P::p        MMethod names/n0.nit:50,2--51,13        A private method in a private class
 names::n0$P$p  MMethodDef      names/n0.nit:50,2--51,13        A private method in a private class
-names::n0::P0  MClass  names/n0.nit:54,1--67,3 
+names::n0::P0  MClass  names/n0.nit:54,1--67,3 A private subclass introduced in the same module
 names::n0$P0   MClassDef       names/n0.nit:54,1--67,3 A private subclass introduced in the same module
 names::n0$P0$A::a      MMethodDef      names/n0.nit:59,2--60,19        Redefinition it the same module of a public method
 names::n0$P0$::n0::A::z        MMethodDef      names/n0.nit:62,2--63,19        Redefinition it the same module of a private method
@@ -144,13 +144,13 @@ names::n1 MModule names/n1.nit:15,1--90,3 Second module
 names::n1$A    MClassDef       names/n1.nit:20,1--30,3 A refinement of a class
 names::n1$A$a  MMethodDef      names/n1.nit:22,2--23,19        A refinement in the same class
 names::n1$A$z  MMethodDef      names/n1.nit:25,2--26,19        A refinement in the same class
-names::n1::A::b        MMethod names/n1.nit:28,2--29,13        
+names::n1::A::b        MMethod names/n1.nit:28,2--29,13        A public method introduced in a refinement
 names::n1$A$b  MMethodDef      names/n1.nit:28,2--29,13        A public method introduced in a refinement
 names::n1$A0   MClassDef       names/n1.nit:32,1--42,3 A refinement of a subclass
 names::n1$A0$A::a      MMethodDef      names/n1.nit:34,2--35,19        A refinement+redefinition
 names::n1$A0$::n0::A::z        MMethodDef      names/n1.nit:37,2--38,19        A refinement+redefinition
 names::n1$A0$::n0::P::p        MMethodDef      names/n1.nit:40,2--41,19        A refinement+redefinition
-names::A1      MClass  names/n1.nit:44,1--57,3 
+names::A1      MClass  names/n1.nit:44,1--57,3 A subclass introduced in a submodule
 names$A1       MClassDef       names/n1.nit:44,1--57,3 A subclass introduced in a submodule
 names$A1$A::a  MMethodDef      names/n1.nit:49,2--50,19        A redefinition in a subclass from a different module
 names$A1$::n0::A::z    MMethodDef      names/n1.nit:52,2--53,19        A redefinition in a subclass from a different module
@@ -161,20 +161,20 @@ names::n1$::n0::P0        MClassDef       names/n1.nit:65,1--75,3 A refinement of a subclass
 names::n1$::n0::P0$A::a        MMethodDef      names/n1.nit:67,2--68,19        A refinement+redefinition
 names::n1$::n0::P0$::n0::A::z  MMethodDef      names/n1.nit:70,2--71,19        A refinement+redefinition
 names::n1$::n0::P0$::n0::P::p  MMethodDef      names/n1.nit:73,2--74,19        A refinement+redefinition
-names::n1::P1  MClass  names/n1.nit:77,1--90,3 
+names::n1::P1  MClass  names/n1.nit:77,1--90,3 A private subclass introduced in a different module
 names::n1$P1   MClassDef       names/n1.nit:77,1--90,3 A private subclass introduced in a different module
 names::n1$P1$A::a      MMethodDef      names/n1.nit:82,2--83,19        A redefinition in a subclass from a different module
 names::n1$P1$::n0::A::z        MMethodDef      names/n1.nit:85,2--86,19        A redefinition in a subclass from a different module
 names::n1$P1$::n0::P::p        MMethodDef      names/n1.nit:88,2--89,19        A redefinition in a subclass from a different module
 names::n2      MModule names/n2.nit:15,1--33,3 A alternative second module, used to make name conflicts
 names::n2$A    MClassDef       names/n2.nit:20,1--27,3 A refinement of a class
-names::n2::A::b        MMethod names/n2.nit:22,2--23,13        
+names::n2::A::b        MMethod names/n2.nit:22,2--23,13        Name conflict? A second public method
 names::n2$A$b  MMethodDef      names/n2.nit:22,2--23,13        Name conflict? A second public method
-names::n2::A::z        MMethod names/n2.nit:25,2--26,13        
+names::n2::A::z        MMethod names/n2.nit:25,2--26,13        Name conflict? A second private method
 names::n2$A$z  MMethodDef      names/n2.nit:25,2--26,13        Name conflict? A second private method
-names::n2::P   MClass  names/n2.nit:29,1--33,3 
+names::n2::P   MClass  names/n2.nit:29,1--33,3 Name conflict? A second private class
 names::n2$P    MClassDef       names/n2.nit:29,1--33,3 Name conflict? A second private class
-names::n2::P::p        MMethod names/n2.nit:31,2--32,13        
+names::n2::P::p        MMethod names/n2.nit:31,2--32,13        Name conflict? A private method in an homonym class.
 names::n2$P$p  MMethodDef      names/n2.nit:31,2--32,13        Name conflict? A private method in an homonym class.
 names1 MPackage        names1.nit      An alternative second module in a distinct package
 names1>        MGroup  names1.nit      An alternative second module in a distinct package
@@ -182,13 +182,13 @@ names1::names1    MModule names1.nit:15,1--90,3   An alternative second module in a d
 names1::names1$names::A        MClassDef       names1.nit:20,1--30,3   A refinement of a class
 names1::names1$names::A$a      MMethodDef      names1.nit:22,2--23,19  A refinement in the same class
 names1::names1$names::A$z      MMethodDef      names1.nit:25,2--26,19  A refinement in the same class
-names1::names1::A::b   MMethod names1.nit:28,2--29,13  
+names1::names1::A::b   MMethod names1.nit:28,2--29,13  A public method introduced in a refinement
 names1::names1$names::A$b      MMethodDef      names1.nit:28,2--29,13  A public method introduced in a refinement
 names1::names1$names::A0       MClassDef       names1.nit:32,1--42,3   A refinement of a subclass
 names1::names1$names::A0$names::A::a   MMethodDef      names1.nit:34,2--35,19  A refinement+redefinition
 names1::names1$names::A0$names::n0::A::z       MMethodDef      names1.nit:37,2--38,19  A refinement+redefinition
 names1::names1$names::A0$names::n0::P::p       MMethodDef      names1.nit:40,2--41,19  A refinement+redefinition
-names1::A1     MClass  names1.nit:44,1--57,3   
+names1::A1     MClass  names1.nit:44,1--57,3   A subclass introduced in a submodule
 names1$A1      MClassDef       names1.nit:44,1--57,3   A subclass introduced in a submodule
 names1$A1$names::A::a  MMethodDef      names1.nit:49,2--50,19  A redefinition in a subclass from a different module
 names1$A1$names::n0::A::z      MMethodDef      names1.nit:52,2--53,19  A redefinition in a subclass from a different module
@@ -199,7 +199,7 @@ names1::names1$names::n0::P0        MClassDef       names1.nit:65,1--75,3   A refinement of a s
 names1::names1$names::n0::P0$names::A::a       MMethodDef      names1.nit:67,2--68,19  A refinement+redefinition
 names1::names1$names::n0::P0$names::n0::A::z   MMethodDef      names1.nit:70,2--71,19  A refinement+redefinition
 names1::names1$names::n0::P0$names::n0::P::p   MMethodDef      names1.nit:73,2--74,19  A refinement+redefinition
-names1::names1::P1     MClass  names1.nit:77,1--90,3   
+names1::names1::P1     MClass  names1.nit:77,1--90,3   A private subclass introduced in a different module
 names1::names1$P1      MClassDef       names1.nit:77,1--90,3   A private subclass introduced in a different module
 names1::names1$P1$names::A::a  MMethodDef      names1.nit:82,2--83,19  A redefinition in a subclass from a different module
 names1::names1$P1$names::n0::A::z      MMethodDef      names1.nit:85,2--86,19  A redefinition in a subclass from a different module
index e4088a2..5f2ca1c 100644 (file)
@@ -17,8 +17,8 @@ import pthreads
 
 redef class Sys
        var iface: String is lazy do
-               srand
-               return "localhost:{10000+20000.rand}"
+               var testid = "NIT_TESTING_ID".environ.to_i
+               return "localhost:{10000+testid}"
        end
 
        var fs_path: String = getcwd / "../lib/nitcorn/examples/www/hello_world/dir" is lazy
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
index 84ba34a..d11c60a 100755 (executable)
@@ -21,6 +21,8 @@
 export LANG=C
 export LC_ALL=C
 export NIT_TESTING=true
+# Use the pid as a collision prevention
+export NIT_TESTING_ID=$$
 export NIT_SRAND=0
 
 unset NIT_DIR