Merge: String: Bugfixes
authorJean Privat <jean@pryen.org>
Wed, 3 Sep 2014 01:31:55 +0000 (21:31 -0400)
committerJean Privat <jean@pryen.org>
Wed, 3 Sep 2014 01:31:55 +0000 (21:31 -0400)
When rewriting the to_s method in Array, an error was subtle enough to fight its way through the tests but was discovered when reworking the Ropes (yup, be prepared, it'll appear once more).

Oh and there was a bug in the substring_from method (well, more of a lack of efficiency then a real bug).

Pull-Request: #699
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>

63 files changed:
VERSION
lib/android/assets_and_resources.nit
lib/android/audio.nit
lib/android/intent/intent_api11.nit
lib/android/intent/intent_api12.nit
lib/android/intent/intent_api14.nit
lib/android/intent/intent_api15.nit
lib/android/intent/intent_api16.nit
lib/android/intent/intent_api17.nit
lib/android/intent/intent_api18.nit
lib/android/intent/intent_api19.nit
lib/android/shared_preferences/shared_preferences_api11.nit
lib/java/io.nit [moved from lib/android/java_io.nit with 94% similarity]
lib/java/java.nit [moved from lib/java.nit with 99% similarity]
lib/mnit/mnit_app.nit
lib/mnit_linux/linux_app.nit
lib/string_experimentations/utf8_noindex.nit
lib/test_suite.nit [new file with mode: 0644]
src/nitunit.nit
src/testing/README [new file with mode: 0644]
src/testing/testing.nit [new file with mode: 0644]
src/testing/testing_base.nit [new file with mode: 0644]
src/testing/testing_doc.nit [new file with mode: 0644]
src/testing/testing_gen.nit [new file with mode: 0644]
src/testing/testing_suite.nit [new file with mode: 0644]
tests/cc.skip
tests/exec.skip
tests/listfull.sh
tests/niti.skip
tests/nitunit.args
tests/sav/android.res [deleted file]
tests/sav/ballz_android.res [deleted file]
tests/sav/complete_simple_android.res [deleted file]
tests/sav/dino_android.res [deleted file]
tests/sav/dino_linux.res [new file with mode: 0644]
tests/sav/emscripten.res [deleted file]
tests/sav/emscripten_nodejs.res [deleted file]
tests/sav/friendz.res [deleted file]
tests/sav/friendz_android.res [deleted file]
tests/sav/friendz_linux.res [new file with mode: 0644]
tests/sav/linux_app.res [new file with mode: 0644]
tests/sav/linux_assets.res [new file with mode: 0644]
tests/sav/mnit.res [deleted file]
tests/sav/mnit_android.res [deleted file]
tests/sav/mnit_linux.res [new file with mode: 0644]
tests/sav/mnit_null.res [new file with mode: 0644]
tests/sav/moles_android.res [deleted file]
tests/sav/moles_linux.res [new file with mode: 0644]
tests/sav/niti/mnit_injected_input.res [new file with mode: 0644]
tests/sav/nitunit_args1.res
tests/sav/nitunit_args2.res [new file with mode: 0644]
tests/sav/nitunit_args3.res [new file with mode: 0644]
tests/sav/pep8analysis_web.res [deleted file]
tests/sav/puzzle.res [new file with mode: 0644]
tests/sav/queens.res [new file with mode: 0644]
tests/sav/shoot_android.res [deleted file]
tests/sav/shoot_linux.res [new file with mode: 0644]
tests/sav/simple_android.res [deleted file]
tests/sav/simple_linux.res [new file with mode: 0644]
tests/sav/test_platform_android.res [deleted file]
tests/test_nitunit.nit
tests/test_test_nitunit.nit [new file with mode: 0644]
tests/tests.sh

diff --git a/VERSION b/VERSION
index 41a02af..ca46cd2 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.6.7
+v0.6.8
index d654641..ba304bd 100644 (file)
@@ -25,8 +25,8 @@
 module assets_and_resources
 
 import native_app_glue
-import java_io
 import java
+import java::io
 
 in "Java" `{
        import android.content.res.AssetManager;
index 480238f..9fe93e9 100644 (file)
@@ -22,7 +22,7 @@
 module audio
 
 import java
-import java_io
+import java::io
 import assets_and_resources
 import app
 
index bc97bb6..1ba5e88 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 11 services
-module intent_api11
+module intent_api11 is min_api_version(11)
 
 import intent
 
index b33b30f..ddf2cff 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 12 services
-module intent_api12
+module intent_api12 is min_api_version(12)
 
 import intent_api11
 
index c1f3ae1..3bb6576 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 14 services
-module intent_api14
+module intent_api14 is min_api_version(14)
 
 import intent_api12
 
index 4a73e44..4df53ce 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 15 services
-module intent_api15
+module intent_api15 is min_api_version(15)
 
 import intent_api14
 
index 85d73e8..74f6b0a 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 16 services
-module intent_api16
+module intent_api16 is min_api_version(16)
 
 import intent_api15
 
index 9e3ec13..0299a21 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 17 services
-module intent_api17
+module intent_api17 is min_api_version(17)
 
 import intent_api16
 
index 9e4e8a3..840bceb 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 18 services
-module intent_api18
+module intent_api18 is min_api_version(18)
 
 import intent_api17
 
index 9f4ac0d..73b1d8b 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines intent module to add API 19 services
-module intent_api19
+module intent_api19 is min_api_version(19)
 
 import intent_api18
 
index 4709ca5..50d88e9 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Refines shared_preferences module to add API 11 services
-module shared_preferences_api11
+module shared_preferences_api11 is min_api_version(11)
 
 import shared_preferences
 
similarity index 94%
rename from lib/android/java_io.nit
rename to lib/java/io.nit
index bcd70dc..04245a5 100644 (file)
@@ -1,4 +1,4 @@
-# this file is part of NIT ( http://www.nitlanguage.org ).
+# This file is part of NIT ( http://www.nitlanguage.org ).
 #
 # Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
 #
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# java io services
+# Services from the `java.io` package
 #
-# this module is used by `assets_and_resources` and `audio` for advanced purposes
-module java_io
+# This module is used by `android::assets_and_resources` and `android::audio`.
+module io
 
 import java
 
@@ -28,7 +28,6 @@ in "Java" `{
        import java.io.FileDescriptor;
        import java.io.IOException;
        import java.io.SyncFailedException;
-       import android.util.Log;
 `}
 
 extern class NativeFile in "Java" `{ java.io.File `}
@@ -42,7 +41,6 @@ extern class NativeFile in "Java" `{ java.io.File `}
                try {
                        return recv.createNewFile();
                }catch(IOException e){
-                       Log.e("Can't create file", e.getMessage());
                        e.printStackTrace();
                        return false;
                }
@@ -56,7 +54,6 @@ extern class NativeFile in "Java" `{ java.io.File `}
                try {
                        return recv.getCanonicalFile();
                }catch(IOException e){
-                       Log.e("Can't create file", e.getMessage());
                        e.printStackTrace();
                        return null;
                }
similarity index 99%
rename from lib/java.nit
rename to lib/java/java.nit
index a3da38d..d9d1f27 100644 (file)
@@ -24,7 +24,7 @@
 # of `Sys::jni_env`, and multiple JVM using `Sys::jvm`.
 #
 # The module `jvm` gives more control over the JVM instances and wraps
-# most of JNI functions. You can use it to further customize the behavior 
+# most of JNI functions. You can use it to further customize the behavior
 # of your code.
 module java is
        c_compiler_option("-I $(JAVA_HOME)/include/")
@@ -173,7 +173,7 @@ redef extern class JavaObject
                var jni_env = sys.jni_env
                return pop_from_local_frame_with_env(jni_env)
        end
-       
+
        private fun pop_from_local_frame_with_env(jni_env: JniEnv): SELF `{
                return (*jni_env)->PopLocalFrame(jni_env, recv);
        `}
index 79c1ad2..4c003a6 100644 (file)
@@ -61,7 +61,12 @@ redef class App
        end
 
        # Internal method to generate inputs
-       protected fun generate_input is abstract
+       protected fun generate_input
+       do
+               if "NIT_TESTING".environ == "true" then exit 0
+               print "Compiled without platform"
+               exit 1
+       end
 
        # Main app loop
        # Usually you want to redef frame_core instead of this
index b071182..e1d2e73 100644 (file)
@@ -30,6 +30,7 @@ redef class App
 
        redef fun setup
        do
+               if "NIT_TESTING".environ == "true" then exit 0
                display = new Opengles1Display
 
                super
index 323f0ab..bf49334 100644 (file)
@@ -73,7 +73,7 @@ extern class UnicodeChar `{ uint32_t* `}
        # Returns the Unicode code point representing the character
        #
        # Note : A unicode character might not be a visible glyph, but it will be used to determine canonical equivalence
-       fun code_point: Int `{
+       fun code_point: Int import UnicodeChar.len `{
                uint32_t val = *recv;
                uint32_t ret = 0;
                switch(UnicodeChar_len(recv)){
diff --git a/lib/test_suite.nit b/lib/test_suite.nit
new file mode 100644 (file)
index 0000000..6261eea
--- /dev/null
@@ -0,0 +1,51 @@
+# 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.
+
+# Common interface for `nitunit` test-suites.
+module test_suite is
+       # Annotation used by test-suite modules.
+       new_annotation test_suite
+end
+
+# A test-suite that can be executed by `nitunit`.
+#
+# All test-suite classes must implement `TestSuite`.
+class TestSuite
+       # Internal empty init.
+       private init nitunit do end
+
+       # Method called before each test-case.
+       #
+       # Redefine this method to factorize code that have to be
+       # executed before every test.
+       fun before_test do end
+
+       # Method called after each test-case.
+       #
+       # Redefine this method to factorize code that have to be
+       # executed after every test.
+       fun after_test do end
+end
+
+# Method called before each test-suite.
+#
+# Redefine this method to factorize code that have to be
+# executed before every test suite.
+fun before_module do end
+
+# Method called after each test-suite.
+#
+# Redefine this method to factorize code that have to be
+# executed after every test suite.
+fun after_module do end
index 627e223..0a8973d 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Program to extract and execute unit tests from nit source files
+# Testing tool.
+# see `testing/README`
 module nitunit
 
-import modelize_property
-intrude import markdown
-import parser_util
+import testing
 
-# Extractor, Executor an Reporter for the tests in a module
-class NitUnitExecutor
-       super Doc2Mdwn
-
-       # The module to import
-       var mmodule: MModule
+var toolcontext = new ToolContext
 
-       # The prefix of the generated Nit source-file
-       var prefix: String
+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_gen_unit, toolcontext.opt_gen_force, toolcontext.opt_gen_private, toolcontext.opt_gen_show)
+toolcontext.tooldescription = "Usage: nitunit [OPTION]... <file.nit>...\nExecutes the unit tests from Nit source files."
 
-       # The XML node associated to the module
-       var testsuite: HTMLTag
+toolcontext.process_options(args)
+var args = toolcontext.option_context.rest
 
-       # Initialize a new e
-       init(toolcontext: ToolContext, prefix: String, mmodule: MModule, testsuite: HTMLTag)
-       do
-               super(toolcontext)
-               self.prefix = prefix
-               self.mmodule = mmodule
-               self.testsuite = testsuite
+if toolcontext.opt_gen_unit.value then
+       if toolcontext.opt_pattern.value != null then
+               print "Option --pattern cannot be used with --gen-suite"
+               exit(0)
        end
-
-       # All blocks of code from a same `ADoc`
-       var blocks = new Array[Array[String]]
-
-       redef fun process_code(n: HTMLTag, text: String)
-       do
-               # Try to parse it
-               var ast = toolcontext.parse_something(text)
-
-               # We want executable code
-               if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then
-                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
-                               toolcontext.warning(ndoc.location, "Warning: There is a block of code that is not valid Nit, thus not considered a nitunit")
-                               if ast isa AError then toolcontext.warning(ast.location, ast.message)
-                               ndoc = null # To avoid multiple warning in the same node
-                       end
-                       return
-               end
-
-               # Search `assert` in the AST
-               var v = new SearchAssertVisitor
-               v.enter_visit(ast)
-               if not v.foundit then
-                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
-                               toolcontext.warning(ndoc.location, "Warning: There is a block of Nit code without `assert`, thus not considered a nitunit")
-                               ndoc = null # To avoid multiple warning in the same node
-                       end
-                       return
-               end
-
-               # Create a first block
-               # Or create a new block for modules that are more than a main part
-               if blocks.is_empty or ast isa AModule then
-                       blocks.add(new Array[String])
-               end
-
-               # Add it to the file
-               blocks.last.add(text)
+       if toolcontext.opt_file.value != null then
+               print "Option --target-file cannot be used with --gen-suite"
+               exit(0)
        end
-
-       # The associated node to localize warnings
-       var ndoc: nullable ADoc
-
-       # used to generate distinct names
-       var cpt = 0
-
-       # The entry point for a new `ndoc` node
-       # Fill the prepated `tc` (testcase) XTM node
-       fun extract(ndoc: ADoc, tc: HTMLTag)
-       do
-               blocks.clear
-
-               self.ndoc = ndoc
-
-               work(ndoc.to_mdoc)
-               toolcontext.check_errors
-
-               if blocks.is_empty then return
-
-               for block in blocks do test_block(ndoc, tc, block)
+else
+       if toolcontext.opt_gen_force.value then
+               print "Option --force must be used with --gen-suite"
+               exit(0)
        end
-
-       # Execute a block
-       fun test_block(ndoc: ADoc, tc: HTMLTag, block: Array[String])
-       do
-               toolcontext.modelbuilder.unit_entities += 1
-
-               cpt += 1
-               var file = "{prefix}{cpt}.nit"
-
-               toolcontext.info("Execute {tc.attrs["name"]} in {file}", 1)
-
-               var dir = file.dirname
-               if dir != "" then dir.mkdir
-               var f
-               f = new OFStream.open(file)
-               f.write("# GENERATED FILE\n")
-               f.write("# Example extracted from a documentation\n")
-               f.write("import {mmodule.name}\n")
-               f.write("\n")
-               for text in block do
-                       f.write(text)
-               end
-               f.close
-
-               if toolcontext.opt_noact.value then return
-
-               var nit_dir = toolcontext.nit_dir
-               var nitg = "{nit_dir or else ""}/bin/nitg"
-               if nit_dir == null or not nitg.file_exists then
-                       toolcontext.error(null, "Cannot find nitg. Set envvar NIT_DIR.")
-                       toolcontext.check_errors
-               end
-               var cmd = "{nitg} --ignore-visibility --no-color '{file}' -I {mmodule.location.file.filename.dirname} >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
-               var res = sys.system(cmd)
-               var res2 = 0
-               if res == 0 then
-                       res2 = sys.system("./{file}.bin >>'{file}.out1' 2>&1 </dev/null")
-               end
-
-               var msg
-               f = new IFStream.open("{file}.out1")
-               var n2
-               n2 = new HTMLTag("system-err")
-               tc.add n2
-               msg = f.read_all
-               f.close
-
-               n2 = new HTMLTag("system-out")
-               tc.add n2
-               for text in block do n2.append(text)
-
-
-               if res != 0 then
-                       var ne = new HTMLTag("failure")
-                       ne.attr("message", msg)
-                       tc.add ne
-                       toolcontext.warning(ndoc.location, "FAILURE: {tc.attrs["classname"]}.{tc.attrs["name"]} (in {file}): {msg}")
-                       toolcontext.modelbuilder.failed_entities += 1
-               else if res2 != 0 then
-                       var ne = new HTMLTag("error")
-                       ne.attr("message", msg)
-                       tc.add ne
-                       toolcontext.warning(ndoc.location, "ERROR: {tc.attrs["classname"]}.{tc.attrs["name"]} (in {file}): {msg}")
-                       toolcontext.modelbuilder.failed_entities += 1
-               end
-               toolcontext.check_errors
-
-               testsuite.add(tc)
-       end
-end
-
-class SearchAssertVisitor
-       super Visitor
-       var foundit = false
-       redef fun visit(node)
-       do
-               if foundit then
-                       return
-               else if node isa AAssertExpr then
-                       foundit = true
-                       return
-               else
-                       node.visit_all(self)
-               end
+       if toolcontext.opt_gen_private.value then
+               print "Option --private must be used with --gen-suite"
+               exit(0)
        end
-end
-
-redef class ModelBuilder
-       var total_entities = 0
-       var doc_entities = 0
-       var unit_entities = 0
-       var failed_entities = 0
-
-       fun test_markdown(mmodule: MModule): HTMLTag
-       do
-               var ts = new HTMLTag("testsuite")
-               toolcontext.info("nitunit: {mmodule}", 2)
-               if not mmodule2nmodule.has_key(mmodule) then return ts
-
-               var nmodule = mmodule2nmodule[mmodule]
-               assert nmodule != null
-
-               # usualy, only the original module must be imported in the unit test.
-               var o = mmodule
-               var g = o.mgroup
-               if g != null and g.mproject.name == "standard" then
-                       # except for a unit test in a module of standard
-                       # in this case, the whole standard must be imported
-                       o = get_mmodule_by_name(nmodule, g, g.mproject.name).as(not null)
-               end
-
-               ts.attr("package", mmodule.full_name)
-
-               var prefix = toolcontext.opt_dir.value
-               if prefix == null then prefix = ".nitunit"
-               prefix = prefix.join_path(mmodule.to_s)
-               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts)
-
-               var tc
-
-               do
-                       total_entities += 1
-                       var nmoduledecl = nmodule.n_moduledecl
-                       if nmoduledecl == null then break label x
-                       var ndoc = nmoduledecl.n_doc
-                       if ndoc == null then break label x
-                       doc_entities += 1
-                       tc = new HTMLTag("testcase")
-                       # NOTE: jenkins expects a '.' in the classname attr
-                       tc.attr("classname", mmodule.full_name + ".<module>")
-                       tc.attr("name", "<module>")
-                       d2m.extract(ndoc, tc)
-               end label x
-               for nclassdef in nmodule.n_classdefs do
-                       var mclassdef = nclassdef.mclassdef.as(not null)
-                       if nclassdef isa AStdClassdef then
-                               total_entities += 1
-                               var ndoc = nclassdef.n_doc
-                               if ndoc != null then
-                                       doc_entities += 1
-                                       tc = new HTMLTag("testcase")
-                                       tc.attr("classname", mmodule.full_name + "." + mclassdef.mclass.full_name)
-                                       tc.attr("name", "<class>")
-                                       d2m.extract(ndoc, tc)
-                               end
-                       end
-                       for npropdef in nclassdef.n_propdefs do
-                               var mpropdef = npropdef.mpropdef.as(not null)
-                               total_entities += 1
-                               var ndoc = npropdef.n_doc
-                               if ndoc != null then
-                                       doc_entities += 1
-                                       tc = new HTMLTag("testcase")
-                                       tc.attr("classname", mmodule.full_name + "." + mclassdef.mclass.full_name)
-                                       tc.attr("name", mpropdef.mproperty.full_name)
-                                       d2m.extract(ndoc, tc)
-                               end
-                       end
-               end
-
-               return ts
+       if toolcontext.opt_gen_show.value then
+               print "Option --only-show must be used with --gen-suite"
+               exit(0)
        end
 end
 
-redef class ToolContext
-       var opt_full = new OptionBool("Process also imported modules", "--full")
-       var opt_output = new OptionString("Output name (default is 'nitunit.xml')", "-o", "--output")
-       var opt_dir = new OptionString("Working directory (default is '.nitunit')", "--dir")
-       var opt_noact = new OptionBool("Does not compile and run tests", "--no-act")
-end
-
-var toolcontext = new ToolContext
-
-toolcontext.option_context.add_option(toolcontext.opt_full, toolcontext.opt_output, toolcontext.opt_dir, toolcontext.opt_noact)
-toolcontext.tooldescription = "Usage: nitunit [OPTION]... <file.nit>...\nExecutes the unit tests from Nit source files."
-
-toolcontext.process_options(args)
-var args = toolcontext.option_context.rest
-
 var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 var mmodules = modelbuilder.parse(args)
 modelbuilder.run_phases
 
+if toolcontext.opt_gen_unit.value then
+       modelbuilder.gen_test_unit(mmodules.first)
+       exit(0)
+end
+
 var page = new HTMLTag("testsuites")
 
 if toolcontext.opt_full.value then mmodules = model.mmodules
 
 for m in mmodules do
        page.add modelbuilder.test_markdown(m)
+       page.add modelbuilder.test_unit(m)
 end
 
 var file = toolcontext.opt_output.value
 if file == null then file = "nitunit.xml"
 page.write_to_file(file)
 print "Results saved in {file}"
-
+# print docunits results
+print "\nDocUnits:"
 if modelbuilder.unit_entities == 0 then
-       print "No nitunits found"
+       print "No doc units found"
 else if modelbuilder.failed_entities == 0 and not toolcontext.opt_noact.value then
-       print "Success"
+       print "DocUnits Success"
 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"
+end
+print "Class suites: {modelbuilder.total_classes}; Test Cases: {modelbuilder.total_tests}; Failures: {modelbuilder.failed_tests}"
diff --git a/src/testing/README b/src/testing/README
new file mode 100644 (file)
index 0000000..772ec38
--- /dev/null
@@ -0,0 +1,162 @@
+# Test unit generation and execution for Nit.
+
+In Nit, unit testing can be achieved in two ways:
+
+* using `DocUnits` in code comments
+* using `TestSuites` with test unit files
+
+DocUnits are executable pieces of code found in the documentation of modules,
+classes and properties.
+They are used for documentation purpose, they should be kept simple and illustrative.
+More advanced unit testing can be done using TestSuites.
+
+TestSuites are test files coupled to a tested module.
+They contain a list of test methods called TestCase.
+
+## Working with `DocUnits`
+
+With DocUnits, executable code can be placed in comments of modules, classes and properties.
+The execution can be verified using `assert`
+
+Example with a class:
+
+       module foo
+
+       #    var foo = new Foo
+       #    assert foo.bar == 10
+       class Foo
+               var bar = 10
+       end
+
+Everything used in the test must be declared.
+To test a method you have to instanciate its class:
+
+       module foo
+
+       #    var foo = new Foo
+       #    assert foo.bar == 10
+       class Foo
+               #    var foo = new Foo
+               #    assert foo.baz(1, 2) == 3
+               fun baz(a, b: Int) do return a + b
+       end
+
+`nitunit` is used to test Nit files:
+
+       $ nitunit foo.nit
+
+## Working with `TestSuites`
+
+TestSuites are Nit files that define a set of TestCase for a particular module.
+
+The test suite module must be declared using the `test_suite` annotation.
+The structure of a test suite is the following:
+
+       # test suite for module `foo`
+       module test_foo is test_suite
+
+       import test_suite # import the `TestSuite` class and the `test_suite` annotation
+       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
+                       assert subject.baz(1, 2) == 3
+               end
+       end
+
+Test suite can be executed using the same `nitunit` command:
+
+       $ nitunit foo.nit
+
+To be started automatically with nitunit, the module 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`.
+Otherwise, you can use the `-t` option to specify the test suite module name:
+
+       $ nitunit foo.nit -t my_test_suite.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:
+
+       class TestFoo
+               super TestSuite
+
+               fun test_baz_1 do
+                       var subject = new Foo
+                       assert subject.baz(1, 2) == 3
+               end
+
+               fun test_baz_2 do
+                       var subject = new Foo
+                       assert subject.baz(1, -2) == -1
+               end
+       end
+
+`TestSuites` 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 is noinit
+
+               # Method executed before each test
+               redef fun before_test do
+                       subject = new Foo
+               end
+
+               fun test_baz_1 do
+                       assert subject.baz(1, 2) == 3
+               end
+
+               fun test_baz_2 do
+                       assert subject.baz(1, -2) == -1
+               end
+       end
+
+When using custom test attributes, a empty init must be declared to allow automatic test running.
+
+`before_module` and `after_module`: methods called before/after each test suite.
+They have to be declared at top level:
+
+       module test_bdd_connector
+
+       import test_suite
+       import bdd_connector
+
+       # Testing the bdd_connector
+       class TestConnector
+               super TestSuite
+               # test cases using a server
+       end
+
+       # Method executed before testing the module
+       redef fun before_module do
+               # start server before all test cases
+       end
+
+       # Method executed after testing the module
+       redef fun after_module do
+               # stop server after all test cases
+       end
+
+## Generating test suites
+
+Write test suites for big modules can be a pepetitive and boring task...
+To make it easier, `nitunit` can generate test skeletons for Nit modules:
+
+       $ nitunit --gen-suite foo.nit
+
+This will generate the test suite `test_foo` containing test case stubs for all public
+methods found in `foo.nit`.
+
+Useful options with `--gen-suite`:
+
+* `--private`: also generate tests for protected and private methods
+* `--force`: force generation of the skeleton (existing test suite will be overwritten)
diff --git a/src/testing/testing.nit b/src/testing/testing.nit
new file mode 100644 (file)
index 0000000..24251ae
--- /dev/null
@@ -0,0 +1,20 @@
+# 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.
+
+# Test unit generation and execution for Nit.
+module testing
+
+import testing_doc
+import testing_suite
+import testing_gen
diff --git a/src/testing/testing_base.nit b/src/testing/testing_base.nit
new file mode 100644 (file)
index 0000000..243a51e
--- /dev/null
@@ -0,0 +1,37 @@
+# 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.
+
+# Base options for testing tools.
+module testing_base
+
+import modelize_property
+import parser_util
+
+redef class ToolContext
+       # opt --full
+       var opt_full = new OptionBool("Process also imported modules", "--full")
+       # opt --output
+       var opt_output = new OptionString("Output name (default is 'nitunit.xml')", "-o", "--output")
+       # opt --dirr
+       var opt_dir = new OptionString("Working directory (default is '.nitunit')", "--dir")
+       # opt --no-act
+       var opt_noact = new OptionBool("Does not compile and run tests", "--no-act")
+
+       # Working directory for testing.
+       fun test_dir: String do
+               var dir = opt_dir.value
+               if dir == null then return ".nitunit"
+               return dir
+       end
+end
diff --git a/src/testing/testing_doc.nit b/src/testing/testing_doc.nit
new file mode 100644 (file)
index 0000000..e370b8a
--- /dev/null
@@ -0,0 +1,266 @@
+# 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.
+
+# Testing from code comments.
+module testing_doc
+
+import testing_base
+intrude import markdown
+
+# Extractor, Executor and Reporter for the tests in a module
+class NitUnitExecutor
+       super Doc2Mdwn
+
+       # The module to import
+       var mmodule: MModule
+
+       # The prefix of the generated Nit source-file
+       var prefix: String
+
+       # The XML node associated to the module
+       var testsuite: HTMLTag
+
+       # Initialize a new e
+       init(toolcontext: ToolContext, prefix: String, mmodule: MModule, testsuite: HTMLTag)
+       do
+               super(toolcontext)
+               self.prefix = prefix
+               self.mmodule = mmodule
+               self.testsuite = testsuite
+       end
+
+       # All blocks of code from a same `ADoc`
+       var blocks = new Array[Array[String]]
+
+       redef fun process_code(n: HTMLTag, text: String)
+       do
+               # Try to parse it
+               var ast = toolcontext.parse_something(text)
+
+               # We want executable code
+               if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then
+                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
+                               toolcontext.warning(ndoc.location, "Warning: There is a block of code that is not valid Nit, thus not considered a nitunit")
+                               if ast isa AError then toolcontext.warning(ast.location, ast.message)
+                               ndoc = null # To avoid multiple warning in the same node
+                       end
+                       return
+               end
+
+               # Search `assert` in the AST
+               var v = new SearchAssertVisitor
+               v.enter_visit(ast)
+               if not v.foundit then
+                       if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
+                               toolcontext.warning(ndoc.location, "Warning: There is a block of Nit code without `assert`, thus not considered a nitunit")
+                               ndoc = null # To avoid multiple warning in the same node
+                       end
+                       return
+               end
+
+               # Create a first block
+               # Or create a new block for modules that are more than a main part
+               if blocks.is_empty or ast isa AModule then
+                       blocks.add(new Array[String])
+               end
+
+               # Add it to the file
+               blocks.last.add(text)
+       end
+
+       # The associated node to localize warnings
+       var ndoc: nullable ADoc
+
+       # used to generate distinct names
+       var cpt = 0
+
+       # The entry point for a new `ndoc` node
+       # Fill the prepated `tc` (testcase) XTM node
+       fun extract(ndoc: ADoc, tc: HTMLTag)
+       do
+               blocks.clear
+
+               self.ndoc = ndoc
+
+               work(ndoc.to_mdoc)
+               toolcontext.check_errors
+
+               if blocks.is_empty then return
+
+               for block in blocks do test_block(ndoc, tc, block)
+       end
+
+       # Execute a block
+       fun test_block(ndoc: ADoc, tc: HTMLTag, block: Array[String])
+       do
+               toolcontext.modelbuilder.unit_entities += 1
+
+               cpt += 1
+               var file = "{prefix}{cpt}.nit"
+
+               toolcontext.info("Execute doc-unit {tc.attrs["name"]} in {file}", 1)
+
+               var dir = file.dirname
+               if dir != "" then dir.mkdir
+               var f
+               f = new OFStream.open(file)
+               f.write("# GENERATED FILE\n")
+               f.write("# Example extracted from a documentation\n")
+               f.write("import {mmodule.name}\n")
+               f.write("\n")
+               for text in block do
+                       f.write(text)
+               end
+               f.close
+
+               if toolcontext.opt_noact.value then return
+
+               var nit_dir = toolcontext.nit_dir
+               var nitg = "{nit_dir or else ""}/bin/nitg"
+               if nit_dir == null or not nitg.file_exists then
+                       toolcontext.error(null, "Cannot find nitg. Set envvar NIT_DIR.")
+                       toolcontext.check_errors
+               end
+               var cmd = "{nitg} --ignore-visibility --no-color '{file}' -I {mmodule.location.file.filename.dirname} >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
+               var res = sys.system(cmd)
+               var res2 = 0
+               if res == 0 then
+                       res2 = sys.system("./{file}.bin >>'{file}.out1' 2>&1 </dev/null")
+               end
+
+               var msg
+               f = new IFStream.open("{file}.out1")
+               var n2
+               n2 = new HTMLTag("system-err")
+               tc.add n2
+               msg = f.read_all
+               f.close
+
+               n2 = new HTMLTag("system-out")
+               tc.add n2
+               for text in block do n2.append(text)
+
+
+               if res != 0 then
+                       var ne = new HTMLTag("failure")
+                       ne.attr("message", msg)
+                       tc.add ne
+                       toolcontext.warning(ndoc.location, "FAILURE: {tc.attrs["classname"]}.{tc.attrs["name"]} (in {file}): {msg}")
+                       toolcontext.modelbuilder.failed_entities += 1
+               else if res2 != 0 then
+                       var ne = new HTMLTag("error")
+                       ne.attr("message", msg)
+                       tc.add ne
+                       toolcontext.warning(ndoc.location, "ERROR: {tc.attrs["classname"]}.{tc.attrs["name"]} (in {file}): {msg}")
+                       toolcontext.modelbuilder.failed_entities += 1
+               end
+               toolcontext.check_errors
+
+               testsuite.add(tc)
+       end
+end
+
+class SearchAssertVisitor
+       super Visitor
+       var foundit = false
+       redef fun visit(node)
+       do
+               if foundit then
+                       return
+               else if node isa AAssertExpr then
+                       foundit = true
+                       return
+               else
+                       node.visit_all(self)
+               end
+       end
+end
+
+redef class ModelBuilder
+       var total_entities = 0
+       var doc_entities = 0
+       var unit_entities = 0
+       var failed_entities = 0
+
+       fun test_markdown(mmodule: MModule): HTMLTag
+       do
+               var ts = new HTMLTag("testsuite")
+               toolcontext.info("nitunit: doc-unit {mmodule}", 2)
+               if not mmodule2nmodule.has_key(mmodule) then return ts
+
+               var nmodule = mmodule2nmodule[mmodule]
+               assert nmodule != null
+
+               # usualy, only the original module must be imported in the unit test.
+               var o = mmodule
+               var g = o.mgroup
+               if g != null and g.mproject.name == "standard" then
+                       # except for a unit test in a module of standard
+                       # in this case, the whole standard must be imported
+                       o = get_mmodule_by_name(nmodule, g, g.mproject.name).as(not null)
+               end
+
+               ts.attr("package", mmodule.full_name)
+
+               var prefix = toolcontext.test_dir
+               prefix = prefix.join_path(mmodule.to_s)
+               var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts)
+
+               var tc
+
+               do
+                       total_entities += 1
+                       var nmoduledecl = nmodule.n_moduledecl
+                       if nmoduledecl == null then break label x
+                       var ndoc = nmoduledecl.n_doc
+                       if ndoc == null then break label x
+                       doc_entities += 1
+                       tc = new HTMLTag("testcase")
+                       # NOTE: jenkins expects a '.' in the classname attr
+                       tc.attr("classname", mmodule.full_name + ".<module>")
+                       tc.attr("name", "<module>")
+                       d2m.extract(ndoc, tc)
+               end label x
+               for nclassdef in nmodule.n_classdefs do
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef == null then continue
+                       if nclassdef isa AStdClassdef then
+                               total_entities += 1
+                               var ndoc = nclassdef.n_doc
+                               if ndoc != null then
+                                       doc_entities += 1
+                                       tc = new HTMLTag("testcase")
+                                       tc.attr("classname", mmodule.full_name + "." + mclassdef.mclass.full_name)
+                                       tc.attr("name", "<class>")
+                                       d2m.extract(ndoc, tc)
+                               end
+                       end
+                       for npropdef in nclassdef.n_propdefs do
+                               var mpropdef = npropdef.mpropdef
+                               if mpropdef == null then continue
+                               total_entities += 1
+                               var ndoc = npropdef.n_doc
+                               if ndoc != null then
+                                       doc_entities += 1
+                                       tc = new HTMLTag("testcase")
+                                       tc.attr("classname", mmodule.full_name + "." + mclassdef.mclass.full_name)
+                                       tc.attr("name", mpropdef.mproperty.full_name)
+                                       d2m.extract(ndoc, tc)
+                               end
+                       end
+               end
+
+               return ts
+       end
+end
diff --git a/src/testing/testing_gen.nit b/src/testing/testing_gen.nit
new file mode 100644 (file)
index 0000000..19532c6
--- /dev/null
@@ -0,0 +1,181 @@
+# 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.
+
+# Test Suites generation.
+module testing_gen
+
+import testing_base
+import template
+
+# Used to generate a nitunit test file skeleton.
+class NitUnitGenerator
+
+       var toolcontext: ToolContext
+
+       # Generate the NitUnit test file skeleton for `mmodule` in `test_file`.
+       fun gen_unit(mmodule: MModule, test_file: String): Template do
+               var with_private = toolcontext.opt_gen_private.value
+               var tpl = new Template
+               tpl.addn "module test_{mmodule.name} is test_suite"
+               tpl.addn ""
+               tpl.addn "import test_suite"
+               if with_private then
+                       tpl.addn "intrude import {mmodule.name}"
+               else
+                       tpl.addn "import {mmodule.name}"
+               end
+               for mclassdef in mmodule.mclassdefs do
+                       if mclassdef.mclass.kind != concrete_kind then continue
+                       tpl.addn ""
+                       tpl.addn "class Test{mclassdef.name}"
+                       tpl.addn "\tsuper TestSuite"
+                       for mpropdef in mclassdef.mpropdefs do
+                               if not mpropdef isa MMethodDef then continue
+                               var mproperty = mpropdef.mproperty
+                               if mpropdef.is_abstract then continue
+                               if mproperty.is_init then continue
+                               if not with_private and mproperty.visibility <= protected_visibility then continue
+                               var case_name = case_name(mpropdef)
+                               tpl.addn ""
+                               tpl.addn "\tfun {case_name} do"
+                               tpl.addn "\t\tassert not_implemented: false # TODO remove once implemented"
+                               tpl.addn ""
+                               tpl.addn gen_init(mclassdef)
+                               var args = new Array[String]
+                               for mparameter in mpropdef.msignature.mparameters do
+                                       tpl.addn gen_decl(mparameter.name, mparameter.mtype, mclassdef)
+                                       args.add mparameter.name
+                               end
+                               var return_mtype = mpropdef.msignature.return_mtype
+                               if return_mtype != null then
+                                       tpl.addn gen_decl("exp", return_mtype, mclassdef)
+                                       tpl.add "\t\tvar res = "
+                               else
+                                       tpl.add "\t\t"
+                               end
+                               tpl.addn gen_call(mpropdef, args)
+                               if return_mtype != null then
+                                       tpl.addn "\t\tassert exp == res"
+                               end
+                               tpl.addn "\tend"
+                       end
+                       tpl.addn "end"
+               end
+               return tpl
+       end
+
+       # Generate case name based on `MMethodDef`.
+       # special method name like "[]", "+"... are filtered
+       private fun case_name(mmethoddef: MMethodDef): String do
+               var name = mmethoddef.name
+               if name == "[]" then return "test_bra"
+               if name == "[]=" then return "test_bra_assign"
+               if name == "+" then return "test_plus"
+               if name == "-" then return "test_minus"
+               if name == "*" then return "test_star"
+               if name == "/" then return "test_slash"
+               if name == "%" then return "test_percent"
+               if name == "unary -" then return "test_unary_minus"
+               if name == "==" then return "test_equals"
+               if name == "!=" then return "test_not_equals"
+               if name == "<" then return "test_lt"
+               if name == "<=" then return "test_le"
+               if name == "<=>" then return "test_compare"
+               if name == ">=" then return "test_ge"
+               if name == ">" then return "test_gt"
+               return "test_{name}"
+       end
+
+       # Method names that do not need a "." in call.
+       var nodot: Array[String] = ["+", "-", "*", "/", "%", "==", "!=", "<", "<=", "<=>", ">", ">=", ">"]
+
+       # Generate subject init.
+       private fun gen_init(mclassdef: MClassDef): Streamable do
+               if mclassdef.mclass.arity == 0 then
+                       return "\t\tvar subject: {mclassdef.name}"
+               end
+               return "\t\tvar subject: {mclassdef.name}[{mclassdef.bound_mtype.arguments.join(", ")}]"
+       end
+
+       private fun gen_decl(name: String, mtype: MType, mclassdef: MClassDef): String do
+               if mtype.need_anchor then
+                       mtype = mtype.anchor_to(mclassdef.mmodule, mclassdef.bound_mtype)
+               end
+               return "\t\tvar {name}: {mtype.to_s}"
+       end
+
+       # Generate call to `method` using `args`.
+       private fun gen_call(method: MMethodDef, args: Array[String]): Streamable do
+               # Here we handle the magic of the Nit syntax, have fun :)
+               var name = method.name
+               if name == "[]" then return "subject[{args.join(", ")}]"
+               if name == "[]=" then
+                       var last = args.pop
+                       return "subject[{args.join(", ")}] = {last}"
+               end
+               if name == "unary -" then return "-subject"
+               var tpl = new Template
+               if nodot.has(name) then
+                       tpl.add "subject {name}"
+                       if args.length == 1 then
+                               tpl.add " {args.first}"
+                       else if args.length > 1 then
+                               tpl.add " ({args.join(", ")})"
+                       end
+                       return tpl
+               end
+               if name.has_suffix("=") then
+                       name = name.substring(0, name.length - 1)
+                       var last = args.pop
+                       tpl.add "subject.{name}"
+                       if not args.is_empty then
+                               tpl.add "({args.join(", ")})"
+                       end
+                       tpl.add " = {last}"
+                       return tpl
+               end
+               tpl.add "subject.{name}"
+               if args.length == 1 then
+                       tpl.add " {args.first}"
+               else if args.length > 1 then
+                       tpl.add "({args.join(", ")})"
+               end
+               return tpl
+       end
+end
+
+redef class ModelBuilder
+       # Generate NitUnit test file skeleton for `mmodule`.
+       fun gen_test_unit(mmodule: MModule) do
+               var test_file = "test_{mmodule.name}.nit"
+               if test_file.file_exists and not toolcontext.opt_gen_force.value and not toolcontext.opt_gen_show.value then
+                       toolcontext.info("Skip generation for {mmodule}, file {test_file} already exists", 1)
+                       return
+               end
+               var generator = new NitUnitGenerator(toolcontext)
+               var tpl = generator.gen_unit(mmodule, test_file)
+               if toolcontext.opt_gen_show.value then
+                       tpl.write_to(sys.stdout)
+               else
+                       tpl.write_to_file(test_file)
+               end
+       end
+end
+
+redef class ToolContext
+       var opt_gen_unit = new OptionBool("Generate test suite skeleton for a module", "--gen-suite")
+       var opt_gen_force = new OptionBool("Force test generation even if file exists", "-f", "--force")
+       var opt_gen_private = new OptionBool("Also generate test case for private methods", "--private")
+       var opt_gen_show = new OptionBool("Only display skeleton, do not write file", "--only-show")
+end
diff --git a/src/testing/testing_suite.nit b/src/testing/testing_suite.nit
new file mode 100644 (file)
index 0000000..acf5650
--- /dev/null
@@ -0,0 +1,396 @@
+# 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.
+
+# Testing from external files.
+module testing_suite
+
+import testing_base
+import html
+
+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. Examples: 'TestFoo', 'TestFoo*', 'TestFoo::test_foo', 'TestFoo::test_foo*', 'test_foo', 'test_foo*'", "-p", "--pattern")
+end
+
+# Used to test nitunit test files.
+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
+               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
+               if before_module != null then
+                       toolcontext.modelbuilder.total_tests += 1
+                       suite.before_module = new TestCase(suite, before_module, toolcontext)
+               end
+               # generate all test cases
+               for mclassdef in mmodule.mclassdefs do
+                       if not mclassdef.is_test then continue
+                       if not suite_match_pattern(mclassdef) then continue
+                       toolcontext.modelbuilder.total_classes += 1
+                       var before_test = mclassdef.before_test
+                       var after_test = mclassdef.after_test
+                       for mpropdef in mclassdef.mpropdefs do
+                               if not mpropdef isa MMethodDef or not mpropdef.is_test then continue
+                               if not case_match_pattern(mpropdef) then continue
+                               toolcontext.modelbuilder.total_tests += 1
+                               var test = new TestCase(suite, mpropdef, toolcontext)
+                               test.before_test = before_test
+                               test.after_test = after_test
+                               suite.add_test test
+                       end
+               end
+               # method to execute after all tests in the module
+               var after_module = mmodule.after_test
+               if after_module != null then
+                       toolcontext.modelbuilder.total_tests += 1
+                       suite.after_module = new TestCase(suite, after_module, toolcontext)
+               end
+               suite.run
+               return suite
+       end
+
+       # Is the test suite name match the pattern option?
+       private fun suite_match_pattern(suite: MClassDef): Bool do
+               var pattern = mbuilder.toolcontext.opt_pattern.value
+               if pattern == null then return true
+               var ps = pattern.split_with("::")
+               var p = ps.first
+               if ps.length == 1 and p.first.is_lower then return true
+               if ps.length == 2 and p.first.is_lower then return false
+               if p.has_suffix("*") then
+                       p = p.substring(0, p.length - 1)
+                       if suite.name.has_prefix(p) then return true
+               else
+                       if suite.name == p then return true
+               end
+               return false
+       end
+
+       # Is the test case name match the pattern option?
+       private fun case_match_pattern(case: MPropDef): Bool do
+               var pattern = mbuilder.toolcontext.opt_pattern.value
+               if pattern == null then return true
+               var ps = pattern.split_with("::")
+               var p = ps.last
+               if ps.length == 1 and p.first.is_upper then return true
+               if ps.length == 2 and p.first.is_upper then return false
+               if p.has_suffix("*") then
+                       p = p.substring(0, p.length - 1)
+                       if case.name.has_prefix(p) then return true
+               else
+                       if case.name == p then return true
+               end
+               return false
+       end
+end
+
+# A test suite contains all the test cases for a `MModule`.
+class TestSuite
+
+       # `MModule` under test
+       var mmodule: MModule
+
+       # `ToolContext` to use to display messages.
+       var toolcontext: ToolContext
+
+       # List of `TestCase` to be executed in this suite.
+       var test_cases = new Array[TestCase]
+
+       # Add a `TestCase` to the suite.
+       fun add_test(case: TestCase) do test_cases.add case
+
+       # Test to be executed before the whole test suite.
+       var before_module: nullable TestCase = null
+
+       # Test to be executed after the whole test suite.
+       var after_module: nullable TestCase = null
+
+       # Execute the test suite
+       fun run do
+               if not toolcontext.test_dir.file_exists then
+                       toolcontext.test_dir.mkdir
+               end
+               toolcontext.info("Execute test-suite {mmodule.name}", 1)
+               var before_module = self.before_module
+               if not before_module == null then run_case(before_module)
+               for case in test_cases do run_case(case)
+               var after_module = self.after_module
+               if not after_module == null then run_case(after_module)
+       end
+
+       # Execute a test case
+       fun run_case(test_case: TestCase) do
+               test_case.write_to_nit
+               test_case.compile
+               test_case.run
+       end
+
+       # Return the test suite in XML format compatible with Jenkins.
+       # Contents depends on the `run` execution.
+       fun to_xml: HTMLTag do
+               var n = new HTMLTag("testsuite")
+               n.attr("package", mmodule.name)
+               for test in test_cases do n.add test.to_xml
+               return n
+       end
+end
+
+# A test case is a unit test considering only a `MMethodDef`.
+class TestCase
+
+       # Test suite wich `self` belongs to.
+       var test_suite: TestSuite
+
+       # Test method to be compiled and tested.
+       var test_method: MMethodDef
+
+       # `ToolContext` to use to display messages and find `nitg` bin.
+       var toolcontext: ToolContext
+
+       # `MMethodDef` to call before the test case.
+       var before_test: nullable MMethodDef = null
+
+       # `MMethodDef` to call after the test case.
+       var after_test: nullable MMethodDef = null
+
+       # Generated test file name.
+       fun test_file: String do
+               var dir = toolcontext.test_dir
+               var mod = test_method.mclassdef.mmodule.name
+               var cls = test_method.mclassdef.name
+               var name = test_method.name
+               return "{dir}/{mod}_{cls}_{name}"
+       end
+
+       # Generate the test unit in a nit file.
+       fun write_to_nit do
+               var name = test_method.name
+               var file = new Template
+               file.addn "intrude import test_suite"
+               file.addn "import {test_method.mclassdef.mmodule.name}\n"
+               if test_method.mproperty.is_toplevel then
+                       file.addn name
+               else
+                       file.addn "var subject = new {test_method.mclassdef.name}.nitunit"
+                       if before_test != null then file.addn "subject.{before_test.name}"
+                       file.addn "subject.{name}"
+                       if after_test != null then file.addn "subject.{after_test.name}"
+               end
+               file.write_to_file("{test_file}.nit")
+       end
+
+       # Compile all test cases in once.
+       fun compile do
+               # find nitg
+               var nit_dir = toolcontext.nit_dir
+               var nitg = "{nit_dir or else ""}/bin/nitg"
+               if nit_dir == null or not nitg.file_exists then
+                       toolcontext.error(null, "Cannot find nitg. Set envvar NIT_DIR.")
+                       toolcontext.check_errors
+               end
+               # compile test suite
+               var file = test_file
+               var include_dir = test_method.mclassdef.mmodule.location.file.filename.dirname
+               var cmd = "{nitg} --no-color '{file}.nit' -I {include_dir} -o '{file}.bin' > '{file}.out' 2>&1 </dev/null"
+               var res = sys.system(cmd)
+               var f = new IFStream.open("{file}.out")
+               var msg = f.read_all
+               f.close
+               # set test case result
+               var loc = test_method.location
+               if res != 0 then
+                       failure = msg
+                       toolcontext.warning(loc, "FAILURE: {test_method.name} (in file {file}.nit): {msg}")
+                       toolcontext.modelbuilder.failed_tests += 1
+               end
+               toolcontext.check_errors
+       end
+
+       # Execute the test case.
+       fun run do
+               toolcontext.info("Execute test-case {test_method.name}", 1)
+               was_exec = true
+               if toolcontext.opt_noact.value then return
+               # execute
+               var file = test_file
+               var res = sys.system("./{file}.bin > '{file}.out1' 2>&1 </dev/null")
+               var f = new IFStream.open("{file}.out1")
+               var msg = f.read_all
+               f.close
+               # set test case result
+               var loc = test_method.location
+               if res != 0 then
+                       error = msg
+                       toolcontext.warning(loc, "ERROR: {test_method.name} (in file {file}.nit): {msg}")
+                       toolcontext.modelbuilder.failed_tests += 1
+               end
+               toolcontext.check_errors
+       end
+
+       # Error occured during execution.
+       var error: nullable String = null
+
+       # Error occured during compilation.
+       var failure: nullable String = null
+
+       # Was the test case executed at least one?
+       var was_exec = false
+
+       # Return the `TestCase` in XML format compatible with Jenkins.
+       fun to_xml: HTMLTag do
+               var mclassdef = test_method.mclassdef
+               var tc = new HTMLTag("testcase")
+               # NOTE: jenkins expects a '.' in the classname attr
+               tc.attr("classname", mclassdef.mmodule.full_name + "." + mclassdef.mclass.full_name)
+               tc.attr("name", test_method.mproperty.full_name)
+               if was_exec then
+                       tc.add  new HTMLTag("system-err")
+                       var n = new HTMLTag("system-out")
+                       n.append "out"
+                       tc.add n
+                       if error != null then
+                               n = new HTMLTag("error")
+                               n.attr("message", error.to_s)
+                               tc.add n
+                       end
+                       if failure != null then
+                               n = new HTMLTag("failure")
+                               n.attr("message", failure.to_s)
+                               tc.add n
+                       end
+               end
+               return tc
+       end
+end
+
+redef class MMethodDef
+       # TODO use annotations?
+
+       # Is the method a test_method?
+       # i.e. begins with "test_"
+       private fun is_test: Bool do return name.has_prefix("test_")
+
+       # Is the method a "before_test"?
+       private fun is_before: Bool do return name == "before_test"
+
+       # Is the method a "after_test"?
+       private fun is_after: Bool do return name == "after_test"
+
+       # Is the method a "before_module"?
+       private fun is_before_module: Bool do return mproperty.is_toplevel and name == "before_module"
+
+       # Is the method a "after_module"?
+       private fun is_after_module: Bool do return mproperty.is_toplevel and name == "after_module"
+end
+
+redef class MClassDef
+       # Is the class a TestClass?
+       # i.e. begins with "Test"
+       private fun is_test: Bool do
+               for sup in in_hierarchy.greaters do
+                       if sup.name == "TestSuite" then return true
+               end
+               return false
+       end
+
+       # "before_test" method for this classdef.
+       private fun before_test: nullable MMethodDef do
+               for mpropdef in mpropdefs do
+                       if mpropdef isa MMethodDef and mpropdef.is_before then return mpropdef
+               end
+               return null
+       end
+
+       # "after_test" method for this classdef.
+       private fun after_test: nullable MMethodDef do
+               for mpropdef in mpropdefs do
+                       if mpropdef isa MMethodDef and mpropdef.is_after then return mpropdef
+               end
+               return null
+       end
+end
+
+redef class MModule
+       # "before_module" method for this module.
+       private fun before_test: nullable MMethodDef do
+               for mclassdef in mclassdefs do
+                       if not mclassdef.name == "Object" then continue
+                       for mpropdef in mclassdef.mpropdefs do
+                               if mpropdef isa MMethodDef and mpropdef.is_before_module then return mpropdef
+                       end
+               end
+               return null
+       end
+
+       # "after_module" method for this module.
+       private fun after_test: nullable MMethodDef do
+               for mclassdef in mclassdefs do
+                       if not mclassdef.name == "Object" then continue
+                       for mpropdef in mclassdef.mpropdefs do
+                               if mpropdef isa MMethodDef and mpropdef.is_after_module then return mpropdef
+                       end
+               end
+               return null
+       end
+end
+
+redef class ModelBuilder
+       var total_classes = 0
+       var total_tests = 0
+       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 include_dir = mmodule.location.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", 1)
+                       return ts
+               end
+               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", 1)
+                       return ts
+               end
+               return res.to_xml
+       end
+end
index 82cd3d0..2e20b7e 100644 (file)
@@ -5,3 +5,6 @@ posix_ext
 physical_interface_for_mpd_on_rpi
 blink
 input
+android_app
+android_assets
+opengles1
index 67896c0..b4d2b33 100644 (file)
@@ -1,10 +1,5 @@
 example_exec_ls
 leapfrog_curses
-dino_linux
-moles_linux
-simple_linux
-shoot_linux
 websocket_server
 converter
-mnit_linux
-friendz_linux
+show_basedir
index b02edda..6282781 100755 (executable)
@@ -1,11 +1,4 @@
 #!/bin/sh
-list=""
-for x in ../lib/*
-do
-       bx=`basename $x`
-       y="$x/$bx.nit"
-       test -f $y && list="$list $y"
-done
 printf "%s\n" "$@" *.nit \
        ../examples/*.nit \
        ../examples/*/*.nit \
@@ -16,7 +9,9 @@ printf "%s\n" "$@" *.nit \
        ../examples/pnacl/converter/converter.nit \
        ../examples/nitcorn/src/*.nit \
        ../examples/mpi/src/*.nit \
-       ../lib/*.nit $list \
+       ../lib/*.nit \
+       ../lib/*/*.nit \
+       ../lib/*/*/*.nit  \
        ../src/nit*.nit \
        ../src/test_*.nit \
        ../contrib/*.nit \
index f09cabb..22d7416 100644 (file)
@@ -14,9 +14,8 @@ nitg_args5
 nitg_args6
 test_markdown_args1
 pep8analysis
-test_android_platform
-android
 nitcc_parser_gen
-mnit
 emscripten
 nitserial_args
+nitunit_args2
+nitunit_args3
index 7572830..cc7239d 100644 (file)
@@ -1 +1,3 @@
 test_nitunit.nit --no-color -o $WRITE
+test_nitunit.nit --gen-suite --only-show
+test_nitunit.nit --gen-suite --only-show --private
diff --git a/tests/sav/android.res b/tests/sav/android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/ballz_android.res b/tests/sav/ballz_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/complete_simple_android.res b/tests/sav/complete_simple_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/dino_android.res b/tests/sav/dino_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/dino_linux.res b/tests/sav/dino_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/emscripten.res b/tests/sav/emscripten.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/emscripten_nodejs.res b/tests/sav/emscripten_nodejs.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/friendz.res b/tests/sav/friendz.res
deleted file mode 100644 (file)
index 6f89576..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Runtime error: Abstract method `generate_input` called on `App` (../lib/mnit/mnit_app.nit:63)
diff --git a/tests/sav/friendz_android.res b/tests/sav/friendz_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/friendz_linux.res b/tests/sav/friendz_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/linux_app.res b/tests/sav/linux_app.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/linux_assets.res b/tests/sav/linux_assets.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/mnit.res b/tests/sav/mnit.res
deleted file mode 100644 (file)
index 6f89576..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Runtime error: Abstract method `generate_input` called on `App` (../lib/mnit/mnit_app.nit:63)
diff --git a/tests/sav/mnit_android.res b/tests/sav/mnit_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/mnit_linux.res b/tests/sav/mnit_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/mnit_null.res b/tests/sav/mnit_null.res
new file mode 100644 (file)
index 0000000..31c5498
--- /dev/null
@@ -0,0 +1,3 @@
+GET injected_input_stream /dev/null
+END OF INPUTS
+END OF INPUT
diff --git a/tests/sav/moles_android.res b/tests/sav/moles_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/moles_linux.res b/tests/sav/moles_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/niti/mnit_injected_input.res b/tests/sav/niti/mnit_injected_input.res
new file mode 100644 (file)
index 0000000..b40c338
--- /dev/null
@@ -0,0 +1 @@
+GET injected_input_stream /dev/null
index bf738b9..e115c1d 100644 (file)
@@ -1,12 +1,20 @@
 test_nitunit.nit:20,1--22,0: ERROR: test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit2.nit): Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
 
-test_nitunit.nit:23,2--25,0: FAILURE: test_nitunit.test_nitunit::X.test_nitunit::X::toto (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+test_nitunit.nit:23,2--25,0: FAILURE: test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+
+test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
 
 Results saved in out/nitunit_args1.write
-Entities: 3; Documented ones: 3; With nitunits: 3; Failures: 2
+
+DocUnits:
+Entities: 27; Documented ones: 3; With nitunits: 3; Failures: 2
+
+TestSuites:
+Class suites: 1; Test Cases: 3; Failures: 1
 <testsuites><testsuite package="test_nitunit"><testcase classname="test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
 </system-out></testcase><testcase classname="test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-err></system-err><system-out>assert false
 </system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
-"></error></testcase><testcase classname="test_nitunit.test_nitunit::X" name="test_nitunit::X::toto"><system-err></system-err><system-out>assert undefined_identifier
+"></error></testcase><testcase classname="test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><system-err></system-err><system-out>assert undefined_identifier
 </system-out><failure message=".nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
-"></failure></testcase></testsuite></testsuites>
\ No newline at end of file
+"></failure></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err><system-out>out</system-out></testcase><testcase classname="test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><system-err></system-err><system-out>out</system-out><error message="Runtime error: Assert failed (test_test_nitunit.nit:39)
+"></error></testcase><testcase classname="test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err><system-out>out</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
diff --git a/tests/sav/nitunit_args2.res b/tests/sav/nitunit_args2.res
new file mode 100644 (file)
index 0000000..bc00752
--- /dev/null
@@ -0,0 +1,229 @@
+module test_test_nitunit is test_suite
+
+import test_suite
+import test_nitunit
+
+class TestX
+       super TestSuite
+
+       fun test_foo do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               subject.foo
+       end
+
+       fun test_foo1 do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var a: Int
+               var b: Int
+               subject.foo1(a, b)
+       end
+
+       fun test_foo3 do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var exp: Y[X]
+               var res = subject.foo3
+               assert exp == res
+       end
+end
+
+class TestY
+       super TestSuite
+
+       fun test_bra do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject[e]
+               assert exp == res
+       end
+
+       fun test_bra_assign do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var i: Int
+               subject[e] = i
+       end
+
+       fun test_plus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject + e
+               assert exp == res
+       end
+
+       fun test_minus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject - e
+               assert exp == res
+       end
+
+       fun test_star do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject * e
+               assert exp == res
+       end
+
+       fun test_slash do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject / e
+               assert exp == res
+       end
+
+       fun test_percent do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject % e
+               assert exp == res
+       end
+
+       fun test_unary_minus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var exp: Int
+               var res = -subject
+               assert exp == res
+       end
+
+       fun test_equals do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: nullable Object
+               var exp: Bool
+               var res = subject == e
+               assert exp == res
+       end
+
+       fun test_not_equals do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: nullable Object
+               var exp: Bool
+               var res = subject != e
+               assert exp == res
+       end
+
+       fun test_lt do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject < e
+               assert exp == res
+       end
+
+       fun test_le do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject <= e
+               assert exp == res
+       end
+
+       fun test_compare do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject <=> e
+               assert exp == res
+       end
+
+       fun test_ge do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject >= e
+               assert exp == res
+       end
+
+       fun test_gt do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject > e
+               assert exp == res
+       end
+end
+
+class TestZ
+       super TestSuite
+
+       fun test_bra do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var exp: Bool
+               var res = subject[i, j]
+               assert exp == res
+       end
+
+       fun test_bra_assign do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var k: Bool
+               subject[i, j] = k
+       end
+
+       fun test_foo= do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               subject.foo(i) = j
+       end
+
+       fun test_bar= do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var k: Int
+               subject.bar(i, j) = k
+       end
+end
diff --git a/tests/sav/nitunit_args3.res b/tests/sav/nitunit_args3.res
new file mode 100644 (file)
index 0000000..e93c6ca
--- /dev/null
@@ -0,0 +1,246 @@
+module test_test_nitunit is test_suite
+
+import test_suite
+intrude import test_nitunit
+
+class TestX
+       super TestSuite
+
+       fun test_foo do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               subject.foo
+       end
+
+       fun test_foo1 do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var a: Int
+               var b: Int
+               subject.foo1(a, b)
+       end
+
+       fun test_foo2 do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var exp: Bool
+               var res = subject.foo2
+               assert exp == res
+       end
+
+       fun test_foo3 do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var exp: Y[X]
+               var res = subject.foo3
+               assert exp == res
+       end
+
+       fun test_foo3= do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: X
+               var foo3: Y[X]
+               subject.foo3 = foo3
+       end
+end
+
+class TestY
+       super TestSuite
+
+       fun test_bra do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject[e]
+               assert exp == res
+       end
+
+       fun test_bra_assign do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var i: Int
+               subject[e] = i
+       end
+
+       fun test_plus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject + e
+               assert exp == res
+       end
+
+       fun test_minus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject - e
+               assert exp == res
+       end
+
+       fun test_star do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject * e
+               assert exp == res
+       end
+
+       fun test_slash do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject / e
+               assert exp == res
+       end
+
+       fun test_percent do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Int
+               var res = subject % e
+               assert exp == res
+       end
+
+       fun test_unary_minus do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var exp: Int
+               var res = -subject
+               assert exp == res
+       end
+
+       fun test_equals do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: nullable Object
+               var exp: Bool
+               var res = subject == e
+               assert exp == res
+       end
+
+       fun test_not_equals do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: nullable Object
+               var exp: Bool
+               var res = subject != e
+               assert exp == res
+       end
+
+       fun test_lt do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject < e
+               assert exp == res
+       end
+
+       fun test_le do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject <= e
+               assert exp == res
+       end
+
+       fun test_compare do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject <=> e
+               assert exp == res
+       end
+
+       fun test_ge do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject >= e
+               assert exp == res
+       end
+
+       fun test_gt do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Y[X]
+               var e: Int
+               var exp: Bool
+               var res = subject > e
+               assert exp == res
+       end
+end
+
+class TestZ
+       super TestSuite
+
+       fun test_bra do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var exp: Bool
+               var res = subject[i, j]
+               assert exp == res
+       end
+
+       fun test_bra_assign do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var k: Bool
+               subject[i, j] = k
+       end
+
+       fun test_foo= do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               subject.foo(i) = j
+       end
+
+       fun test_bar= do
+               assert not_implemented: false # TODO remove once implemented
+
+               var subject: Z
+               var i: Int
+               var j: Int
+               var k: Int
+               subject.bar(i, j) = k
+       end
+end
diff --git a/tests/sav/pep8analysis_web.res b/tests/sav/pep8analysis_web.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/puzzle.res b/tests/sav/puzzle.res
new file mode 100644 (file)
index 0000000..e8bb145
--- /dev/null
@@ -0,0 +1,27 @@
+Usage: puzzle [--configs] initial...
+
+--configs: search and time solutions with various configurations of solvers.
+initial:   an initial configuration (letters for the tiles, and dot for the hole). eg:
+
+ 8-puzzle:
+
+ goal (0):    abcdefgh.
+ easy (4):    abce.fdgh
+ medium (10): eabf.cdgh
+ hard (20):   feacbh.dg
+ harder (31): hfgbedc.a
+
+ 15-puzzle:
+ goal (0):    abcdefghijklmno.
+ easy (30):   bacdefghijlkmno.
+ medium (40): fg.jacoheldnibmk
+ hard (55):   kleg.mondcafjhbi
+ harder (61): lomgkcend.afjhbi
+
+ 24-puzzle:
+ goal (0):    abcdefghijklmnopqrstuvwx.
+ easy (55):   giabcjekmdhrtflqsownpuv.x
+ medium (75): giabcjekmdrtwulhs.vnqofpx
+ hard (79):   giabcjekmdrtw.uhsvnlqofpx
+ harder (80): giabcjekmdrt.wuhsvnlqofpx
+
diff --git a/tests/sav/queens.res b/tests/sav/queens.res
new file mode 100644 (file)
index 0000000..e3658cd
--- /dev/null
@@ -0,0 +1,922 @@
+The 8-queens problem
++--------+
+|.......Q|
+|...Q....|
+|Q.......|
+|..Q.....|
+|.....Q..|
+|.Q......|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|.......Q|
+|..Q.....|
+|Q.......|
+|.....Q..|
+|.Q......|
+|....Q...|
+|......Q.|
+|...Q....|
++--------+
++--------+
+|.......Q|
+|.Q......|
+|....Q...|
+|..Q.....|
+|Q.......|
+|......Q.|
+|...Q....|
+|.....Q..|
++--------+
++--------+
+|.......Q|
+|.Q......|
+|...Q....|
+|Q.......|
+|......Q.|
+|....Q...|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|......Q.|
+|....Q...|
+|..Q.....|
+|Q.......|
+|.....Q..|
+|.......Q|
+|.Q......|
+|...Q....|
++--------+
++--------+
+|......Q.|
+|...Q....|
+|.Q......|
+|.......Q|
+|.....Q..|
+|Q.......|
+|..Q.....|
+|....Q...|
++--------+
++--------+
+|......Q.|
+|...Q....|
+|.Q......|
+|....Q...|
+|.......Q|
+|Q.......|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|......Q.|
+|..Q.....|
+|.......Q|
+|.Q......|
+|....Q...|
+|Q.......|
+|.....Q..|
+|...Q....|
++--------+
++--------+
+|......Q.|
+|..Q.....|
+|Q.......|
+|.....Q..|
+|.......Q|
+|....Q...|
+|.Q......|
+|...Q....|
++--------+
++--------+
+|......Q.|
+|.Q......|
+|.....Q..|
+|..Q.....|
+|Q.......|
+|...Q....|
+|.......Q|
+|....Q...|
++--------+
++--------+
+|......Q.|
+|.Q......|
+|...Q....|
+|Q.......|
+|.......Q|
+|....Q...|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|......Q.|
+|Q.......|
+|..Q.....|
+|.......Q|
+|.....Q..|
+|...Q....|
+|.Q......|
+|....Q...|
++--------+
++--------+
+|.....Q..|
+|.......Q|
+|.Q......|
+|...Q....|
+|Q.......|
+|......Q.|
+|....Q...|
+|..Q.....|
++--------+
++--------+
+|.....Q..|
+|...Q....|
+|......Q.|
+|Q.......|
+|.......Q|
+|.Q......|
+|....Q...|
+|..Q.....|
++--------+
++--------+
+|.....Q..|
+|...Q....|
+|......Q.|
+|Q.......|
+|..Q.....|
+|....Q...|
+|.Q......|
+|.......Q|
++--------+
++--------+
+|.....Q..|
+|...Q....|
+|.Q......|
+|.......Q|
+|....Q...|
+|......Q.|
+|Q.......|
+|..Q.....|
++--------+
++--------+
+|.....Q..|
+|...Q....|
+|Q.......|
+|....Q...|
+|.......Q|
+|.Q......|
+|......Q.|
+|..Q.....|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|......Q.|
+|...Q....|
+|Q.......|
+|.......Q|
+|.Q......|
+|....Q...|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|......Q.|
+|.Q......|
+|.......Q|
+|....Q...|
+|Q.......|
+|...Q....|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|......Q.|
+|.Q......|
+|...Q....|
+|.......Q|
+|Q.......|
+|....Q...|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|....Q...|
+|.......Q|
+|Q.......|
+|...Q....|
+|.Q......|
+|......Q.|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|....Q...|
+|......Q.|
+|Q.......|
+|...Q....|
+|.Q......|
+|.......Q|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|Q.......|
+|.......Q|
+|....Q...|
+|.Q......|
+|...Q....|
+|......Q.|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|Q.......|
+|.......Q|
+|...Q....|
+|.Q......|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|.....Q..|
+|..Q.....|
+|Q.......|
+|......Q.|
+|....Q...|
+|.......Q|
+|.Q......|
+|...Q....|
++--------+
++--------+
+|.....Q..|
+|.Q......|
+|......Q.|
+|Q.......|
+|...Q....|
+|.......Q|
+|....Q...|
+|..Q.....|
++--------+
++--------+
+|.....Q..|
+|.Q......|
+|......Q.|
+|Q.......|
+|..Q.....|
+|....Q...|
+|.......Q|
+|...Q....|
++--------+
++--------+
+|.....Q..|
+|Q.......|
+|....Q...|
+|.Q......|
+|.......Q|
+|..Q.....|
+|......Q.|
+|...Q....|
++--------+
++--------+
+|....Q...|
+|.......Q|
+|...Q....|
+|Q.......|
+|......Q.|
+|.Q......|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|....Q...|
+|.......Q|
+|...Q....|
+|Q.......|
+|..Q.....|
+|.....Q..|
+|.Q......|
+|......Q.|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|...Q....|
+|Q.......|
+|..Q.....|
+|.......Q|
+|.....Q..|
+|.Q......|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|.Q......|
+|.....Q..|
+|..Q.....|
+|Q.......|
+|.......Q|
+|...Q....|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|.Q......|
+|.....Q..|
+|..Q.....|
+|Q.......|
+|...Q....|
+|.......Q|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|.Q......|
+|...Q....|
+|.......Q|
+|Q.......|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|Q.......|
+|...Q....|
+|.Q......|
+|.......Q|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|....Q...|
+|......Q.|
+|Q.......|
+|..Q.....|
+|.......Q|
+|.....Q..|
+|...Q....|
+|.Q......|
++--------+
++--------+
+|....Q...|
+|..Q.....|
+|.......Q|
+|...Q....|
+|......Q.|
+|Q.......|
+|.....Q..|
+|.Q......|
++--------+
++--------+
+|....Q...|
+|..Q.....|
+|Q.......|
+|......Q.|
+|.Q......|
+|.......Q|
+|.....Q..|
+|...Q....|
++--------+
++--------+
+|....Q...|
+|..Q.....|
+|Q.......|
+|.....Q..|
+|.......Q|
+|.Q......|
+|...Q....|
+|......Q.|
++--------+
++--------+
+|....Q...|
+|.Q......|
+|.......Q|
+|Q.......|
+|...Q....|
+|......Q.|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|....Q...|
+|.Q......|
+|.....Q..|
+|Q.......|
+|......Q.|
+|...Q....|
+|.......Q|
+|..Q.....|
++--------+
++--------+
+|....Q...|
+|.Q......|
+|...Q....|
+|......Q.|
+|..Q.....|
+|.......Q|
+|.....Q..|
+|Q.......|
++--------+
++--------+
+|....Q...|
+|.Q......|
+|...Q....|
+|.....Q..|
+|.......Q|
+|..Q.....|
+|Q.......|
+|......Q.|
++--------+
++--------+
+|....Q...|
+|Q.......|
+|.......Q|
+|.....Q..|
+|..Q.....|
+|......Q.|
+|.Q......|
+|...Q....|
++--------+
++--------+
+|....Q...|
+|Q.......|
+|.......Q|
+|...Q....|
+|.Q......|
+|......Q.|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|....Q...|
+|Q.......|
+|...Q....|
+|.....Q..|
+|.......Q|
+|.Q......|
+|......Q.|
+|..Q.....|
++--------+
++--------+
+|...Q....|
+|.......Q|
+|....Q...|
+|..Q.....|
+|Q.......|
+|......Q.|
+|.Q......|
+|.....Q..|
++--------+
++--------+
+|...Q....|
+|.......Q|
+|Q.......|
+|....Q...|
+|......Q.|
+|.Q......|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|...Q....|
+|.......Q|
+|Q.......|
+|..Q.....|
+|.....Q..|
+|.Q......|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|...Q....|
+|......Q.|
+|....Q...|
+|..Q.....|
+|Q.......|
+|.....Q..|
+|.......Q|
+|.Q......|
++--------+
++--------+
+|...Q....|
+|......Q.|
+|....Q...|
+|.Q......|
+|.....Q..|
+|Q.......|
+|..Q.....|
+|.......Q|
++--------+
++--------+
+|...Q....|
+|......Q.|
+|..Q.....|
+|.......Q|
+|.Q......|
+|....Q...|
+|Q.......|
+|.....Q..|
++--------+
++--------+
+|...Q....|
+|......Q.|
+|Q.......|
+|.......Q|
+|....Q...|
+|.Q......|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|...Q....|
+|.....Q..|
+|.......Q|
+|..Q.....|
+|Q.......|
+|......Q.|
+|....Q...|
+|.Q......|
++--------+
++--------+
+|...Q....|
+|.....Q..|
+|.......Q|
+|.Q......|
+|......Q.|
+|Q.......|
+|..Q.....|
+|....Q...|
++--------+
++--------+
+|...Q....|
+|.....Q..|
+|Q.......|
+|....Q...|
+|.Q......|
+|.......Q|
+|..Q.....|
+|......Q.|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|.......Q|
+|.....Q..|
+|Q.......|
+|..Q.....|
+|....Q...|
+|......Q.|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|.......Q|
+|....Q...|
+|......Q.|
+|Q.......|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|......Q.|
+|....Q...|
+|Q.......|
+|.......Q|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|......Q.|
+|..Q.....|
+|.....Q..|
+|.......Q|
+|....Q...|
+|Q.......|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|......Q.|
+|..Q.....|
+|.....Q..|
+|.......Q|
+|Q.......|
+|....Q...|
++--------+
++--------+
+|...Q....|
+|.Q......|
+|....Q...|
+|.......Q|
+|.....Q..|
+|Q.......|
+|..Q.....|
+|......Q.|
++--------+
++--------+
+|...Q....|
+|Q.......|
+|....Q...|
+|.......Q|
+|.....Q..|
+|..Q.....|
+|......Q.|
+|.Q......|
++--------+
++--------+
+|...Q....|
+|Q.......|
+|....Q...|
+|.......Q|
+|.Q......|
+|......Q.|
+|..Q.....|
+|.....Q..|
++--------+
++--------+
+|..Q.....|
+|.......Q|
+|...Q....|
+|......Q.|
+|Q.......|
+|.....Q..|
+|.Q......|
+|....Q...|
++--------+
++--------+
+|..Q.....|
+|......Q.|
+|.Q......|
+|.......Q|
+|.....Q..|
+|...Q....|
+|Q.......|
+|....Q...|
++--------+
++--------+
+|..Q.....|
+|......Q.|
+|.Q......|
+|.......Q|
+|....Q...|
+|Q.......|
+|...Q....|
+|.....Q..|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.......Q|
+|.Q......|
+|...Q....|
+|Q.......|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.......Q|
+|Q.......|
+|....Q...|
+|......Q.|
+|.Q......|
+|...Q....|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.......Q|
+|Q.......|
+|...Q....|
+|......Q.|
+|....Q...|
+|.Q......|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|...Q....|
+|.Q......|
+|.......Q|
+|....Q...|
+|......Q.|
+|Q.......|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|...Q....|
+|Q.......|
+|.......Q|
+|....Q...|
+|......Q.|
+|.Q......|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.Q......|
+|......Q.|
+|....Q...|
+|Q.......|
+|.......Q|
+|...Q....|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.Q......|
+|......Q.|
+|Q.......|
+|...Q....|
+|.......Q|
+|....Q...|
++--------+
++--------+
+|..Q.....|
+|.....Q..|
+|.Q......|
+|....Q...|
+|.......Q|
+|Q.......|
+|......Q.|
+|...Q....|
++--------+
++--------+
+|..Q.....|
+|....Q...|
+|.......Q|
+|...Q....|
+|Q.......|
+|......Q.|
+|.Q......|
+|.....Q..|
++--------+
++--------+
+|..Q.....|
+|....Q...|
+|......Q.|
+|Q.......|
+|...Q....|
+|.Q......|
+|.......Q|
+|.....Q..|
++--------+
++--------+
+|..Q.....|
+|....Q...|
+|.Q......|
+|.......Q|
+|.....Q..|
+|...Q....|
+|......Q.|
+|Q.......|
++--------+
++--------+
+|..Q.....|
+|....Q...|
+|.Q......|
+|.......Q|
+|Q.......|
+|......Q.|
+|...Q....|
+|.....Q..|
++--------+
++--------+
+|..Q.....|
+|Q.......|
+|......Q.|
+|....Q...|
+|.......Q|
+|.Q......|
+|...Q....|
+|.....Q..|
++--------+
++--------+
+|.Q......|
+|.......Q|
+|.....Q..|
+|Q.......|
+|..Q.....|
+|....Q...|
+|......Q.|
+|...Q....|
++--------+
++--------+
+|.Q......|
+|......Q.|
+|....Q...|
+|.......Q|
+|Q.......|
+|...Q....|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|.Q......|
+|......Q.|
+|..Q.....|
+|.....Q..|
+|.......Q|
+|....Q...|
+|Q.......|
+|...Q....|
++--------+
++--------+
+|.Q......|
+|.....Q..|
+|.......Q|
+|..Q.....|
+|Q.......|
+|...Q....|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|.Q......|
+|.....Q..|
+|Q.......|
+|......Q.|
+|...Q....|
+|.......Q|
+|..Q.....|
+|....Q...|
++--------+
++--------+
+|.Q......|
+|....Q...|
+|......Q.|
+|...Q....|
+|Q.......|
+|.......Q|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|.Q......|
+|....Q...|
+|......Q.|
+|Q.......|
+|..Q.....|
+|.......Q|
+|.....Q..|
+|...Q....|
++--------+
++--------+
+|.Q......|
+|...Q....|
+|.....Q..|
+|.......Q|
+|..Q.....|
+|Q.......|
+|......Q.|
+|....Q...|
++--------+
++--------+
+|Q.......|
+|......Q.|
+|....Q...|
+|.......Q|
+|.Q......|
+|...Q....|
+|.....Q..|
+|..Q.....|
++--------+
++--------+
+|Q.......|
+|......Q.|
+|...Q....|
+|.....Q..|
+|.......Q|
+|.Q......|
+|....Q...|
+|..Q.....|
++--------+
++--------+
+|Q.......|
+|.....Q..|
+|.......Q|
+|..Q.....|
+|......Q.|
+|...Q....|
+|.Q......|
+|....Q...|
++--------+
++--------+
+|Q.......|
+|....Q...|
+|.......Q|
+|.....Q..|
+|..Q.....|
+|......Q.|
+|.Q......|
+|...Q....|
++--------+
+Found 92 solutions
diff --git a/tests/sav/shoot_android.res b/tests/sav/shoot_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/shoot_linux.res b/tests/sav/shoot_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/simple_android.res b/tests/sav/simple_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
diff --git a/tests/sav/simple_linux.res b/tests/sav/simple_linux.res
new file mode 100644 (file)
index 0000000..92405d4
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.
diff --git a/tests/sav/test_platform_android.res b/tests/sav/test_platform_android.res
deleted file mode 100644 (file)
index 174d681..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Not executable (platform?)
index 4afd56d..b583197 100644 (file)
@@ -22,5 +22,39 @@ module test_nitunit
 class X
        # a 'failure' unit test (does not compile)
        #     assert undefined_identifier
-       fun toto do end
+       fun foo do end
+
+       fun foo1(a, b: Int) do end
+
+       private fun foo2: Bool do return true
+
+       var foo3: Y[X] = new Y[X]
+end
+
+class Y[E: X]
+       fun [](e: Int): Int do return e
+       fun []=(e, i: Int) do end
+
+       fun +(e: Int): Int do return e
+       fun -(e: Int): Int do return e
+       fun *(e: Int): Int do return e
+       fun /(e: Int): Int do return e
+       fun %(e: Int): Int do return e
+       fun -: Int do return -1
+
+       redef fun ==(e) do return true
+       redef fun !=(e) do return true
+
+       fun <(e: Int): Bool do return true
+       fun <=(e: Int): Bool do return true
+       fun <=>(e: Int): Bool do return true
+       fun >=(e: Int): Bool do return true
+       fun >(e: Int): Bool do return true
+end
+
+class Z
+       fun [](i, j: Int): Bool do return true
+       fun []=(i, j: Int, k: Bool) do end
+       fun foo=(i, j: Int) do end
+       fun bar=(i, j, k: Int) do end
 end
diff --git a/tests/test_test_nitunit.nit b/tests/test_test_nitunit.nit
new file mode 100644 (file)
index 0000000..71ce971
--- /dev/null
@@ -0,0 +1,45 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2004-2008 Jean Privat <jean@pryen.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.
+
+# NitUnit file for test_nitunit module.
+module test_test_nitunit is test_suite
+
+import test_suite
+intrude import test_nitunit
+
+class TestX
+       super TestSuite
+
+       var subject: X is noinit
+
+       redef fun before_test do
+               subject = new X
+       end
+
+       fun test_foo do
+               subject.foo
+       end
+
+       # will fail
+       fun test_foo1 do
+               subject.foo1(10, 20)
+               assert false
+       end
+
+       fun test_foo2 do
+               assert subject.foo2
+       end
+end
index 0943020..6455466 100755 (executable)
@@ -551,7 +551,8 @@ END
                                done < $fargs
                        fi
                elif [ -f "./$ff.bin" ]; then
-                       echo "Not executable (platform?)" > "$ff.res"
+                       #Not executable (platform?)"
+                       > "$ff.res"
                        process_result $bf "$bf" $pack
                else
                        echo -n "! "