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>
# 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
do
return command.to_cstring.system
end
+
+ # The pid of the program
+ fun pid: Int `{ return getpid(); `}
end
redef class NativeString
* `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
var app = new App
-app.use("/*", new MyLogger)
+app.use_before("/*", new MyLogger)
app.use("/", new HelloHandler)
app.listen("localhost", 3000)
~~~
(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
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)
~~~
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.
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)
var app = new App
-app.use("/*", new LogHandler)
+app.use_before("/*", new LogHandler)
app.use("/", new HelloHandler)
app.listen("localhost", 3000)
# 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.
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
</html>
[Client] curl -s localhost:*****/
-Warning: Headers already sent!
-<!DOCTYPE html>
-<html>
- <body>
- <h1>Another Index</h1>
- </body>
-</html>
<!DOCTYPE html>
<html>
<body>
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
end
var app = new App
-app.use("/*", new LogHandler)
+app.use_before("/*", new LogHandler)
app.use("/", new HelloHandler)
var host = test_host
## CUSTOMIZATION
-### `--sharedir`
-Directory containing nitdoc assets.
+### `--share-dir`
+Directory containing tools assets.
By default `$NIT_DIR/share/nitdoc/` is used.
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>
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
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,
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}/")
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]
# The visibility of the class
# In Nit, the visibility of a class cannot evolve in refinements
- var visibility: MVisibility
+ redef var visibility
init
do
# 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
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
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.
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
redef var location: Location
+ redef fun visibility do return mproperty.visibility
+
init
do
mclassdef.mpropdefs.add(self)
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
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]
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
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
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)
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)
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
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
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)
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)
# 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
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.
#
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
end
"NIT_TESTING".setenv("true")
+"NIT_TESTING_ID".setenv(pid.to_s)
+"SRAND".setenv("0")
var test_dir = toolcontext.test_dir
test_dir.mkdir
import modelize
private import parser_util
import html
+import console
redef class ToolContext
# opt --full
#
# 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)
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
# 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.
# 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
# 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
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
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
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`.
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
# 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.
#
# 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
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
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
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
# 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
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.
# 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
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
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
end
end
end
- toolcontext.check_errors
+ is_done = true
end
redef fun xml_classname do
# 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")
# 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
-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.<module>" name="<module>"><system-out>assert true
-</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="<class>"><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/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.<module>" name="<module>"><system-err></system-err><system-out>assert true
+</system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="<class>"><error>Runtime error in .nitunit/test_nitunit-2.nit</error><system-err>Runtime error: Assert failed (.nitunit/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/test_nitunit-3.nit</failure><system-err>.nitunit/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 '!'.</failure><system-out>assert !@#$%^&*()
+</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/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
+\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
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
+\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
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
-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>"><testcase classname="nitunit.test_nitunit3>" name="<group>"><failure>Compilation Error</failure><system-err>Runtime error: Assert failed (.nitunit/test_nitunit3-0.nit:7)
+<testsuites><testsuite package="test_nitunit3>"><testcase classname="nitunit.test_nitunit3>" name="<group>"><error>Runtime error in .nitunit/test_nitunit3-0.nit with argument 1</error><system-err>Runtime error: Assert failed (.nitunit/test_nitunit3-0.nit:7)
</system-err><system-out>assert false
assert true
-</system-out></testcase><testcase classname="nitunit.test_nitunit3>" name="<group>+1"><failure>Compilation Error</failure><system-err>test_nitunit3/README.md:7,3--5: Syntax Error: unexpected malformed character '\].</system-err><system-out>;'\][]
-</system-out></testcase></testsuite><testsuite package="test_nitunit3::test_nitunit3"><testcase classname="nitunit.test_nitunit3::test_nitunit3.<module>" name="<module>"><system-out>assert true
+</system-out></testcase><testcase classname="nitunit.test_nitunit3>" name="<group>+1"><failure>Syntax Error: unexpected malformed character '\].</failure><system-out>;'\][]
+</system-out></testcase></testsuite><testsuite package="test_nitunit3::test_nitunit3"><testcase classname="nitunit.test_nitunit3::test_nitunit3.<module>" name="<module>"><system-err></system-err><system-out>assert true
</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
-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
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.<file>" name="test_nitunit_md.md:1,0--15,0"><failure>Compilation Error</failure><system-err>Runtime error: Assert failed (.nitunit/file-0.nit:8)
+<testsuites><testsuite package="test_nitunit_md.md:1,0--15,0"><testcase classname="nitunit.<file>" name="test_nitunit_md.md:1,0--15,0"><error>Runtime error in .nitunit/file-0.nit with argument 1</error><system-err>Runtime error: Assert failed (.nitunit/file-0.nit:8)
</system-err><system-out>var a = 1
assert 1 == 1
assert false
-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 'garbage'.</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 'garbage'.</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 'garbage'.</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 'garbage'.</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 'garbage'.</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 'garbage'.</failure><system-out>*garbage*
</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
-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
TestSuites:
Class suites: 1; Test Cases: 3; Failures: 2
-<testsuites><testsuite package="test_nitunit4>"></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>"></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/gen_test_nitunit4.nit</error><system-err>Before Test
Tested method
After Test
Runtime error: Assert failed (test_nitunit4/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/test_nitunit4.sav/test_baz.res .nitunit/gen_test_nitunit4_test_baz.out1</error><system-err>Diff
--- expected:test_nitunit4/test_nitunit4.sav/test_baz.res
+++ got:.nitunit/gen_test_nitunit4_test_baz.out1
@@ -1 +1,3 @@
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
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
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
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
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
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
# 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
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