Merge: nitweb: list linearized definitions
authorJean Privat <jean@pryen.org>
Tue, 7 Jun 2016 19:11:09 +0000 (15:11 -0400)
committerJean Privat <jean@pryen.org>
Tue, 7 Jun 2016 19:11:09 +0000 (15:11 -0400)
Display linearization lists:

* Mclass linearize all the class definitions
   * linearization of `core::Array` mclassdefs: http://nitweb.moz-code.org/class/core::Array

* MProperty linearize all the prop definitions
    * linearization of `core::Object::hash`: http://nitweb.moz-code.org/property/core::Object::hash

* MClassDef linearize to intro
    * linearization of `core::flat$Array`: http://nitweb.moz-code.org/classdef/core::flat$Array

* MPropdef linearize to intro
    * linearization of `core$Array$Object::SELF`: http://nitweb.moz-code.org/propdef/core$Array$Object::SELF

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

62 files changed:
.gitattributes
contrib/nitrpg/src/test_helper.nit
lib/core/text/abstract_text.nit
lib/core/text/flat.nit
lib/core/text/test_abstract_text.nit [new file with mode: 0644]
lib/nitcorn/examples/src/htcpcp_server.nit
lib/nitcorn/http_request.nit
lib/nitcorn/http_response.nit
lib/nitcorn/media_types.nit
lib/popcorn/Makefile
lib/popcorn/examples/angular/test_example_angular.nit [moved from lib/popcorn/tests/test_example_angular.nit with 68% similarity]
lib/popcorn/examples/angular/test_example_angular.sav/test_example_angular.res [moved from lib/popcorn/tests/res/test_example_angular.res with 100% similarity]
lib/popcorn/examples/handlers/test_example_post_handler.nit [moved from lib/popcorn/tests/test_example_post.nit with 75% similarity]
lib/popcorn/examples/handlers/test_example_post_handler.sav/test_example_post_handler.res [moved from lib/popcorn/tests/res/test_example_post.res with 100% similarity]
lib/popcorn/examples/handlers/test_example_query_string.nit [moved from lib/popcorn/tests/test_example_query_string.nit with 73% similarity]
lib/popcorn/examples/handlers/test_example_query_string.sav/test_example_query_string.res [moved from lib/popcorn/tests/res/test_example_query_string.res with 100% similarity]
lib/popcorn/examples/hello_world/test_example_hello.nit [moved from lib/popcorn/tests/test_example_hello.nit with 73% similarity]
lib/popcorn/examples/hello_world/test_example_hello.sav/test_example_hello.res [moved from lib/popcorn/tests/res/test_example_hello.res with 98% similarity]
lib/popcorn/examples/middlewares/test_example_advanced_logger.nit [moved from lib/popcorn/tests/test_example_advanced_logger.nit with 65% similarity]
lib/popcorn/examples/middlewares/test_example_advanced_logger.sav/test_example_advanced_logger.res [moved from lib/popcorn/tests/res/test_example_advanced_logger.res with 100% similarity]
lib/popcorn/examples/middlewares/test_example_html_error_handler.nit [moved from lib/popcorn/tests/test_example_html_error_handler.nit with 70% similarity]
lib/popcorn/examples/middlewares/test_example_html_error_handler.sav/test_example_html_error_handler.res [moved from lib/popcorn/tests/res/test_example_html_error_handler.res with 100% similarity]
lib/popcorn/examples/middlewares/test_example_simple_error_handler.nit [moved from lib/popcorn/tests/test_example_simple_error_handler.nit with 68% similarity]
lib/popcorn/examples/middlewares/test_example_simple_error_handler.sav/test_example_simple_error_handler.res [moved from lib/popcorn/tests/res/test_example_simple_error_handler.res with 100% similarity]
lib/popcorn/examples/middlewares/test_example_simple_logger.nit [moved from lib/popcorn/tests/test_example_simple_logger.nit with 68% similarity]
lib/popcorn/examples/middlewares/test_example_simple_logger.sav/test_example_simple_logger.res [moved from lib/popcorn/tests/res/test_example_simple_logger.res with 100% similarity]
lib/popcorn/examples/routing/test_example_glob_route.nit [moved from lib/popcorn/tests/test_example_glob_route.nit with 75% similarity]
lib/popcorn/examples/routing/test_example_glob_route.sav/test_example_glob_route.res [moved from lib/popcorn/tests/res/test_example_glob_route.res with 98% similarity]
lib/popcorn/examples/routing/test_example_param_route.nit [moved from lib/popcorn/tests/test_example_param_route.nit with 73% similarity]
lib/popcorn/examples/routing/test_example_param_route.sav/test_example_param_route.res [moved from lib/popcorn/tests/res/test_example_param_route.res with 98% similarity]
lib/popcorn/examples/routing/test_example_router.nit [moved from lib/popcorn/tests/test_example_router.nit with 67% similarity]
lib/popcorn/examples/routing/test_example_router.sav/test_example_router.res [moved from lib/popcorn/tests/res/test_example_router.res with 98% similarity]
lib/popcorn/examples/sessions/test_example_session.nit [moved from lib/popcorn/tests/test_example_session.nit with 71% similarity]
lib/popcorn/examples/sessions/test_example_session.sav/test_example_session.res [moved from lib/popcorn/tests/res/test_example_session.res with 100% similarity]
lib/popcorn/examples/static_files/test_example_static.nit [moved from lib/popcorn/tests/test_example_static.nit with 73% similarity]
lib/popcorn/examples/static_files/test_example_static.sav/test_example_static.res [moved from lib/popcorn/tests/res/test_example_static.res with 100% similarity]
lib/popcorn/examples/static_files/test_example_static_default.nit [moved from lib/popcorn/tests/test_example_static_default.nit with 72% similarity]
lib/popcorn/examples/static_files/test_example_static_default.sav/test_example_static_default.res [moved from lib/popcorn/tests/res/test_example_static_default.res with 100% similarity]
lib/popcorn/examples/static_files/test_example_static_multiple.nit [moved from lib/popcorn/tests/test_example_static_multiple.nit with 67% similarity]
lib/popcorn/examples/static_files/test_example_static_multiple.sav/test_example_static_multiple.res [moved from lib/popcorn/tests/res/test_example_static_multiple.res with 100% similarity]
lib/popcorn/pop_tests.nit [new file with mode: 0644]
lib/popcorn/test_popcorn.nit [new file with mode: 0644]
lib/popcorn/test_popcorn.sav/test_router.res [moved from lib/popcorn/tests/res/test_router.res with 98% similarity]
lib/popcorn/test_popcorn.sav/test_routes.res [moved from lib/popcorn/tests/res/test_routes.res with 99% similarity]
lib/popcorn/tests/Makefile [deleted file]
lib/popcorn/tests/base_tests.nit [deleted file]
lib/popcorn/tests/test_router.nit [deleted file]
lib/popcorn/tests/test_routes.nit [deleted file]
lib/popcorn/tests/tests.sh [deleted file]
share/man/nitunit.md
src/loader.nit
src/nitcatalog.nit
src/nitunit.nit
src/testing/testing_doc.nit
src/testing/testing_suite.nit
tests/nitunit.args
tests/sav/nitunit_args1.res
tests/sav/nitunit_args4.res
tests/sav/nitunit_args5.res
tests/sav/nitunit_args6.res
tests/sav/nitunit_args8.res
tests/sav/nitunit_args9.res

index 02c0677..e326f39 100644 (file)
@@ -6,5 +6,5 @@ tables_nit.c            -diff
 c_src/**               -diff
 
 tests/sav/**/*.res     -whitespace
-lib/popcorn/tests/res/*.res -whitespace
+*.res                  -whitespace
 *.patch                        -whitespace
index 904862c..ecdc358 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Test tools for NitRPG.
-module test_helper is test_suite
+module test_helper
 
 import test_suite
 import game
index 8fefb24..e07e0d4 100644 (file)
@@ -590,10 +590,13 @@ abstract class Text
                return res.to_s
        end
 
-       # Escape " \ ' and non printable characters using the rules of literal C strings and characters
+       # Escape `"` `\` `'`, trigraphs and non printable characters using the rules of literal C strings and characters
        #
-       #     assert "abAB12<>&".escape_to_c         == "abAB12<>&"
+       #     assert "abAB12<>&".escape_to_c       == "abAB12<>&"
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
+       #     assert "allo???!".escape_to_c        == "allo??\\?!"
+       #     assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)"
+       #     assert "??!??<??>??-".escape_to_c    == "?\\?!?\\?<?\\?>?\\?-"
        #
        # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
        # Three digits are always used to avoid following digits to be interpreted as an element
@@ -617,6 +620,24 @@ abstract class Text
                                b.append("\\\'")
                        else if c == '\\' then
                                b.append("\\\\")
+                       else if c == '?' then
+                               # Escape if it is the last question mark of a ANSI C trigraph.
+                               var j = i + 1
+                               if j < length then
+                                       var next = chars[j]
+                                       # We ignore `??'` because it will be escaped as `??\'`.
+                                       if
+                                               next == '!' or
+                                               next == '(' or
+                                               next == ')' or
+                                               next == '-' or
+                                               next == '/' or
+                                               next == '<' or
+                                               next == '=' or
+                                               next == '>'
+                                       then b.add('\\')
+                               end
+                               b.add('?')
                        else if c.code_point < 32 then
                                b.add('\\')
                                var oct = c.code_point.to_base(8)
@@ -640,6 +661,7 @@ abstract class Text
        # The result might no be legal in C but be used in other languages
        #
        #     assert "ab|\{\}".escape_more_to_c("|\{\}") == "ab\\|\\\{\\\}"
+       #     assert "allo???!".escape_more_to_c("")     == "allo??\\?!"
        fun escape_more_to_c(chars: String): String
        do
                var b = new Buffer
index 9e70321..6273609 100644 (file)
@@ -225,6 +225,22 @@ redef class FlatText
                                req_esc += 1
                        else if c == 0x5Cu8 then
                                req_esc += 1
+                       else if c == 0x3Fu8 then
+                               var j = pos + 1
+                               if j < length then
+                                       var next = its[j]
+                                       # We ignore `??'` because it will be escaped as `??\'`.
+                                       if
+                                               next == 0x21u8 or
+                                               next == 0x28u8 or
+                                               next == 0x29u8 or
+                                               next == 0x2Du8 or
+                                               next == 0x2Fu8 or
+                                               next == 0x3Cu8 or
+                                               next == 0x3Du8 or
+                                               next == 0x3Eu8
+                                       then req_esc += 1
+                               end
                        else if c < 32u8 then
                                req_esc += 3
                        end
@@ -280,6 +296,27 @@ redef class FlatText
                                nns[opos] = 0x5Cu8
                                nns[opos + 1] = 0x5Cu8
                                opos += 2
+                       else if c == 0x3Fu8 then
+                               var j = pos + 1
+                               if j < length then
+                                       var next = its[j]
+                                       # We ignore `??'` because it will be escaped as `??\'`.
+                                       if
+                                               next == 0x21u8 or
+                                               next == 0x28u8 or
+                                               next == 0x29u8 or
+                                               next == 0x2Du8 or
+                                               next == 0x2Fu8 or
+                                               next == 0x3Cu8 or
+                                               next == 0x3Du8 or
+                                               next == 0x3Eu8
+                                       then
+                                               nns[opos] = 0x5Cu8
+                                               opos += 1
+                                       end
+                               end
+                               nns[opos] = 0x3Fu8
+                               opos += 1
                        else if c < 32u8 then
                                nns[opos] = 0x5Cu8
                                nns[opos + 1] = 0x30u8
diff --git a/lib/core/text/test_abstract_text.nit b/lib/core/text/test_abstract_text.nit
new file mode 100644 (file)
index 0000000..c67a991
--- /dev/null
@@ -0,0 +1,61 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT.  This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A
+# PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You  are  allowed  to  redistribute it and sell it, alone or is a part of
+# another product.
+
+module test_abstract_text is test_suite
+
+import test_suite
+import text
+intrude import ropes
+
+class TestText
+       super TestSuite
+
+       private var factories: Collection[TextFactory] = [
+               new ConcatFactory,
+               new RopeBufferFactory,
+               new FlatBufferFactory
+       : TextFactory]
+
+       fun test_escape_to_c do
+               for f in factories do
+                       assert f.create("abAB12<>&").escape_to_c       == "abAB12<>&"
+                       assert f.create("\n\"'\\").escape_to_c         == "\\n\\\"\\'\\\\"
+                       assert f.create("allo???!").escape_to_c        == "allo??\\?!"
+                       assert f.create("??=??/??'??(??)").escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)"
+                       assert f.create("??!??<??>??-").escape_to_c    == "?\\?!?\\?<?\\?>?\\?-"
+               end
+       end
+end
+
+# A factory that creates instances of a particular implementation of `Text`
+interface TextFactory
+
+       # Create a `Text` instance from the specified string
+       fun create(s: String): Text is abstract
+end
+
+
+class ConcatFactory
+       super TextFactory
+
+       redef fun create(s) do return new Concat("", s)
+end
+
+class RopeBufferFactory
+       super TextFactory
+
+       redef fun create(s) do return new RopeBuffer.from(s)
+end
+
+class FlatBufferFactory
+       super TextFactory
+
+       redef fun create(s) do return new FlatBuffer.from(s)
+end
index 37fa87e..315d76f 100644 (file)
@@ -21,15 +21,19 @@ module htcpcp_server
 
 import nitcorn
 
+# Nitcorn Action used to answer requests.
 class HTCPCPAction
        super Action
+
+       # Brewing status.
        var brewing = false
-  var is_teapot = false
+
+       # Teapot status.
+       var is_teapot = false
 
        redef fun answer(http_request, turi) do
                var message: String
                var method = http_request.method
-               var headers = http_request.header
                var response: HttpResponse
 
                if is_teapot == true then
@@ -77,10 +81,13 @@ class HTCPCPAction
        end
 end
 
-
+# Nitcorn server.
 class HTCPCServer
+
+       # Port to listen to.
        var port: Int
 
+       # Start listening.
        fun run do
                var vh = new VirtualHost("localhost:{port}")
                vh.routes.add new Route("/", new HTCPCPAction)
index 9e94493..1833fca 100644 (file)
@@ -24,7 +24,7 @@ import core
 
 # A request received over HTTP, is build by `HttpRequestParser`
 class HttpRequest
-       private init do end
+       private init is old_style_init do end
 
        # HTTP protocol version
        var http_version: String
@@ -114,6 +114,7 @@ class HttpRequestParser
        # Words of the first line
        private var first_line = new Array[String]
 
+       # Parse the `first_line`, `header_fields` and `body` of `full_request`.
        fun parse_http_request(full_request: String): nullable HttpRequest
        do
                clear_data
index 3d0fd33..08d2968 100644 (file)
@@ -97,7 +97,8 @@ class HttpStatusCodes
        # All know code and their message
        var codes = new HashMap[Int, String]
 
-       protected init do insert_status_codes
+       # Init the status `codes` list.
+       protected init is old_style_init do insert_status_codes
 
        # Get the message associated to the status `code`, return `null` in unknown
        fun [](code: Int): nullable String
index 37dd9db..305f314 100644 (file)
@@ -20,6 +20,8 @@ module media_types
 
 # Map of known MIME types
 class MediaTypes
+
+       # MIME types by extensions.
        protected var types = new HashMap[String, String]
 
        # Get the type/subtype associated to a file extension `ext`
@@ -106,4 +108,5 @@ class MediaTypes
        end
 end
 
+# MIME types list.
 fun media_types: MediaTypes do return once new MediaTypes
index 12db3df..bc59692 100644 (file)
@@ -17,8 +17,4 @@
 NITUNIT=../../bin/nitunit
 
 check:
-       $(NITUNIT) README.md
-       $(NITUNIT) pop_routes.nit
-       $(NITUNIT) pop_handlers.nit
-       $(NITUNIT) popcorn.nit
-       cd tests; make check
+       $(NITUNIT) .
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_angular is test_suite
+
+import pop_tests
 import example_angular
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleAngular
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                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("../examples/angular/www/", "index.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
+       fun test_example_param_route do
+               var app = new App
+               app.use("/counter", new CounterAPI)
+               app.use("/*", new StaticHandler("../examples/angular/www/", "index.html"))
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_post_handler is test_suite
+
+import pop_tests
 import example_post_handler
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleQueryString
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/ -X POST"
                system "curl -s {host}:{port}/ --data 'user'"
                system "curl -s {host}:{port}/ --data 'user=Morriar'"
                system "curl -s {host}:{port}/ --data 'user=\&order=desc'"
                system "curl -s {host}:{port}/ --data 'user=Morriar\&order=desc'"
-
                system "curl -s {host}:{port}/"
-               return null
        end
-end
-
-var app = new App
-app.use("/", new PostHandler)
-
-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
+       fun test_example_glob_route do
+               var app = new App
+               app.use("/", new PostHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_query_string is test_suite
+
+import pop_tests
 import example_query_string
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleQueryString
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/?user=Morriar"
                system "curl -s {host}:{port}/?reload"
                system "curl -s {host}:{port}/?foo\\&bar=baz"
                system "curl -s {host}:{port}/?items=10\\&order=asc"
-               return null
        end
-end
-
-var app = new App
-app.use("/", new QueryStringHandler)
-
-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
+       fun test_example_glob_route do
+               var app = new App
+               app.use("/", new QueryStringHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_hello is test_suite
+
+import pop_tests
 import example_hello
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleHello
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}"
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}///////////"
                system "curl -s {host}:{port}/not_found"
                system "curl -s {host}:{port}/not_found/not_found"
-               return null
        end
-end
-
-var app = new App
-app.use("/", new HelloHandler)
-
-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
+       fun test_example_hello do
+               var app = new App
+               app.use("/", new HelloHandler)
+               run_test(app)
+       end
+end
@@ -26,4 +26,4 @@
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_advanced_logger is test_suite
+
+import pop_tests
 import example_advanced_logger
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleAdvancedLogger
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/about"
-               return null
        end
-end
-
-var app = new App
-app.use_before("/*", new RequestTimeHandler)
-app.use("/", new HelloHandler)
-app.use_after("/*", new LogHandler)
-
-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
+       fun test_example_param_route do
+               var app = new App
+               app.use_before("/*", new RequestTimeHandler)
+               app.use("/", new HelloHandler)
+               app.use_after("/*", new LogHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_html_error_handler is test_suite
+
+import pop_tests
 import example_html_error_handler
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleHtmlErrorHandler
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/about"
-               return null
        end
-end
-
-var app = new App
-app.use("/*", new HtmlErrorHandler)
-
-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
+       fun test_example_param_route do
+               var app = new App
+               app.use("/*", new HtmlErrorHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_simple_error_handler is test_suite
+
+import pop_tests
 import example_simple_error_handler
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleSimpleErrorHandler
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/about"
-               return null
        end
-end
-
-var app = new App
-app.use("/", new HelloHandler)
-app.use("/*", new SimpleErrorHandler)
-
-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
+       fun test_example_param_route do
+               var app = new App
+               app.use("/", new HelloHandler)
+               app.use("/*", new SimpleErrorHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_simple_logger is test_suite
+
+import pop_tests
 import example_simple_logger
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleSimpleLogger
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/about"
-               return null
        end
-end
-
-var app = new App
-app.use_before("/*", new LogHandler)
-app.use("/", new HelloHandler)
-
-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
+       fun test_example_param_route do
+               var app = new App
+               app.use_before("/*", new LogHandler)
+               app.use("/", new HelloHandler)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_glob_route is test_suite
+
+import pop_tests
 import example_glob_route
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleGlobRoute
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/user/Morriar/item/10"
                system "curl -s {host}:{port}/user/Morriar/item/10/"
                system "curl -s {host}:{port}/user/Morriar/item/10/profile"
                system "curl -s {host}:{port}/user/Morriar/item/10/profile/settings"
-
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/not_found"
                system "curl -s {host}:{port}/not_found/not_found"
-               return null
        end
-end
-
-var app = new App
-app.use("/user/:user/item/:item/*", new UserItem)
-
-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
+       fun test_example_glob_route do
+               var app = new App
+               app.use("/user/:user/item/:item/*", new UserItem)
+               run_test(app)
+       end
+end
@@ -39,4 +39,4 @@ Here the item 10 of the use Morriar.
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_param_route is test_suite
+
+import pop_tests
 import example_param_route
-import base_tests
 
-class TestClient
-       super ClientThread
+class TestExampleParamRoute
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/Morriar"
                system "curl -s {host}:{port}//"
-
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/not_found"
                system "curl -s {host}:{port}/not_found/not_found"
-               return null
        end
-end
-
-var app = new App
-app.use("/:user", new UserHome)
-
-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
+       fun test_example_param_route do
+               var app = new App
+               app.use("/:user", new UserHome)
+               run_test(app)
+       end
+end
@@ -35,4 +35,4 @@ Hello not_found
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_router is test_suite
+
+import pop_tests
 import example_router
-import base_tests
 
-class HelloClient
-       super ClientThread
+class TestExampleRouter
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}"
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/user"
                system "curl -s {host}:{port}/user/"
                system "curl -s {host}:{port}/user/profile"
-
                system "curl -s {host}:{port}/not_found"
                system "curl -s {host}:{port}/user/not_found"
                system "curl -s {host}:{port}/products/not_found"
-               return null
        end
-end
-
-var user_router = new Router
-user_router.use("/*", new UserLogger)
-user_router.use("/", new UserHome)
-user_router.use("/profile", new UserProfile)
-
-var app = new App
-app.use("/", new AppHome)
-app.use("/user", user_router)
 
-var host = test_host
-var port = test_port
-
-var server = new AppThread(host, port, app)
-server.start
-0.1.sleep
-
-var client = new HelloClient(host, port)
-client.start
-client.join
-0.1.sleep
-
-exit 0
+       fun test_example_router do
+               var user_router = new Router
+               user_router.use("/*", new UserLogger)
+               user_router.use("/", new UserHome)
+               user_router.use("/profile", new UserProfile)
+               var app = new App
+               app.use("/", new AppHome)
+               app.use("/user", user_router)
+               run_test(app)
+       end
+end
@@ -45,4 +45,4 @@ User logged
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+module test_example_session is test_suite
+
+import pop_tests
 import example_session
-import base_tests
 
-class HelloClient
-       super ClientThread
+class TestExampleSession
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test do
                system "curl -s {host}:{port}/"
                system "curl -s {host}:{port}/ -X POST"
-
                system "curl -s {host}:{port}/not_found"
                system "curl -s {host}:{port}/user/not_found"
                system "curl -s {host}:{port}/products/not_found"
-               return null
        end
-end
-
-var app = new App
-app.use("/*", new SessionInit)
-app.use("/", new AppLogin)
-
-var host = test_host
-var port = test_port
 
-var server = new AppThread(host, port, app)
-server.start
-0.1.sleep
-
-var client = new HelloClient(host, port)
-client.start
-client.join
-0.1.sleep
-
-exit 0
+       fun test_example_param_route do
+               var app = new App
+               app.use("/*", new SessionInit)
+               app.use("/", new AppLogin)
+               run_test(app)
+       end
+end
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import base_tests
+module test_example_static is test_suite
+
+import pop_tests
 import example_static
 
-class TestClient
-       super ClientThread
+class TestExampleStatic
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test 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"
+       end
 
-               return null
+       fun test_example_param_route do
+               var app = new App
+               app.use("/", new StaticHandler("../examples/static_files/public/"))
+               run_test(app)
        end
 end
-
-var app = new App
-app.use("/", new StaticHandler("../examples/static_files/public/"))
-
-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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import base_tests
+module test_example_static_default is test_suite
+
+import pop_tests
 import example_static_default
 
-class TestClient
-       super ClientThread
+class TestExampleStaticDefault
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test 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"
+       end
 
-               return null
+       fun test_example_param_route do
+               var app = new App
+               app.use("/", new StaticHandler("../examples/static_files/public/", "default.html"))
+               run_test(app)
        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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import base_tests
+module test_example_static_multiple is test_suite
+
+import pop_tests
 import example_static_multiple
 
-class TestClient
-       super ClientThread
+class TestExampleStaticMultiple
+       super TestPopcorn
 
-       redef fun main do
+       redef fun client_test 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}/static/css/style.css"
                system "curl -s {host}:{port}/static/js/app.js"
                system "curl -s {host}:{port}/static/hello.html"
                system "curl -s {host}:{port}/static/"
-
                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"
+       end
 
-               return null
+       fun test_example_param_route do
+               var app = new App
+               app.use("/", new StaticHandler("../examples/static_files/public/"))
+               app.use("/", new StaticHandler("../examples/static_files/files/"))
+               app.use("/static", new StaticHandler("../examples/static_files/public/"))
+               app.use("/static", new StaticHandler("../examples/static_files/files/"))
+               run_test(app)
        end
 end
-
-var app = new App
-app.use("/", new StaticHandler("../examples/static_files/public/"))
-app.use("/", new StaticHandler("../examples/static_files/files/"))
-app.use("/static", new StaticHandler("../examples/static_files/public/"))
-app.use("/static", new StaticHandler("../examples/static_files/files/"))
-
-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
diff --git a/lib/popcorn/pop_tests.nit b/lib/popcorn/pop_tests.nit
new file mode 100644 (file)
index 0000000..1deaeab
--- /dev/null
@@ -0,0 +1,162 @@
+# 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.
+
+# Popcorn testing services
+#
+# ## Blackbox testing
+#
+# Popcorn allows you to test your apps using nitunit blackbox testing.
+#
+# With blackbox testing you compare the output of your program with a result file.
+#
+# To get started with blackbox testing, create a nitunit test suite and imports
+# the `pop_tests` module.
+#
+# You then need to build the app that will be tested by nitunit as shown in the
+# `test_example_hello` method.
+# Calling `run_test` will automatically set the `host` and `port` used for testing.
+#
+# Redefine the `client_test` method to write your scenario.
+# Here we use `curl` to access some URI on the app.
+#
+# ~~~nitish
+# module test_example_hello is test_suite
+#
+# import pop_tests
+# import example_hello
+#
+# class TestExampleHello
+#      super TestPopcorn
+#
+#      fun test_example_hello do
+#              var app = new App
+#              app.use("/", new HelloHandler)
+#              run_test(app)
+#      end
+#
+#      redef fun client_test do
+#              system "curl -s {host}:{port}"
+#              system "curl -s {host}:{port}/"
+#              system "curl -s {host}:{port}///////////"
+#              system "curl -s {host}:{port}/not_found"
+#              system "curl -s {host}:{port}/not_found/not_found"
+#      end
+# end
+# ~~~
+#
+# The blackbox testing needs a reference result file against wich the test output
+# will be compared.
+# Create your expected result file in `test_example_hello.sav/test_example_hello.res`.
+#
+# Test your app by running nitunit:
+#
+# ~~~bash
+# nitunit ./example_hello.nit
+# ~~~
+#
+# See `examples/hello_world` for the complete example.
+module pop_tests
+
+import test_suite
+import popcorn
+import pthreads
+
+redef class Sys
+
+       # Use localhost for testing
+       var test_host = "localhost"
+
+       # Return a new port for each instance
+       fun test_port: Int do
+               srand
+               return 10000+20000.rand
+       end
+end
+
+# Thread running the App to test.
+class AppThread
+       super Thread
+
+       # Host used by tested App.
+       var host: String
+
+       # Port used by tested App.
+       var port: Int
+
+       # App to test.
+       var app: App
+
+       redef fun main
+       do
+               # Hide testing concept to force nitcorn to actually run
+               "NIT_TESTING".setenv("false")
+               app.quiet = true
+               app.listen(host, port)
+               return null
+       end
+end
+
+# Thread running the test client.
+class ClientThread
+       super Thread
+
+       # Test suite to execute.
+       var test_suite: TestPopcorn
+
+       redef fun main do
+               test_suite.client_test
+               print ""
+               return null
+       end
+end
+
+# TestSuite for Popcorn blackbox testing.
+class TestPopcorn
+       super TestSuite
+
+       # Host used to run App.
+       var host: String = test_host
+
+       # Port used to run App.
+       var port: Int = test_port
+
+       # Run the test suite on the App.
+       fun run_test(app: App) do
+               var server = new AppThread(host, port, app)
+               server.start
+               0.1.sleep
+
+               var client = new ClientThread(self)
+               client.start
+               client.join
+               0.1.sleep
+
+               exit 0
+       end
+
+       # Redefine this method to implement your test scenario.
+       fun client_test do end
+
+       # Regex to catch and hide the port from the output to get consistent results
+       var host_re: Regex = "localhost:\[0-9\]+".to_re
+
+       # Execute a System function.
+       fun system(cmd: String, title: nullable String)
+       do
+               title = title or else cmd
+               title = title.replace(host_re, "localhost:*****")
+               print "\n[Client] {title}"
+               sys.system cmd
+       end
+end
diff --git a/lib/popcorn/test_popcorn.nit b/lib/popcorn/test_popcorn.nit
new file mode 100644 (file)
index 0000000..108eb7a
--- /dev/null
@@ -0,0 +1,97 @@
+# 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.
+
+module test_popcorn is test_suite
+
+import pop_tests
+import popcorn
+
+class TestHandler
+       super Handler
+
+       var marker: String
+
+       redef fun get(req, res) do res.send marker
+end
+
+class TestPopcornRouter
+       super TestPopcorn
+
+       redef fun client_test do
+               system "curl -s {host}:{port}"
+               system "curl -s {host}:{port}/"
+               system "curl -s {host}:{port}/user"
+               system "curl -s {host}:{port}/user/"
+               system "curl -s {host}:{port}/user/settings"
+               system "curl -s {host}:{port}/products"
+               system "curl -s {host}:{port}/products/"
+               system "curl -s {host}:{port}/products/list"
+               system "curl -s {host}:{port}/not_found"
+               system "curl -s {host}:{port}/user/not_found"
+               system "curl -s {host}:{port}/products/not_found"
+       end
+
+       fun test_router do
+               var app = new App
+               app.use("/", new TestHandler("/"))
+               app.use("/about", new TestHandler("/about"))
+
+               var router1 = new App
+               router1.use("/", new TestHandler("/user"))
+               router1.use("/settings", new TestHandler("/user/settings"))
+               app.use("/user", router1)
+
+               var router2 = new App
+               router2.use("/", new TestHandler("/products"))
+               router2.use("/list", new TestHandler("/products/list"))
+               app.use("/products", router2)
+
+               run_test(app)
+       end
+end
+
+class TestPopcornRoutes
+       super TestPopcorn
+
+       redef fun client_test do
+               system "curl -s {host}:{port}"
+               system "curl -s {host}:{port}/"
+               system "curl -s {host}:{port}/misc"
+               system "curl -s {host}:{port}/misc/foo"
+               system "curl -s {host}:{port}/misc/foo/bar"
+               system "curl -s {host}:{port}/misc/foo/baz"
+               system "curl -s {host}:{port}/user"
+               system "curl -s {host}:{port}/user/"
+               system "curl -s {host}:{port}/user/id"
+               system "curl -s {host}:{port}/user/id/profile"
+               system "curl -s {host}:{port}/user/id/misc/foo"
+               system "curl -s {host}:{port}/user/id/misc/foo/bar"
+               system "curl -s {host}:{port}/user/id/misc/foo/bar/baz"
+               system "curl -s {host}:{port}/not_found"
+               system "curl -s {host}:{port}/user/id/not_found"
+       end
+
+       fun test_routes do
+               var app = new App
+               app.use("/", new TestHandler("/"))
+               app.use("/user", new TestHandler("/user"))
+               app.use("/misc/*", new TestHandler("/misc/everything"))
+               app.use("/user/:id", new TestHandler("/user/id"))
+               app.use("/user/:id/profile", new TestHandler("/user/id/profile"))
+               app.use("/user/:id/misc/*", new TestHandler("/user/id/misc/everything"))
+               run_test(app)
+       end
+end
similarity index 98%
rename from lib/popcorn/tests/res/test_router.res
rename to lib/popcorn/test_popcorn.sav/test_router.res
index 37be3a6..1022411 100644 (file)
@@ -47,4 +47,4 @@
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
similarity index 99%
rename from lib/popcorn/tests/res/test_routes.res
rename to lib/popcorn/test_popcorn.sav/test_routes.res
index 0c1abfa..58e47d0 100644 (file)
@@ -46,4 +46,4 @@
                <body>
                <h1>404 Not Found</h1>
                </body>
-               </html>
\ No newline at end of file
+               </html>
diff --git a/lib/popcorn/tests/Makefile b/lib/popcorn/tests/Makefile
deleted file mode 100644 (file)
index 7e78098..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2013 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.
-
-all: tests
-
-check: clean
-       ./tests.sh
-
-clean:
-       rm -rf out/
diff --git a/lib/popcorn/tests/base_tests.nit b/lib/popcorn/tests/base_tests.nit
deleted file mode 100644 (file)
index a56a33d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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 popcorn
-import pthreads
-
-redef class Sys
-       var test_host = "localhost"
-
-       # Return a new port for each instance
-       fun test_port: Int do
-               srand
-               return 10000+20000.rand
-       end
-end
-
-class AppThread
-       super Thread
-
-       var host: String
-       var port: Int
-       var app: App
-
-       redef fun main
-       do
-               # Hide testing concept to force nitcorn to actually run
-               "NIT_TESTING".setenv("false")
-               app.quiet = true
-               app.listen(host, port)
-               return null
-       end
-end
-
-class ClientThread
-       super Thread
-
-       var host: String
-       var port: Int
-
-       redef fun main do return null
-
-       # Regex to catch and hide the port from the output to get consistent results
-       var host_re: Regex = "localhost:\[0-9\]+".to_re
-
-       fun system(cmd: String, title: nullable String)
-       do
-               title = title or else cmd
-               title = title.replace(host_re, "localhost:*****")
-               print "\n[Client] {title}"
-               sys.system cmd
-       end
-end
diff --git a/lib/popcorn/tests/test_router.nit b/lib/popcorn/tests/test_router.nit
deleted file mode 100644 (file)
index 915ce4a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# 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
-
-class TestHandler
-       super Handler
-
-       var marker: String
-
-       redef fun get(req, res) do res.send marker
-end
-
-class HelloClient
-       super ClientThread
-
-       redef fun main do
-               system "curl -s {host}:{port}"
-               system "curl -s {host}:{port}/"
-               system "curl -s {host}:{port}/user"
-               system "curl -s {host}:{port}/user/"
-               system "curl -s {host}:{port}/user/settings"
-               system "curl -s {host}:{port}/products"
-               system "curl -s {host}:{port}/products/"
-               system "curl -s {host}:{port}/products/list"
-
-               system "curl -s {host}:{port}/not_found"
-               system "curl -s {host}:{port}/user/not_found"
-               system "curl -s {host}:{port}/products/not_found"
-               return null
-       end
-end
-
-var app = new App
-app.use("/", new TestHandler("/"))
-app.use("/about", new TestHandler("/about"))
-
-var router1 = new App
-router1.use("/", new TestHandler("/user"))
-router1.use("/settings", new TestHandler("/user/settings"))
-app.use("/user", router1)
-
-var router2 = new App
-router2.use("/", new TestHandler("/products"))
-router2.use("/list", new TestHandler("/products/list"))
-app.use("/products", router2)
-
-var host = test_host
-var port = test_port
-
-var server = new AppThread(host, port, app)
-server.start
-0.1.sleep
-
-var client = new HelloClient(host, port)
-client.start
-client.join
-0.1.sleep
-
-exit 0
diff --git a/lib/popcorn/tests/test_routes.nit b/lib/popcorn/tests/test_routes.nit
deleted file mode 100644 (file)
index 2db660a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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
-
-class TestHandler
-       super Handler
-
-       var marker: String
-
-       redef fun get(req, res) do res.send marker
-end
-
-class HelloClient
-       super ClientThread
-
-       redef fun main do
-               system "curl -s {host}:{port}"
-               system "curl -s {host}:{port}/"
-
-               system "curl -s {host}:{port}/misc"
-               system "curl -s {host}:{port}/misc/foo"
-               system "curl -s {host}:{port}/misc/foo/bar"
-               system "curl -s {host}:{port}/misc/foo/baz"
-
-               system "curl -s {host}:{port}/user"
-               system "curl -s {host}:{port}/user/"
-               system "curl -s {host}:{port}/user/id"
-               system "curl -s {host}:{port}/user/id/profile"
-               system "curl -s {host}:{port}/user/id/misc/foo"
-               system "curl -s {host}:{port}/user/id/misc/foo/bar"
-               system "curl -s {host}:{port}/user/id/misc/foo/bar/baz"
-
-               system "curl -s {host}:{port}/not_found"
-               system "curl -s {host}:{port}/user/id/not_found"
-               return null
-       end
-end
-
-var app = new App
-app.use("/", new TestHandler("/"))
-app.use("/user", new TestHandler("/user"))
-app.use("/misc/*", new TestHandler("/misc/everything"))
-app.use("/user/:id", new TestHandler("/user/id"))
-app.use("/user/:id/profile", new TestHandler("/user/id/profile"))
-app.use("/user/:id/misc/*", new TestHandler("/user/id/misc/everything"))
-
-var host = test_host
-var port = test_port
-
-# First, launch a server in the background
-var server = new AppThread(host, port, app)
-server.start
-0.1.sleep
-
-# Then, launch a client running test requests
-var client = new HelloClient(host, port)
-client.start
-client.join
-0.1.sleep
-
-# Force quit the server
-exit 0
diff --git a/lib/popcorn/tests/tests.sh b/lib/popcorn/tests/tests.sh
deleted file mode 100755 (executable)
index 4406058..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-BIN=../bin
-OUT=./out
-RES=./res
-
-NITC=../../../bin/nitc
-
-compile() {
-       local test="$1"
-       $NITC $test.nit -o $OUT/$test.bin 1>&2 2> $OUT/$test.cmp_err
-}
-
-test_prog()
-{
-       local test="$1"
-
-       chmod +x $OUT/$test.bin 2> $OUT/$test.err
-       $OUT/$test.bin > $OUT/$test.res 2> $OUT/$test.err
-
-       diff $OUT/$test.res $RES/$test.res > $OUT/$test.diff 2> /dev/null
-}
-
-# return
-#  0 if the sav not exists
-#  1 if the file does match
-#  2 if the file does not match
-check_result() {
-       local test="$1"
-
-       if [ -s "$OUT/$test.cmp_err" ]; then
-               return 0
-       elif [ -s "$OUT/$test.err" ]; then
-               return 1
-       elif [ ! -r "$RES/$test.res" ]; then
-               return 2
-       elif [ -s "$OUT/$test.diff" ]; then
-               return 3
-       else
-               return 4
-       fi
-}
-
-echo "Testing..."
-echo ""
-
-rm -rf $OUT 2>/dev/null
-mkdir $OUT 2>/dev/null
-
-all=0
-ok=0
-ko=0
-sk=0
-
-for file in `ls test_*.nit`; do
-       ((all++))
-       test="${file%.*}"
-       echo -n "* $test: "
-
-       compile $test
-       test_prog $test
-       check_result $test
-
-       case "$?" in
-               0)
-                       echo "compile error (cat $OUT/$test.cmp_err)"
-                       ((ko++))
-                       ;;
-               1)
-                       echo "error (cat $OUT/$test.cmp_err)"
-                       ((ko++))
-                       ;;
-               2)
-                       echo "skip ($test.res not found)"
-                       ((sk++))
-                       continue;;
-               3)
-                       echo "error (diff $OUT/$test.res $RES/$test.res)"
-                       ((ko++))
-                       ;;
-               4)
-                       echo "success"
-                       ((ok++))
-                       ;;
-
-       esac
-done
-echo ""
-echo "==> success $ok/$all ($ko tests failed, $sk skipped)"
-
-# return result
-test "$ok" == "$all"
index 23b7382..2bec157 100644 (file)
@@ -129,18 +129,25 @@ This flag can be used by libraries and program to prevent (or limit) the executi
 
 ## Working with `TestSuites`
 
-TestSuites are Nit files that define a set of TestCases for a particular module.
+TestSuites are Nit modules that define a set of TestCases.
 
-The test suite must be called `test_` followed by the name of the module to test.
-So for the module `foo.nit` the test suite will be called `test_foo.nit`.
+A test suite is a module that uses the annotation `is test_suite`.
+
+It is common that a test suite focuses on testing a single module.
+In this case, the name of the test_suite is often `test_foo.nit` where `foo.nit` is the tested module.
 
 The structure of a test suite is the following:
 
 ~~~~
 # test suite for module `foo`
-module test_foo
+module test_foo is test_suite
+
+import test_suite
 import foo # can be intrude to test private things
+
 class TestFoo
+       super TestSuite
+
     # test case for `foo::Foo::baz`
     fun test_baz do
         var subject = new Foo
@@ -153,11 +160,13 @@ Test suite can be executed using the same `nitunit` command:
 
     $ nitunit foo.nit
 
-`nitunit` will execute a test for each method named `test_*` in a class named `Test*`
-so multiple tests can be executed for a single method:
+`nitunit` will execute a test for each method named `test_*` in a class
+subclassing `TestSuite` so multiple tests can be executed for a single method:
 
 ~~~~
 class TestFoo
+       super TestSuite
+
     fun test_baz_1 do
         var subject = new Foo
         assert subject.baz(1, 2) == 3
@@ -196,7 +205,10 @@ The test is failed if non-zero is returned by `diff`.
 
 ~~~
 module test_mod is test_suite
+
 class TestFoo
+       super TestSuite
+
        fun test_bar do
                print "Hello!"
        end
@@ -216,13 +228,14 @@ To helps the management of the expected results, the option `--autosav` can be u
 
 ## Configuring TestSuites
 
-`TestSuites` also provide methods to configure the test run:
+`TestSuite`s also provide methods to configure the test run:
 
 `before_test` and `after_test`: methods called before/after each test case.
 They can be used to factorize repetitive tasks:
 
 ~~~~
 class TestFoo
+       super TestSuite
     var subject: Foo
     # Mandatory empty init
     init do end
@@ -308,9 +321,6 @@ Only run test case with name that match pattern.
 
 Examples: `TestFoo`, `TestFoo*`, `TestFoo::test_foo`, `TestFoo::test_foo*`, `test_foo`, `test_foo*`
 
-### `-t`, `--target-file`
-Specify test suite location.
-
 ### `--autosav`
 Automatically create/update .res files for black box testing.
 
index d1a4ce5..d1626cb 100644 (file)
@@ -700,7 +700,7 @@ redef class ModelBuilder
                if decl != null then
                        var decl_name = decl.n_name.n_id.text
                        if decl_name != mmodule.name then
-                               error(decl.n_name, "Error: module name mismatch; declared {decl_name} file named {mmodule.name}.")
+                               warning(decl.n_name, "module-name-mismatch", "Error: module name mismatch; declared {decl_name} file named {mmodule.name}.")
                        end
                end
 
index 5c478f0..42dc5dd 100644 (file)
@@ -561,10 +561,16 @@ end
 
 # Get files or groups
 var args = tc.option_context.rest
+var mmodules
 if opt_no_parse.value then
-       modelbuilder.scan_full(args)
+       mmodules = modelbuilder.scan_full(args)
 else
-       modelbuilder.parse_full(args)
+       mmodules = modelbuilder.parse_full(args)
+end
+var mpackages = new Set[MPackage]
+for m in mmodules do
+       var p = m.mpackage
+       if p != null then mpackages.add p
 end
 
 # Scan packages and compute information
@@ -586,7 +592,7 @@ for p in model.mpackages do
        end
 end
 
-if not opt_no_git.value then for p in model.mpackages do
+if not opt_no_git.value then for p in mpackages do
        catalog.git_info(p)
 end
 
@@ -703,7 +709,7 @@ css.write_to_file(out/"style.css")
 
 # PAGES
 
-for p in model.mpackages do
+for p in mpackages do
        # print p
        var f = "p/{p.name}.html"
        catalog.package_page(p)
@@ -726,7 +732,7 @@ index.add catalog.list_best(catalog.score)
 if catalog.deps.not_empty then
        index.add "<h2>Most Required</h2>\n"
        var reqs = new Counter[MPackage]
-       for p in model.mpackages do
+       for p in mpackages do
                reqs[p] = catalog.deps[p].smallers.length - 1
        end
        index.add catalog.list_best(reqs)
@@ -743,7 +749,7 @@ index.add """
 <div class="sidebar">
 <h3>Stats</h3>
 <ul class="box">
-<li>{{{model.mpackages.length}}} packages</li>
+<li>{{{mpackages.length}}} packages</li>
 <li>{{{catalog.maint2proj.length}}} maintainers</li>
 <li>{{{catalog.contrib2proj.length}}} contributors</li>
 <li>{{{catalog.tag2proj.length}}} tags</li>
@@ -775,6 +781,6 @@ page = catalog.new_page("")
 page.more_head.add "<title>Projets of Nit</title>"
 page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
 page.add "<h2>Table of Projets</h2>\n"
-page.add catalog.table_packages(model.mpackages)
+page.add catalog.table_packages(mpackages.to_a)
 page.add "</div>\n"
 page.write_to_file(out/"table.html")
index c9aa8ae..996fe27 100644 (file)
@@ -20,7 +20,7 @@ import testing
 
 var toolcontext = new ToolContext
 
-toolcontext.option_context.add_option(toolcontext.opt_full, toolcontext.opt_output, toolcontext.opt_dir, toolcontext.opt_noact, toolcontext.opt_pattern, toolcontext.opt_file, toolcontext.opt_autosav, toolcontext.opt_gen_unit, toolcontext.opt_gen_force, toolcontext.opt_gen_private, toolcontext.opt_gen_show, toolcontext.opt_nitc)
+toolcontext.option_context.add_option(toolcontext.opt_full, toolcontext.opt_output, toolcontext.opt_dir, toolcontext.opt_noact, toolcontext.opt_pattern, toolcontext.opt_autosav, toolcontext.opt_gen_unit, toolcontext.opt_gen_force, toolcontext.opt_gen_private, toolcontext.opt_gen_show, toolcontext.opt_nitc)
 toolcontext.tooldescription = "Usage: nitunit [OPTION]... <file.nit>...\nExecutes the unit tests from Nit source files."
 
 toolcontext.process_options(args)
@@ -31,10 +31,6 @@ if toolcontext.opt_gen_unit.value then
                print "Option --pattern cannot be used with --gen-suite"
                exit(0)
        end
-       if toolcontext.opt_file.value != null then
-               print "Option --target-file cannot be used with --gen-suite"
-               exit(0)
-       end
 else
        if toolcontext.opt_gen_force.value then
                print "Option --force must be used with --gen-suite"
@@ -92,7 +88,8 @@ end
 
 for m in mmodules do
        page.add modelbuilder.test_markdown(m)
-       page.add modelbuilder.test_unit(m)
+       var ts = modelbuilder.test_unit(m)
+       if ts != null then page.add ts
 end
 
 var file = toolcontext.opt_output.value
index 814f7d2..75e0830 100644 (file)
@@ -274,7 +274,7 @@ class NitUnitExecutor
                if mmodule != null then
                        opts.add "-I {mmodule.filepath.dirname}"
                end
-               var cmd = "{nitc} --ignore-visibility --no-color '{file}' {opts.join(" ")} >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
+               var cmd = "{nitc} --ignore-visibility --no-color -q '{file}' {opts.join(" ")} >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
                var res = toolcontext.safe_exec(cmd)
                return res
        end
index a37d243..f102c6c 100644 (file)
@@ -20,8 +20,6 @@ import html
 private import annotation
 
 redef class ToolContext
-       # -- target-file
-       var opt_file = new OptionString("Specify test suite location", "-t", "--target-file")
        # --pattern
        var opt_pattern = new OptionString("Only run test case with name that match pattern", "-p", "--pattern")
        # --autosav
@@ -34,20 +32,9 @@ class NitUnitTester
        # `ModelBuilder` used to parse test files.
        var mbuilder: ModelBuilder
 
-       # Parse a file and return the contained `MModule`.
-       private fun parse_module_unit(file: String): nullable MModule do
-               var mmodule = mbuilder.parse([file]).first
-               if mbuilder.get_mmodule_annotation("test_suite", mmodule) == null then return null
-               mbuilder.run_phases
-               return mmodule
-       end
-
-       # Compile and execute the test suite for a NitUnit `file`.
-       fun test_module_unit(file: String): nullable TestSuite do
+       # Compile and execute `mmodule` as a test suite.
+       fun test_module_unit(mmodule: MModule): TestSuite do
                var toolcontext = mbuilder.toolcontext
-               var mmodule = parse_module_unit(file)
-               # is the module a test_suite?
-               if mmodule == null then return null
                var suite = new TestSuite(mmodule, toolcontext)
                # method to execute before all tests in the module
                var before_module = mmodule.before_test
@@ -210,7 +197,7 @@ class TestSuite
                        return
                end
                var include_dir = module_file.filename.dirname
-               var cmd = "{nitc} --no-color '{file}.nit' -I {include_dir} -o '{file}.bin' > '{file}.out' 2>&1 </dev/null"
+               var cmd = "{nitc} --no-color -q '{file}.nit' -I {include_dir} -o '{file}.bin' > '{file}.out' 2>&1 </dev/null"
                var res = toolcontext.safe_exec(cmd)
                var f = new FileReader.open("{file}.out")
                var msg = f.read_all
@@ -344,7 +331,7 @@ end
 
 redef class MClassDef
        # Is the class a TestClass?
-       # i.e. begins with "Test"
+       # i.e. is a subclass of `TestSuite`
        private fun is_test: Bool do
                var in_hierarchy = self.in_hierarchy
                if in_hierarchy == null then return false
@@ -389,33 +376,14 @@ redef class ModelBuilder
        # Number of failed tests.
        var failed_tests = 0
 
-       # Run NitUnit test file for mmodule (if exists).
-       fun test_unit(mmodule: MModule): HTMLTag do
-               var ts = new HTMLTag("testsuite")
-               toolcontext.info("nitunit: test-suite test_{mmodule}", 2)
-               var f = toolcontext.opt_file.value
-               var test_file = "test_{mmodule.name}.nit"
-               if f != null then
-                       test_file = f
-               else if not test_file.file_exists then
-                       var module_file = mmodule.location.file
-                       if module_file == null then
-                               toolcontext.info("Skip test for {mmodule}, no file found", 2)
-                               return ts
-                       end
-                       var include_dir = module_file.filename.dirname
-                       test_file = "{include_dir}/{test_file}"
-               end
-               if not test_file.file_exists then
-                       toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 2)
-                       return ts
-               end
+       # Run NitUnit test suite for `mmodule` (if it is one).
+       fun test_unit(mmodule: MModule): nullable HTMLTag do
+               # is the module a test_suite?
+               if get_mmodule_annotation("test_suite", mmodule) == null then return null
+               toolcontext.info("nitunit: test-suite {mmodule}", 2)
+
                var tester = new NitUnitTester(self)
-               var res = tester.test_module_unit(test_file)
-               if res == null then
-                       toolcontext.info("Skip test for {mmodule}, no test suite found", 2)
-                       return ts
-               end
+               var res = tester.test_module_unit(mmodule)
                return res.to_xml
        end
 end
index 2116656..f0bc3ee 100644 (file)
@@ -1,4 +1,4 @@
-test_nitunit.nit --no-color -o $WRITE
+test_nitunit.nit test_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 --no-color -o $WRITE
index 65ee58d..d64cff1 100644 (file)
@@ -22,7 +22,7 @@
 
 [OK] test_test_nitunit$TestX$test_foo2
 
-Docunits: Entities: 27; Documented ones: 4; With nitunits: 4; Failures: 3
+Docunits: Entities: 34; Documented ones: 6; 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.
@@ -32,5 +32,5 @@ Test suites: Classes: 1; Test Cases: 3; Failures: 1
 </system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><failure>Compilation error in nitunit.out&#47;test_nitunit-3.nit</failure><system-err>nitunit.out&#47;test_nitunit-3.nit:5,8--27: Error: method or variable `undefined_identifier` unknown in `Sys`.
 </system-err><system-out>assert undefined_identifier
 </system-out></testcase><testcase classname="nitunit.test_nitunit::test_nitunit.test_nitunit::X" name="test_nitunit::X::foo1"><failure>Syntax Error: unexpected operator &#39;!&#39;.</failure><system-out>assert !@#$%^&amp;*()
-</system-out></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><error>Runtime Error in file nitunit.out&#47;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::test_test_nitunit"></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&#47;gen_test_test_nitunit.nit</error><system-err>Runtime error: Assert failed (test_test_nitunit.nit:39)
 </system-err></testcase><testcase classname="nitunit.test_test_nitunit::test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err></testcase></testsuite></testsuites>
\ No newline at end of file
index cbfb8c5..7a74b0c 100644 (file)
@@ -19,4 +19,4 @@ end
 </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
+</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
index 38cb4c7..1c9dc40 100644 (file)
@@ -9,4 +9,4 @@ Test suites: Classes: 0; Test Cases: 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-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
+</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
index ff7185a..fa6339c 100644 (file)
@@ -19,4 +19,4 @@ Test suites: Classes: 0; Test Cases: 0
 assert true
 </system-out></testcase><testcase classname="nitunit.test_nitunit3&gt;" name="&lt;group&gt;#2"><failure>Syntax Error: unexpected malformed character &#39;\].</failure><system-out>;&#39;\][]
 </system-out></testcase></testsuite><testsuite package="test_nitunit3::test_nitunit3"><testcase classname="nitunit.test_nitunit3::test_nitunit3.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
-</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
+</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
index d9fdafc..d81c785 100644 (file)
@@ -13,4 +13,4 @@ Test suites: Classes: 0; Test Cases: 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>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out> *garbage*
 </system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo2"><failure>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out>*garbage*
 </system-out></testcase><testcase classname="nitunit.test_doc3::test_doc3.core::Sys" name="test_doc3::test_doc3::Sys::foo3"><failure>Syntax Error: unexpected identifier &#39;garbage&#39;.</failure><system-out>*garbage*
-</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
+</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
index 773614a..31a2cd3 100644 (file)
        After Test
 
 
+==== Test-suite of module test_nitunit4::test_nitunit4_base | tests: 0
+==== Test-suite of module test_nitunit4::test_nitunit4_base | tests: 0
+
 Docunits: Entities: 13; Documented ones: 0; With nitunits: 0
-Test suites: Classes: 1; Test Cases: 4; Failures: 3
+Test suites: Classes: 2; Test Cases: 4; Failures: 3
 [FAILURE] 3/4 tests failed.
 `nitunit.out` is not removed for investigation.
-<testsuites><testsuite package="test_nitunit4&gt;"></testsuite><testsuite package="test_nitunit4::nitunit4"></testsuite><testsuite package="test_nitunit4"><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_foo"><error>Runtime Error in file nitunit.out&#47;gen_test_nitunit4.nit</error><system-err>Before Test
+<testsuites><testsuite package="test_nitunit4&gt;"></testsuite><testsuite package="test_nitunit4::nitunit4"></testsuite><testsuite package="test_nitunit4::test_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&#47;gen_test_nitunit4.nit</error><system-err>Before Test
 Tested method
 After Test
 Runtime error: Assert failed (test_nitunit4&#47;test_nitunit4_base.nit:31)
@@ -50,4 +53,4 @@ After Test
 </system-err></testcase><testcase classname="nitunit.test_nitunit4::test_nitunit4.test_nitunit4::TestTestSuite" name="test_nitunit4::TestTestSuite::test_sav_conflict"><error>Conflicting expected output: test_nitunit4&#47;test_nitunit4.sav&#47;test_sav_conflict.res, test_nitunit4&#47;sav&#47;test_sav_conflict.res and test_nitunit4&#47;test_sav_conflict.res all exist</error><system-err>Before Test
 Tested method
 After Test
-</system-err></testcase></testsuite><testsuite package="test_nitunit4::test_nitunit4"></testsuite><testsuite></testsuite><testsuite package="test_nitunit4::test_nitunit4_base"></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
+</system-err></testcase></testsuite><testsuite package="test_nitunit4::test_nitunit4_base"></testsuite><testsuite package="test_nitunit4_base"></testsuite></testsuites>
\ No newline at end of file