2015 Jean-Philippe Caissy <jean-philippe.caissy@shopify.com>
2015 Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
2015-2016 Guilherme Mansur <guilhermerpmansur@gmail.com>
+ 2016 Tony Gaetani <tony.gaetani@gmail.com>
License: Apache 2.0 (see LICENSE)
Comment: The main license of the work, except for the following exceptions
* gcc http://gcc.gnu.org/ (or a compatible C compiler)
* pkg-config http://www.freedesktop.org/wiki/Software/pkg-config/
* ccache http://ccache.samba.org/ to improve recompilation
- * libgc-dev http://www.hpl.hp.com/personal/Hans_Boehm/gc/
+ * libgc-dev http://hboehm.info/gc/
* graphviz http://www.graphviz.org/ to enable graphs with the nitdoc tool
* libunwind http://nongnu.org/libunwind
# Calculate the self-th element of the fibonacci sequence.
fun fibonacci: Int
do
- if self < 2 then
- return 1
- else
- return (self-2).fibonacci + (self-1).fibonacci
- end
- end
+ if self < 2 then return self
+ return (self-2).fibonacci + (self-1).fibonacci
+ end
end
# Print usage and exit.
return res
end
+ # Is `self` the path to an existing directory ?
+ #
+ # ~~~nit
+ # assert ".".to_path.is_dir
+ # assert not "/etc/issue".to_path.is_dir
+ # assert not "/should/not/exist".to_path.is_dir
+ # ~~~
+ fun is_dir: Bool do
+ var st = stat
+ if st == null then return false
+ return st.is_dir
+ end
+
# Delete a directory and all of its content
#
# Does not go through symbolic links and may get stuck in a cycle if there
end
return res
end
+
+ # Is `self` a power of two ?
+ #
+ # ~~~nit
+ # assert not 3.is_pow2
+ # assert 2.is_pow2
+ # assert 1.is_pow2
+ # assert not 0.is_pow2
+ # ~~~
+ fun is_pow2: Bool do return self != 0 and (self & self - 1) == 0
end
redef class Byte
# Show directory listing?
var show_directory_listing = true is writable
+ # Default file returned when no static file matches the requested URI.
+ #
+ # If no `default_file` is provided, the FileServer responds 404 error to
+ # unmatched queries.
+ var default_file: nullable String = null is writable
+
redef fun answer(request, turi)
do
var response
# This make sure that the requested file is within the root folder.
if (local_file + "/").has_prefix(root) then
# Does it exists?
- if local_file.file_exists then
- if local_file.file_stat.is_dir then
+ var file_stat = local_file.file_stat
+ if file_stat != null then
+ if file_stat.is_dir then
# If we target a directory without an ending `/`,
# redirect to the directory ending with `/`.
- if not request.uri.is_empty and
- request.uri.chars.last != '/' then
- response = new HttpResponse(303)
- response.header["Location"] = request.uri + "/"
- return response
+ var uri = request.uri
+ if not uri.is_empty and uri.chars.last != '/' then
+ return answer_redirection(request.uri + "/")
end
# Show index file instead of the directory listing
end
end
- var is_dir = local_file.file_stat.is_dir
- if show_directory_listing and is_dir then
- # Show the directory listing
- var title = turi
- var files = local_file.files
+ file_stat = local_file.file_stat
+ if show_directory_listing and file_stat != null and file_stat.is_dir then
+ response = answer_directory_listing(request, turi, local_file)
+ else if file_stat != null and not file_stat.is_dir then # It's a single file
+ response = answer_file(local_file)
+ else response = answer_default
+ else response = answer_default
+ else response = new HttpResponse(403)
- alpha_comparator.sort files
+ if response.status_code != 200 then
+ var tmpl = error_page(response.status_code)
+ if header != null and tmpl isa ErrorTemplate then tmpl.header = header
+ response.body = tmpl.to_s
+ end
- var links = new Array[String]
- if turi.length > 1 then
- var path = (request.uri + "/..").simplify_path
- links.add "<a href=\"{path}/\">..</a>"
- end
- for file in files do
- var local_path = local_file.join_path(file).simplify_path
- var web_path = file.simplify_path
- if local_path.file_stat.is_dir then web_path = web_path + "/"
- links.add "<a href=\"{web_path}\">{file}</a>"
- end
+ return response
+ end
+
+ # Answer the `default_file` if any.
+ fun answer_default: HttpResponse do
+ var default_file = self.default_file
+ if default_file == null then
+ return new HttpResponse(404)
+ end
+
+ var local_file = (root / default_file).simplify_path
+ return answer_file(local_file)
+ end
- var header = self.header
- var header_code
- if header != null then
- header_code = header.write_to_string
- else header_code = ""
+ # Answer a 303 redirection to `location`.
+ fun answer_redirection(location: String): HttpResponse do
+ var response = new HttpResponse(303)
+ response.header["Location"] = location
+ return response
+ end
+
+ # Build a reponse containing a single `local_file`.
+ #
+ # Returns a 404 error if local_file does not exists.
+ fun answer_file(local_file: String): HttpResponse do
+ if not local_file.file_exists then return new HttpResponse(404)
+
+ var response = new HttpResponse(200)
+ response.files.add local_file
+
+ # Set Content-Type depending on the file extension
+ var ext = local_file.file_extension
+ if ext != null then
+ var media_type = media_types[ext]
+ if media_type != null then
+ response.header["Content-Type"] = media_type
+ else response.header["Content-Type"] = "application/octet-stream"
+ end
- response = new HttpResponse(200)
- response.body = """
+ # Cache control
+ response.header["cache-control"] = cache_control
+ return response
+ end
+
+ # Answer with a directory listing for files within `local_files`.
+ fun answer_directory_listing(request: HttpRequest, turi, local_file: String): HttpResponse do
+ # Show the directory listing
+ var title = turi
+ var files = local_file.files
+
+ alpha_comparator.sort files
+
+ var links = new Array[String]
+ if turi.length > 1 then
+ var path = (request.uri + "/..").simplify_path
+ links.add "<a href=\"{path}/\">..</a>"
+ end
+ for file in files do
+ var local_path = local_file.join_path(file).simplify_path
+ var web_path = file.simplify_path
+ var file_stat = local_path.file_stat
+ if file_stat != null and file_stat.is_dir then web_path = web_path + "/"
+ links.add "<a href=\"{web_path}\">{file}</a>"
+ end
+
+ var header = self.header
+ var header_code
+ if header != null then
+ header_code = header.write_to_string
+ else header_code = ""
+
+ var response = new HttpResponse(200)
+ response.body = """
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</body>
</html>"""
- response.header["Content-Type"] = media_types["html"].as(not null)
- else if not is_dir then
- # It's a single file
- response = new HttpResponse(200)
- response.files.add local_file
-
- var ext = local_file.file_extension
- if ext != null then
- var media_type = media_types[ext]
- if media_type != null then
- response.header["Content-Type"] = media_type
- else response.header["Content-Type"] = "application/octet-stream"
- end
-
- # Cache control
- response.header["cache-control"] = cache_control
-
- else response = new HttpResponse(404)
- else response = new HttpResponse(404)
- else response = new HttpResponse(403)
-
- if response.status_code != 200 then
- var tmpl = error_page(response.status_code)
- if header != null and tmpl isa ErrorTemplate then tmpl.header = header
- response.body = tmpl.to_s
- end
-
+ response.header["Content-Type"] = media_types["html"].as(not null)
return response
end
end
If you run the app from another directory, it’s safer to use the absolute path of
the directory that you want to serve.
+In some cases, you can want to redirect request to static files to a default file
+instead of returning a 404 error.
+This can be achieved by specifying a default file in the StaticHandler:
+
+~~~
+app.use("/static/", new StaticHandler("public/", "default.html"))
+~~~
+
+This way all non-matched queries to the StaticHandler will be answered with the
+`default.html` file.
+
## Advanced Routing
**Routing** refers to the definition of application end points (URIs) and how
import popcorn
var app = new App
-app.use("/*", new StaticHandler("my-ng-app/"))
+app.use("/*", new StaticHandler("my-ng-app/", "index.html"))
app.listen("localhost", 3000)
~~~
+Because the StaticHandler will not find the angular routes as static files,
+you must specify the path to the default angular controller.
+In this example, the StaticHandler will redirect any unknown requests to the `index.html`
+angular controller.
+
See the examples for a more detailed use case working with a JSON API.
var app = new App
app.use("/counter", new CounterAPI)
-app.use("/*", new StaticHandler("www/"))
+app.use("/*", new StaticHandler("www/", "index.html"))
app.listen("localhost", 3000)
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import popcorn
+
+var app = new App
+app.use("/", new StaticHandler("public/", "default.html"))
+app.listen("localhost", 3000)
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Default Page</h1>
+ </body>
+</html>
# Static files directory to serve.
var static_dir: String
+ # Default file to serve if nothing matches the request.
+ #
+ # `null` for no default file.
+ var default_file: nullable String
+
# Internal file server used to lookup and render files.
var file_server: FileServer is lazy do
var srv = new FileServer(static_dir)
srv.show_directory_listing = false
+ srv.default_file = default_file
return srv
end
[Client] curl -s localhost:*****/counter -X POST
{"label":"Visitors","value":1}
[Client] curl -s localhost:*****/counter
-{"label":"Visitors","value":1}
\ No newline at end of file
+{"label":"Visitors","value":1}
+[Client] curl -s localhost:*****/not_found
+<!DOCTYPE html>
+<html lang='en' ng-app='ng-example'>
+ <head>
+ <base href='/'>
+ <title>ng-example</title>
+ </head>
+ <body>
+ <div ng-view></div>
+
+ <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js'></script>
+ <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-route.js'></script>
+ <script src='/javascripts/ng-example.js'></script>
+ </body>
+</html>
--- /dev/null
+
+[Client] curl -s localhost:*****/css/style.css
+body {
+ color: blue;
+ padding: 20px;
+}
+
+[Client] curl -s localhost:*****/js/app.js
+alert("Hello World!");
+
+[Client] curl -s localhost:*****/hello.html
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Hello Popcorn!</h1>
+
+ <img src="/images/trollface.jpg" alt="maybe it's a kitten?" />
+
+ <script src="/js/app.js"></script>
+ </body>
+</html>
+
+[Client] curl -s localhost:*****/
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Default Page</h1>
+ </body>
+</html>
+
+[Client] curl -s localhost:*****/css/not_found.nit
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Default Page</h1>
+ </body>
+</html>
+
+[Client] curl -s localhost:*****/static/css/not_found.nit
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Default Page</h1>
+ </body>
+</html>
+
+[Client] curl -s localhost:*****/not_found.nit
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+
+ <title>Some Popcorn love</title>
+
+ <link rel="stylesheet" type="text/css" href="/css/style.css">
+ </head>
+ <body>
+ <h1>Default Page</h1>
+ </body>
+</html>
system "curl -s {host}:{port}/counter"
system "curl -s {host}:{port}/counter -X POST"
system "curl -s {host}:{port}/counter"
+ system "curl -s {host}:{port}/not_found" # handled by angular controller
return null
end
end
var app = new App
app.use("/counter", new CounterAPI)
-app.use("/*", new StaticHandler("www/"))
+app.use("/*", new StaticHandler("../examples/angular/www/", "index.html"))
var host = test_host
var port = test_port
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import base_tests
+import example_static_default
+
+class TestClient
+ super ClientThread
+
+ redef fun main do
+ system "curl -s {host}:{port}/css/style.css"
+ system "curl -s {host}:{port}/js/app.js"
+ system "curl -s {host}:{port}/hello.html"
+ system "curl -s {host}:{port}/"
+
+ system "curl -s {host}:{port}/css/not_found.nit"
+ system "curl -s {host}:{port}/static/css/not_found.nit"
+ system "curl -s {host}:{port}/not_found.nit"
+
+ return null
+ end
+end
+
+var app = new App
+app.use("/", new StaticHandler("../examples/static_files/public/", "default.html"))
+
+var host = test_host
+var port = test_port
+
+var server = new AppThread(host, port, app)
+server.start
+0.1.sleep
+
+var client = new TestClient(host, port)
+client.start
+client.join
+0.1.sleep
+
+exit 0
--- /dev/null
+[package]
+name=readline
+tags=lib
+maintainer=Frédéric Vachon <fredvac@gmail.com>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/readline.nit
+git=https://github.com/nitlang/nit.git
+git.directory=lib/readline.nit
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2016 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# GNU readline library wrapper
+module readline is ldflags "-lreadline"
+
+in "C" `{
+ #include <readline/readline.h>
+ #include <readline/history.h>
+`}
+
+private fun native_readline(prompt: NativeString): NativeString `{
+ return readline(prompt);
+`}
+
+private fun native_add_history(data: NativeString) `{
+ if (data == NULL) return;
+ add_history(data);
+`}
+
+# Set emacs keybindings mode
+fun set_vi_mode `{ rl_editing_mode = 0; `}
+
+# Set emacs keybindings mode
+fun set_emacs_mode `{ rl_editing_mode = 1; `}
+
+# Use the GNU Library readline function
+# Returns `null` if EOF is read
+# If `with_history` is true, it will save all commands in the history except
+# empty strings and white characters strings
+fun readline(message: String, with_history: nullable Bool): nullable String do
+ var line = native_readline(message.to_cstring)
+ if line.address_is_null then return null
+
+ var nit_str = line.to_s
+
+ if with_history != null and with_history then
+ if nit_str.trim != "" then native_add_history(line)
+ end
+
+ return nit_str
+end
+
+# Adds the data String to the history no matter what it contains
+fun add_history(data: String) do native_add_history data.to_cstring
`nitunit` produces a XML file compatible with JUnit.
### `--dir`
-Working directory (default is '.nitunit').
+Working directory (default is 'nitunit.out').
In order to execute the tests, nit files are generated then compiled and executed in the giver working directory.
+In case of success, the directory is removed.
+In case of failure, it is kept as is so files can be investigated.
+
### `--nitc`
nitc compiler to use.
var doc_score = 0.0
for g in mpackage.mgroups do
mmodules += g.mmodules.length
- entity_score += 1.0
- if g.mdoc != null then doc_score += 1.0
+ var gs = 1.0
+ entity_score += gs
+ if g.mdoc != null then doc_score += gs
for m in g.mmodules do
var source = m.location.file
if source != null then
loc += file.line_starts.length - 1
end
end
- entity_score += 1.0
- if m.mdoc != null then doc_score += 1.0
+ var ms = gs
+ if m.is_test_suite then ms /= 100.0
+ entity_score += ms
+ if m.mdoc != null then doc_score += ms else ms /= 10.0
for cd in m.mclassdefs do
- var s = 0.2
- if not cd.is_intro then s /= 10.0
- if not cd.mclass.visibility <= private_visibility then s /= 10.0
- entity_score += s
- if cd.mdoc != null then doc_score += s
+ var cs = ms * 0.2
+ if not cd.is_intro then cs /= 100.0
+ if not cd.mclass.visibility <= private_visibility then cs /= 100.0
+ entity_score += cs
+ if cd.mdoc != null then doc_score += cs
mclasses += 1
for pd in cd.mpropdefs do
- s = 0.1
- if not pd.is_intro then s /= 10.0
- if not pd.mproperty.visibility <= private_visibility then s /= 10.0
- entity_score += s
- if pd.mdoc != null then doc_score += s
+ var ps = ms * 0.1
+ if not pd.is_intro then ps /= 100.0
+ if not pd.mproperty.visibility <= private_visibility then ps /= 100.0
+ entity_score += ps
+ if pd.mdoc != null then doc_score += ps
if not pd isa MMethodDef then continue
mmethods += 1
end
var file = toolcontext.opt_output.value
if file == null then file = "nitunit.xml"
page.write_to_file(file)
-# print docunits results
-print "DocUnits:"
-if modelbuilder.unit_entities == 0 then
- print "No doc units found"
-else if modelbuilder.failed_entities == 0 and not toolcontext.opt_noact.value then
- print "DocUnits Success"
+
+# Print results
+printn "Docunits: Entities: {modelbuilder.total_entities}; Documented ones: {modelbuilder.doc_entities}; With nitunits: {modelbuilder.unit_entities}"
+if modelbuilder.unit_entities == 0 or toolcontext.opt_noact.value then
+ print ""
+else
+ printn "; Failures: "
+ var cpt = modelbuilder.failed_entities
+ if toolcontext.opt_no_color.value then
+ print cpt
+ else if cpt == 0 then
+ print "0".green.bold
+ else
+ print cpt.to_s.red.bold
+ end
end
-print "Entities: {modelbuilder.total_entities}; Documented ones: {modelbuilder.doc_entities}; With nitunits: {modelbuilder.unit_entities}; Failures: {modelbuilder.failed_entities}"
-# print testsuites results
-print "\nTestSuites:"
-if modelbuilder.total_tests == 0 then
- print "No test cases found"
-else if modelbuilder.failed_tests == 0 and not toolcontext.opt_noact.value then
- print "TestSuites Success"
+printn "Test suites: Classes: {modelbuilder.total_classes}; Test Cases: {modelbuilder.total_tests}"
+if modelbuilder.total_tests == 0 or toolcontext.opt_noact.value then
+ print ""
+else
+ printn "; Failures: "
+ var cpt = modelbuilder.failed_tests
+ if toolcontext.opt_no_color.value then
+ print cpt
+ else if cpt == 0 then
+ print "0".green.bold
+ else
+ print cpt.to_s.red.bold
+ end
end
-print "Class suites: {modelbuilder.total_classes}; Test Cases: {modelbuilder.total_tests}; Failures: {modelbuilder.failed_tests}"
+
+var total = modelbuilder.unit_entities + modelbuilder.total_tests
+var fail = modelbuilder.failed_entities + modelbuilder.failed_tests
+if toolcontext.opt_noact.value then
+ # nothing
+else if total == 0 then
+ var head = "[NOTHING]"
+ if not toolcontext.opt_no_color.value then
+ head = head.yellow
+ end
+ print "{head} No unit tests to execute."
+else if fail == 0 then
+ var head = "[SUCCESS]"
+ if not toolcontext.opt_no_color.value then
+ head = head.green.bold
+ end
+ print "{head} All {total} tests passed."
+else
+ var head = "[FAILURE]"
+ if not toolcontext.opt_no_color.value then
+ head = head.red.bold
+ end
+ print "{head} {fail}/{total} tests failed."
+
+ print "`{test_dir}` is not removed for investigation."
+ exit 1
+end
+
+test_dir.rmdir
var port = toolcontext.opt_port.value
var app = new App
- app.use("/random", new RandomAction(model))
- app.use("/doc/:namespace", new DocAction(model, modelbuilder))
- app.use("/code/:namespace", new CodeAction(model, modelbuilder))
- app.use("/search/:namespace", new SearchAction(model))
- app.use("/uml/:namespace", new UMLDiagramAction(model, mainmodule))
- app.use("/", new TreeAction(model))
+
+ app.use("/api", new APIRouter(model, modelbuilder, mainmodule))
+ app.use("/doc/:namespace", new DocAction(model, mainmodule, modelbuilder))
+ app.use("/", new TreeAction(model, mainmodule))
app.listen(host, port.to_i)
end
if not check_depth(rt) then continue
#print "{ot}/{t} -> {rt}"
live_types.add(rt)
- todo_types.add(rt)
+ # unshift means a deep-first visit.
+ # So that the `check_depth` limit is reached sooner.
+ todo_types.unshift(rt)
end
end
#print "MType {live_types.length}: {live_types.join(", ")}"
# Working directory for testing.
fun test_dir: String do
var dir = opt_dir.value
- if dir == null then return ".nitunit"
+ if dir == null then return "nitunit.out"
return dir
end
line += "X".red.bold
end
end
+
+ if opt_no_color.value then
+ if done == 0 then
+ print "* {name} ({tests.length} tests)"
+ end
+ return
+ end
+
line += "] {done}/{tests.length}"
if more_message != null then
line += " " + more_message
printn "{line}"
end
+ # Shoe the full description of the test-case.
+ #
+ # The output honors `--no-color`.
+ #
+ # `more message`, if any, is added after the error message.
+ fun show_unit(test: UnitTest, more_message: nullable String) do
+ print test.to_screen(more_message, not opt_no_color.value)
+ end
end
# A unit test is an elementary test discovered, run and reported by nitunit.
var error_location: nullable Location = null is writable
# A colorful `[OK]` or `[KO]`.
- fun status_tag: String do
+ fun status_tag(color: nullable Bool): String do
+ color = color or else true
if not is_done then
return "[ ]"
else if error != null then
- return "[KO]".red.bold
+ var res = "[KO]"
+ if color then res = res.red.bold
+ return res
else
- return "[OK]".green.bold
+ var res = "[OK]"
+ if color then res = res.green.bold
+ return res
end
end
# The full (color) description of the test-case.
#
# `more message`, if any, is added after the error message.
- fun to_screen(more_message: nullable String): String do
+ fun to_screen(more_message: nullable String, color: nullable Bool): String do
+ color = color or else true
var res
var error = self.error
if error != null then
if more_message != null then error += " " + more_message
var loc = error_location or else location
- res = "{status_tag} {full_name}\n {loc.to_s.yellow}: {error}\n{loc.colored_line("1;31")}"
+ if color then
+ res = "{status_tag(color)} {full_name}\n {loc.to_s.yellow}: {error}\n{loc.colored_line("1;31")}"
+ else
+ res = "{status_tag(color)} {full_name}\n {loc}: {error}"
+ end
var output = self.raw_output
if output != null then
res += "\n Output\n\t{output.chomp.replace("\n", "\n\t")}\n"
end
else
- res = "{status_tag} {full_name}"
+ res = "{status_tag(color)} {full_name}"
if more_message != null then res += more_message
end
return res
print ""
for du in docunits do
- print du.to_screen
+ toolcontext.show_unit(du)
end
for du in docunits do
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
+ toolcontext.show_unit(case)
end
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module model_api
+
+import web_base
+import highlight
+import uml
+
+# Specific handler for nitweb API.
+abstract class APIHandler
+ super ModelHandler
+
+ # The JSON API does not filter anything by default.
+ #
+ # So we can cache the model view.
+ var view: ModelView is lazy do
+ var view = new ModelView(model)
+ view.min_visibility = private_visibility
+ view.include_fictive = true
+ view.include_empty_doc = true
+ view.include_attribute = true
+ view.include_test_suite = true
+ return view
+ end
+
+ # Try to load the mentity from uri with `/:id`.
+ #
+ # Send 400 if `:id` is null.
+ # Send 404 if no entity is found.
+ # Return null in both cases.
+ fun mentity_from_uri(req: HttpRequest, res: HttpResponse): nullable MEntity do
+ var id = req.param("id")
+ if id == null then
+ res.error 400
+ return null
+ end
+ var mentity = find_mentity(view, id)
+ if mentity == null then
+ res.error 404
+ end
+ return mentity
+ end
+end
+
+# Group all api handlers in one router.
+class APIRouter
+ super Router
+
+ # Model to pass to handlers.
+ var model: Model
+
+ # ModelBuilder to pass to handlers.
+ var modelbuilder: ModelBuilder
+
+ # Mainmodule to pass to handlers.
+ var mainmodule: MModule
+
+ init do
+ use("/list", new APIList(model, mainmodule))
+ use("/search", new APISearch(model, mainmodule))
+ use("/random", new APIRandom(model, mainmodule))
+ use("/entity/:id", new APIEntity(model, mainmodule))
+ use("/code/:id", new APIEntityCode(model, mainmodule, modelbuilder))
+ use("/uml/:id", new APIEntityUML(model, mainmodule))
+ end
+end
+
+# Search mentities from a query string.
+#
+# Example: `GET /search?q=Arr`
+class APISearch
+ super APIHandler
+
+ redef fun get(req, res) do
+ var q = req.string_arg("q")
+ if q == null then
+ res.error 400
+ return
+ end
+ var arr = new JsonArray
+ for mentity in view.mentities do
+ if mentity.name.has_prefix(q) then arr.add mentity
+ end
+ res.json arr
+ end
+end
+
+# List all mentities.
+#
+# MEntities can be filtered on their kind using the `k` parameter.
+# Allowed kinds are `package`, `group`, `module`, `class`, `classdef`, `property`, `propdef`.
+#
+# List size can be limited with the `n` parameter.
+#
+# Example: `GET /list?k=module?n=10`
+class APIList
+ super APIHandler
+
+ # List mentities depending on the `k` kind parameter.
+ fun list_mentities(req: HttpRequest): Array[MEntity] do
+ var k = req.string_arg("k")
+ var mentities = new Array[MEntity]
+ if k == "package" then
+ for mentity in view.mpackages do mentities.add mentity
+ else if k == "group" then
+ for mentity in view.mgroups do mentities.add mentity
+ else if k == "module" then
+ for mentity in view.mmodules do mentities.add mentity
+ else if k == "class" then
+ for mentity in view.mclasses do mentities.add mentity
+ else if k == "classdef" then
+ for mentity in view.mclassdefs do mentities.add mentity
+ else if k == "property" then
+ for mentity in view.mproperties do mentities.add mentity
+ else if k == "propdef" then
+ for mentity in view.mpropdefs do mentities.add mentity
+ else
+ for mentity in view.mentities do mentities.add mentity
+ end
+ return mentities
+ end
+
+ # Limit mentities depending on the `n` parameter.
+ fun limit_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
+ var n = req.int_arg("n")
+ if n != null then
+ return mentities.sub(0, n)
+ end
+ return mentities
+ end
+
+ redef fun get(req, res) do
+ var mentities = list_mentities(req)
+ mentities = limit_mentities(req, mentities)
+ var arr = new JsonArray
+ for mentity in mentities do arr.add mentity
+ res.json arr
+ end
+end
+
+# Return a random list of MEntities.
+#
+# Example: `GET /random?n=10&k=module`
+class APIRandom
+ super APIList
+
+ # Randomize mentities order.
+ fun randomize_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
+ var res = mentities.to_a
+ res.shuffle
+ return res
+ end
+
+ redef fun get(req, res) do
+ var mentities = list_mentities(req)
+ mentities = limit_mentities(req, mentities)
+ mentities = randomize_mentities(req, mentities)
+ var arr = new JsonArray
+ for mentity in mentities do arr.add mentity
+ res.json arr
+ end
+end
+
+# Return the JSON representation of a MEntity.
+#
+# Example: `GET /entity/core::Array`
+class APIEntity
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then return
+ res.json mentity.api_json(self)
+ end
+end
+
+
+# Return a UML representation of MEntity.
+#
+# Example: `GET /entity/core::Array/uml`
+class APIEntityUML
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ var dot
+ if mentity isa MClassDef then mentity = mentity.mclass
+ if mentity isa MClass then
+ var uml = new UMLModel(view, mainmodule)
+ dot = uml.generate_class_uml.write_to_string
+ else if mentity isa MModule then
+ var uml = new UMLModel(view, mentity)
+ dot = uml.generate_package_uml.write_to_string
+ else
+ res.error 404
+ return
+ end
+ res.send render_svg(dot)
+ end
+
+ # Render a `dot` string as a svg image.
+ fun render_svg(dot: String): String do
+ var proc = new ProcessDuplex("dot", "-Tsvg")
+ var svg = proc.write_and_read(dot)
+ proc.close
+ proc.wait
+ return svg
+ end
+end
+
+# Return the source code of MEntity.
+#
+# Example: `GET /entity/core::Array/code`
+class APIEntityCode
+ super APIHandler
+
+ # Modelbuilder used to access sources.
+ var modelbuilder: ModelBuilder
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then return
+ var source = render_source(mentity)
+ if source == null then
+ res.error 404
+ return
+ end
+ res.send source
+ end
+
+ # Highlight `mentity` source code.
+ private fun render_source(mentity: MEntity): nullable HTMLTag do
+ var node = modelbuilder.mentity2node(mentity)
+ if node == null then return null
+ var hl = new HighlightVisitor
+ hl.enter_visit node
+ return hl.html
+ end
+end
module web
import web_actions
+import model_api
# Display the tree of all loaded mentities.
class TreeAction
- super ModelAction
+ super ModelHandler
redef fun get(req, res) do
var model = init_model_view(req)
end
end
-# Display the list of mentities matching `namespace`.
-class SearchAction
- super ModelAction
-
- # TODO handle more than full namespaces.
- redef fun get(req, res) do
- var namespace = req.param("namespace")
- var model = init_model_view(req)
- var mentity = find_mentity(model, namespace)
- if mentity == null then
- res.error(404)
- return
- end
- if req.is_json_asked then
- res.json(mentity.to_json)
- return
- end
- var view = new HtmlResultPage(namespace or else "null", [mentity])
- res.send_view(view)
- end
-end
-
-# Display a MEntity source code.
-class CodeAction
- super ModelAction
-
- # Modelbuilder used to access sources.
- var modelbuilder: ModelBuilder
-
- redef fun get(req, res) do
- var namespace = req.param("namespace")
- var model = init_model_view(req)
- var mentity = find_mentity(model, namespace)
- if mentity == null then
- res.error(404)
- return
- end
- var view = new HtmlSourcePage(modelbuilder, mentity)
- res.send_view(view)
- end
-end
-
# Display the doc of a MEntity.
class DocAction
- super ModelAction
+ super ModelHandler
# Modelbuilder used to access sources.
var modelbuilder: ModelBuilder
res.error(404)
return
end
- if req.is_json_asked then
- res.json(mentity.to_json)
- return
- end
-
var view = new HtmlDocPage(modelbuilder, mentity)
res.send_view(view)
end
end
-
-# Return an UML diagram for `namespace`.
-class UMLDiagramAction
- super ModelAction
-
- # Mainmodule used for hierarchy flattening.
- var mainmodule: MModule
-
- redef fun get(req, res) do
- var namespace = req.param("namespace")
- var model = init_model_view(req)
- var mentity = find_mentity(model, namespace)
- if mentity == null then
- res.error(404)
- return
- end
-
- var dot
- if mentity isa MClassDef then mentity = mentity.mclass
- if mentity isa MClass then
- var uml = new UMLModel(model, mainmodule)
- dot = uml.generate_class_uml.write_to_string
- else if mentity isa MModule then
- var uml = new UMLModel(model, mentity)
- dot = uml.generate_package_uml.write_to_string
- else
- res.error(404)
- return
- end
- var view = new HtmlDotPage(dot, mentity.as(not null).html_name)
- res.send_view(view)
- end
-end
-
-# Return a random list of MEntities.
-class RandomAction
- super ModelAction
-
- redef fun get(req, res) do
- var n = req.int_arg("n") or else 10
- var k = req.string_arg("k") or else "modules"
- var model = init_model_view(req)
- var mentities: Array[MEntity]
- if k == "modules" then
- mentities = model.mmodules.to_a
- else if k == "classdefs" then
- mentities = model.mclassdefs.to_a
- else
- mentities = model.mpropdefs.to_a
- end
- mentities.shuffle
- mentities = mentities.sub(0, n)
- if req.is_json_asked then
- var json = new JsonArray
- for mentity in mentities do
- json.add mentity.to_json
- end
- res.json(json)
- return
- end
- var view = new HtmlResultPage("random", mentities)
- res.send_view(view)
- end
-end
import model::model_views
import model::model_json
+import doc_down
import popcorn
# Specific nitcorn Action that uses a Model
-class ModelAction
+class ModelHandler
super Handler
# Model to use.
var model: Model
+ # MModule used to flatten model.
+ var mainmodule: MModule
+
# Find the MEntity ` with `full_name`.
fun find_mentity(model: ModelView, full_name: nullable String): nullable MEntity do
if full_name == null then return null
fun send_view(view: NitView, status: nullable Int) do send(view.render, status)
end
-redef class HttpRequest
- # Does the client asked for a json formatted response?
- #
- # Checks the URL get parameter `?json=true`.
- fun is_json_asked: Bool do return bool_arg("json") or else false
+redef class MEntity
+
+ # URL to `self` within the web interface.
+ fun web_url: String is abstract
+
+ # URL to `self` within the JSON api.
+ fun api_url: String do return "/api/entity/" / full_name
+
+ redef fun json do
+ var obj = super
+ obj["web_url"] = web_url
+ obj["api_url"] = api_url
+ return obj
+ end
+
+ # Get the full json repesentation of `self` with MEntityRefs resolved.
+ fun api_json(handler: ModelHandler): JsonObject do return json
+end
+
+redef class MEntityRef
+ redef fun json do
+ var obj = super
+ obj["web_url"] = mentity.web_url
+ obj["api_url"] = mentity.api_url
+ obj["name"] = mentity.name
+ obj["mdoc"] = mentity.mdoc_or_fallback
+ obj["visibility"] = mentity.visibility
+ obj["location"] = mentity.location
+ var modifiers = new JsonArray
+ for modifier in mentity.collect_modifiers do
+ modifiers.add modifier
+ end
+ obj["modifiers"] = modifiers
+ return obj
+ end
+end
+
+redef class MDoc
+
+ # Add doc down processing
+ redef fun json do
+ var obj = super
+ obj["synopsis"] = synopsis
+ obj["documentation"] = documentation
+ obj["comment"] = comment
+ obj["html_synopsis"] = html_synopsis.write_to_string
+ obj["html_documentation"] = html_documentation.write_to_string
+ obj["html_comment"] = html_comment.write_to_string
+ return obj
+ end
+end
+
+redef class MPackage
+ redef var web_url = "/package/{full_name}" is lazy
+end
+
+redef class MGroup
+ redef var web_url = "/group/{full_name}" is lazy
+end
+
+redef class MModule
+ redef var web_url = "/module/{full_name}" is lazy
+
+ redef fun api_json(handler) do
+ var obj = super
+ obj["intro_mclassdefs"] = to_mentity_refs(collect_intro_mclassdefs(private_view))
+ obj["redef_mclassdefs"] = to_mentity_refs(collect_redef_mclassdefs(private_view))
+ obj["imports"] = to_mentity_refs(in_importation.direct_greaters)
+ return obj
+ end
+end
+
+redef class MClass
+ redef var web_url = "/class/{full_name}" is lazy
+
+ redef fun api_json(handler) do
+ var obj = super
+ obj["all_mproperties"] = to_mentity_refs(collect_accessible_mproperties(private_view))
+ obj["intro_mproperties"] = to_mentity_refs(collect_intro_mproperties(private_view))
+ obj["redef_mproperties"] = to_mentity_refs(collect_redef_mproperties(private_view))
+ var poset = hierarchy_poset(handler.mainmodule, private_view)
+ obj["parents"] = to_mentity_refs(poset[self].direct_greaters)
+ return obj
+ end
+end
+
+redef class MClassDef
+ redef var web_url = "/classdef/{full_name}" is lazy
+
+ redef fun json do
+ var obj = super
+ obj["intro"] = to_mentity_ref(mclass.intro)
+ obj["mpackage"] = to_mentity_ref(mmodule.mpackage)
+ return obj
+ end
+
+ redef fun api_json(handler) do
+ var obj = super
+ obj["intro_mpropdefs"] = to_mentity_refs(collect_intro_mpropdefs(private_view))
+ obj["redef_mpropdefs"] = to_mentity_refs(collect_redef_mpropdefs(private_view))
+ return obj
+ end
+end
+
+redef class MProperty
+ redef var web_url = "/property/{full_name}" is lazy
+
+ redef fun json do
+ var obj = super
+ obj["intro_mclass"] = to_mentity_ref(intro_mclassdef.mclass)
+ obj["mpackage"] = to_mentity_ref(intro_mclassdef.mmodule.mpackage)
+ return obj
+ end
+end
+
+redef class MPropDef
+ redef var web_url = "/propdef/{full_name}" is lazy
+
+ redef fun json do
+ var obj = super
+ obj["intro"] = to_mentity_ref(mproperty.intro)
+ obj["intro_mclassdef"] = to_mentity_ref(mproperty.intro.mclassdef)
+ obj["mmodule"] = to_mentity_ref(mclassdef.mmodule)
+ obj["mgroup"] = to_mentity_ref(mclassdef.mmodule.mgroup)
+ obj["mpackage"] = to_mentity_ref(mclassdef.mmodule.mpackage)
+ return obj
+ end
+end
+
+redef class MClassType
+ redef var web_url = mclass.web_url is lazy
+end
+
+redef class MNullableType
+ redef var web_url = mtype.web_url is lazy
+end
+
+redef class MParameterType
+ redef var web_url = mclass.web_url is lazy
+end
+
+redef class MVirtualType
+ redef var web_url = mproperty.web_url is lazy
end
end
end
-# Display a search results list.
-class HtmlResultPage
- super NitView
-
- # Initial query.
- var query: String
-
- # Result set
- var results: Array[MEntity]
-
- redef fun render do
- var tpl = new Template
- tpl.add new Header(1, "Results for {query}")
- if results.is_empty then
- tpl.add "<p>No result for {query}.<p>"
- return tpl
- end
- var list = new UnorderedList
- for mentity in results do
- var link = mentity.html_link
- link.text = mentity.html_full_name
- list.add_li new ListItem(link)
- end
- tpl.add list
- return tpl
- end
-end
-
# Display the source for each mentities
class HtmlSourcePage
super NitView
return tpl
end
end
-
-# Display the source for each mentities
-class HtmlDotPage
- super NitView
-
- # Dot to process.
- var dot: Text
-
- # Page title.
- var title: String
-
- redef fun render do
- var tpl = new Template
- tpl.add new Header(1, title)
- tpl.add render_dot
- return tpl
- end
-
- private fun render_dot: String do
- var proc = new ProcessDuplex("dot", "-Tsvg", "-Tcmapx")
- var svg = proc.write_and_read(dot)
- proc.close
- proc.wait
- return svg
- end
-end
mpi
emscripten
ui_test
+readline
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import end
+
+interface Object
+ type SELF: Object
+ fun output_class_name is intern
+end
+
+class A[E]
+ new do return new B[E]
+end
+
+class B[E]
+ super A[E]
+
+ fun foo: A[E] do return new A[SELF]
+end
+
+(new B[Object]).foo.output_class_name
test_nitunit.nit --no-color -o $WRITE
test_nitunit.nit --gen-suite --only-show
test_nitunit.nit --gen-suite --only-show --private
-test_nitunit2.nit -o $WRITE
+test_nitunit2.nit --no-color -o $WRITE
test_doc2.nit --no-color -o $WRITE
test_nitunit3 --no-color -o $WRITE
test_nitunit_md.md --no-color -o $WRITE
--- /dev/null
+B[B[Object]]
<h3>Quality</h3>
<ul class="box">
<li>28 warnings (63/kloc)</li>
-<li>93% documented</li>
+<li>95% documented</li>
</ul>
<h3>Tags</h3>
<a href="../index.html#tag_test">test</a>, <a href="../index.html#tag_game">game</a><h3>Requirements</h3>
--- /dev/null
+Fatal Error: limitation in the rapidtype analysis engine: a type depth of 256 is too important, the problematic type is `A[A[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[Sys]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]`.
--- /dev/null
+Fatal Error: limitation in the rapidtype analysis engine: a type depth of 256 is too important, the problematic type is `A[A[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[Sys]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]`.
--- /dev/null
+Fatal Error: limitation in the rapidtype analysis engine: a type depth of 256 is too important, the problematic type is `A[A[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[B[Sys]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]`.
-\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
- ^
+* Docunits of module test_nitunit::test_nitunit (4 tests)
+
+[OK] test_nitunit::test_nitunit
+[KO] test_nitunit$X
+ test_nitunit.nit:21,7--22,0: Runtime error in nitunit.out/test_nitunit-2.nit
Output
- Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
+ Runtime error: Assert failed (nitunit.out/test_nitunit-2.nit:5)
-\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
- ^
+[KO] test_nitunit$X$foo
+ test_nitunit.nit:24,8--25,0: Compilation error in nitunit.out/test_nitunit-3.nit
Output
- .nitunit/test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
+ nitunit.out/test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
+
+[KO] test_nitunit$X$foo1
+ test_nitunit.nit:28,15: Syntax Error: unexpected operator '!'.
+* Test-suite of module test_test_nitunit::test_test_nitunit (3 tests)
-\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
- ^
+[OK] test_test_nitunit$TestX$test_foo
+[KO] test_test_nitunit$TestX$test_foo1
+ test_test_nitunit.nit:36,2--40,4: Runtime Error in file nitunit.out/gen_test_test_nitunit.nit
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: 4; With nitunits: 4; Failures: 3
-
-TestSuites:
-Class suites: 1; Test Cases: 3; Failures: 1
+[OK] test_test_nitunit$TestX$test_foo2
+Docunits: Entities: 27; Documented ones: 4; With nitunits: 4; Failures: 3
+Test suites: Classes: 1; Test Cases: 3; Failures: 1
+[FAILURE] 4/7 tests failed.
+`nitunit.out` is not removed for investigation.
<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-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="<class>"><error>Runtime error in nitunit.out/test_nitunit-2.nit</error><system-err>Runtime error: Assert failed (nitunit.out/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-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><failure>Compilation error in nitunit.out/test_nitunit-3.nit</failure><system-err>nitunit.out/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><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-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.out/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
+* Docunits of module test_nitunit2::test_nitunit2 (3 tests)
-TestSuites:
-No test cases found
-Class suites: 0; Test Cases: 0; Failures: 0
+[OK] test_nitunit2::test_nitunit2$core::Sys$foo1
+[OK] test_nitunit2::test_nitunit2$core::Sys$bar2
+[OK] test_nitunit2::test_nitunit2$core::Sys$foo3
+Docunits: Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
+Test suites: Classes: 0; Test Cases: 0
+[SUCCESS] All 3 tests passed.
<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
-\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
+* Docunits of module test_doc2::test_doc2 (3 tests)
-TestSuites:
-No test cases found
-Class suites: 0; Test Cases: 0; Failures: 0
+[OK] test_doc2::test_doc2$core::Sys$foo1
+[OK] test_doc2::test_doc2$core::Sys$foo2
+[OK] test_doc2::test_doc2$core::Sys$foo3
+Docunits: Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
+Test suites: Classes: 0; Test Cases: 0
+[SUCCESS] All 3 tests passed.
<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
-\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
- ^
+* Docunits of group test_nitunit3> (2 tests)
+
+[KO] test_nitunit3>
+ test_nitunit3/README.md:4,2--15,0: Runtime error in nitunit.out/test_nitunit3-0.nit with argument 1
Output
- Runtime error: Assert failed (.nitunit/test_nitunit3-0.nit:7)
+ Runtime error: Assert failed (nitunit.out/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
+[KO] test_nitunit3>
+ test_nitunit3/README.md:7,3--5: Syntax Error: unexpected malformed character '\].
+* Docunits of module test_nitunit3::test_nitunit3 (1 tests)
-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>"><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)
+[OK] test_nitunit3::test_nitunit3
+Docunits: Entities: 2; Documented ones: 2; With nitunits: 3; Failures: 2
+Test suites: Classes: 0; Test Cases: 0
+[FAILURE] 2/3 tests failed.
+`nitunit.out` is not removed for investigation.
+<testsuites><testsuite package="test_nitunit3>"><testcase classname="nitunit.test_nitunit3>" name="<group>"><error>Runtime error in nitunit.out/test_nitunit3-0.nit with argument 1</error><system-err>Runtime error: Assert failed (nitunit.out/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>Syntax Error: unexpected malformed character '\].</failure><system-out>;'\][]
-\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 of file test_nitunit_md.md:1,0--15,0 (1 tests)
-DocUnits:
-Entities: 1; Documented ones: 1; With nitunits: 1; Failures: 1
+[KO] nitunit.<file>.test_nitunit_md.md:1,0--15,0
+ test_nitunit_md.md:4,2--16,0: Runtime error in nitunit.out/file-0.nit with argument 1
+ Output
+ Runtime error: Assert failed (nitunit.out/file-0.nit:8)
-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"><error>Runtime error in .nitunit/file-0.nit with argument 1</error><system-err>Runtime error: Assert failed (.nitunit/file-0.nit:8)
+Docunits: Entities: 1; Documented ones: 1; With nitunits: 1; Failures: 1
+Test suites: Classes: 0; Test Cases: 0
+[FAILURE] 1/1 tests failed.
+`nitunit.out` is not removed for investigation.
+<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.out/file-0.nit with argument 1</error><system-err>Runtime error: Assert failed (nitunit.out/file-0.nit:8)
</system-err><system-out>var a = 1
assert 1 == 1
assert false
-\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
+* Docunits of module test_doc3::test_doc3 (3 tests)
-TestSuites:
-No test cases found
-Class suites: 0; Test Cases: 0; Failures: 0
+[KO] test_doc3::test_doc3$core::Sys$foo1
+ test_doc3.nit:17,9--15: Syntax Error: unexpected identifier 'garbage'.
+[KO] test_doc3::test_doc3$core::Sys$foo2
+ test_doc3.nit:23,4--10: Syntax Error: unexpected identifier 'garbage'.
+[KO] test_doc3::test_doc3$core::Sys$foo3
+ test_doc3.nit:30,4--10: Syntax Error: unexpected identifier 'garbage'.
+Docunits: Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 3
+Test suites: Classes: 0; Test Cases: 0
+[FAILURE] 3/3 tests failed.
+`nitunit.out` is not removed for investigation.
<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*
-\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
- ^
+* Test-suite of module test_nitunit4::test_nitunit4 (3 tests)
+
+[KO] test_nitunit4$TestTestSuite$test_foo
+ test_nitunit4/test_nitunit4.nit:22,2--26,4: Runtime Error in file nitunit.out/gen_test_nitunit4.nit
Output
Before Test
Tested method
After Test
Runtime error: Assert failed (test_nitunit4/test_nitunit4_base.nit:31)
-\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
- ^
+[OK] test_nitunit4$TestTestSuite$test_bar
+[KO] test_nitunit4$TestTestSuite$test_baz
+ test_nitunit4/test_nitunit4.nit:32,2--34,4: Difference with expected output: diff -u test_nitunit4/test_nitunit4.sav/test_baz.res nitunit.out/gen_test_nitunit4_test_baz.out1
Output
Diff
--- expected:test_nitunit4/test_nitunit4.sav/test_baz.res
- +++ got:.nitunit/gen_test_nitunit4_test_baz.out1
+ +++ got:nitunit.out/gen_test_nitunit4_test_baz.out1
@@ -1 +1,3 @@
-Bad result file
+Before Test
+Tested method
+After Test
-DocUnits:
-No doc units found
-Entities: 12; Documented ones: 0; With nitunits: 0; Failures: 0
-
-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 in file .nitunit/gen_test_nitunit4.nit</error><system-err>Before Test
+Docunits: Entities: 12; Documented ones: 0; With nitunits: 0
+Test suites: Classes: 1; Test Cases: 3; Failures: 2
+[FAILURE] 2/3 tests failed.
+`nitunit.out` is not removed for investigation.
+<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.out/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"><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
+</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.out/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
++++ got:nitunit.out/gen_test_nitunit4_test_baz.out1
@@ -1 +1,3 @@
-Bad result file
+Before Test
--- /dev/null
+prompt>line 1
+line 1
+prompt>line 2
+line 2
+prompt>line 2bis
+line 2bis
+prompt>line 3 \b \bine\b \b\b \b\b \b3\b \b
+line 3
+prompt>
\ No newline at end of file
--- /dev/null
+line 1
+line 2
+line 2bis
+line 3 \bine\b\b\b3\b
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import readline
+
+loop
+ var line = readline("prompt>", true)
+ if line == null then break
+ print line
+end