X-Git-Url: http://nitlanguage.org diff --git a/src/testing/testing_suite.nit b/src/testing/testing_suite.nit index f102c6c..13cf20f 100644 --- a/src/testing/testing_suite.nit +++ b/src/testing/testing_suite.nit @@ -17,7 +17,8 @@ module testing_suite import testing_base import html -private import annotation +private import parse_annotations +private import realtime redef class ToolContext # --pattern @@ -37,29 +38,49 @@ class NitUnitTester var toolcontext = mbuilder.toolcontext 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 + for mmethod in mmodule.before_all do toolcontext.modelbuilder.total_tests += 1 - suite.before_module = new TestCase(suite, before_module, toolcontext) + suite.before_all.add new TestCase(suite, mmethod, 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 test_class = new TestClass + + # method to execute before all tests in the class + for mmethod in mclassdef.before_all do + toolcontext.modelbuilder.total_tests += 1 + test_class.before_all.add new TestCase(suite, mmethod, toolcontext) + end + + var before = mclassdef.before + var after = mclassdef.after + 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) - suite.add_test test + test.before = before + test.after = after + test_class.test_cases.add test end + + # method to execute after all tests in the class + for mmethod in mclassdef.after_all do + toolcontext.modelbuilder.total_tests += 1 + test_class.after_all.add new TestCase(suite, mmethod, toolcontext) + end + + suite.test_classes.add test_class end # method to execute after all tests in the module - var after_module = mmodule.after_test - if after_module != null then + for mmethod in mmodule.after_all do toolcontext.modelbuilder.total_tests += 1 - suite.after_module = new TestCase(suite, after_module, toolcontext) + suite.after_all.add new TestCase(suite, mmethod, toolcontext) end suite.run return suite @@ -110,42 +131,125 @@ class TestSuite 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 + var test_classes = new Array[TestClass] - # Test to be executed before the whole test suite. - var before_module: nullable TestCase = null + # Tests to be executed before the whole test suite. + var before_all = new Array[TestCase] - # Test to be executed after the whole test suite. - var after_module: nullable TestCase = null + # Tests to be executed after the whole test suite. + var after_all = new Array[TestCase] - fun show_status - do + # Display test suite status in std-out. + fun show_status do + var test_cases = new Array[TestCase] + for test_class in test_classes do + test_cases.add_all test_class.before_all + test_cases.add_all test_class.test_cases + test_cases.add_all test_class.after_all + end + test_cases.add_all before_all + test_cases.add_all after_all toolcontext.show_unit_status("Test-suite of module " + mmodule.full_name, test_cases) end # Execute the test suite fun run do + set_env show_status if not toolcontext.test_dir.file_exists then toolcontext.test_dir.mkdir end write_to_nit compile + if failure != null then + for test_class in test_classes do + for case in test_class.test_cases do + case.fail "Compilation Error" + case.raw_output = failure + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + end + end + show_status + print "" + return + end toolcontext.info("Execute test-suite {mmodule.name}", 1) - var before_module = self.before_module - if not before_module == null then before_module.run - for case in test_cases do - case.run + + for before_module in before_all do + before_module.run toolcontext.clear_progress_bar - toolcontext.show_unit(case) - show_status + toolcontext.show_unit(before_module) + if before_module.error != null then + for test_class in test_classes do + for case in test_class.before_all do + case.fail "Nitunit Error: before module test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + end + for case in test_class.test_cases do + case.fail "Nitunit Error: before module test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + end + for case in test_class.after_all do + case.fail "Nitunit Error: before module test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + end + end + for after_module in after_all do + after_module.fail "Nitunit Error: before module test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(after_module) + end + show_status + print "" + return + end + end + + for test_class in test_classes do + for case in test_class.before_all do + case.run + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + if case.error != null then + for scase in test_class.test_cases do + scase.fail "Nitunit Error: before class test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(scase) + end + for scase in test_class.after_all do + scase.fail "Nitunit Error: before class test failed" + toolcontext.clear_progress_bar + toolcontext.show_unit(scase) + end + show_status + print "" + return + end + end + for case in test_class.test_cases do + case.run + toolcontext.clear_progress_bar + toolcontext.show_unit(case) + show_status + end + for after_class in test_class.after_all do + after_class.run + toolcontext.clear_progress_bar + toolcontext.show_unit(after_class) + show_status + end end - var after_module = self.after_module - if not after_module == null then after_module.run + for after_module in after_all do + after_module.run + toolcontext.clear_progress_bar + toolcontext.show_unit(after_module) + show_status + end show_status print "" @@ -154,11 +258,25 @@ class TestSuite # Write the test unit for `self` in a nit compilable file. fun write_to_nit do var file = new Template - file.addn "intrude import test_suite" + file.addn "intrude import core" file.addn "import {mmodule.name}\n" file.addn "var name = args.first" - for case in test_cases do - case.write_to_nit(file) + for before_module in before_all do + before_module.write_to_nit(file) + end + for test_class in test_classes do + for case in test_class.before_all do + case.write_to_nit(file) + end + for case in test_class.test_cases do + case.write_to_nit(file) + end + for case in test_class.after_all do + case.write_to_nit(file) + end + end + for after_module in after_all do + after_module.write_to_nit(file) end file.write_to_file("{test_file}.nit") end @@ -168,13 +286,8 @@ class TestSuite fun to_xml: HTMLTag do var n = new HTMLTag("testsuite") n.attr("package", mmodule.name) - var failure = self.failure - if failure != null then - var f = new HTMLTag("failure") - f.attr("message", failure.to_s) - n.add f - else - for test in test_cases do n.add test.to_xml + for test_class in test_classes do + for test in test_class.test_cases do n.add test.to_xml end return n end @@ -202,20 +315,36 @@ class TestSuite var f = new FileReader.open("{file}.out") var msg = f.read_all f.close - # set test case result - var loc = mmodule.location if res != 0 then failure = msg - toolcontext.warning(loc, "failure", "FAILURE: {mmodule.name} (in file {file}.nit): {msg}") - toolcontext.modelbuilder.failed_tests += 1 end - toolcontext.check_errors + end + + # Set environment variables for test suite execution + fun set_env do + var loc = mmodule.location.file + if loc == null then return + toolcontext.set_testing_path(loc.filename) end # Error occured during test-suite compilation. var failure: nullable String = null end +# A test class contains multiple test cases +# +# For each test class, methods can be executed before and after all cases. +class TestClass + # List of `TestCase` to be executed in this suite. + var test_cases = new Array[TestCase] + + # Tests to be executed before the whole test suite. + var before_all = new Array[TestCase] + + # Tests to be executed after the whole test suite. + var after_all = new Array[TestCase] +end + # A test case is a unit test considering only a `MMethodDef`. class TestCase super UnitTest @@ -226,6 +355,12 @@ class TestCase # Test method to be compiled and tested. var test_method: MMethodDef + # Cases to execute before this one + var before = new Array[MMethodDef] + + # Cases to execute after this one + var after = new Array[MMethodDef] + redef fun full_name do return test_method.full_name redef fun location do return test_method.location @@ -240,10 +375,14 @@ class TestCase if test_method.mproperty.is_toplevel then file.addn "\t{name}" else - file.addn "\tvar subject = new {test_method.mclassdef.name}.nitunit" - file.addn "\tsubject.before_test" + file.addn "\tvar subject = new {test_method.mclassdef.name}.intern" + for mmethod in before do + file.addn "\tsubject.{mmethod.name}" + end file.addn "\tsubject.{name}" - file.addn "\tsubject.after_test" + for mmethod in after do + file.addn "\tsubject.{mmethod.name}" + end end file.addn "end" end @@ -257,7 +396,10 @@ class TestCase var method_name = test_method.name var test_file = test_suite.test_file var res_name = "{test_file}_{method_name.escape_to_c}" + var clock = new Clock var res = toolcontext.safe_exec("{test_file}.bin {method_name} > '{res_name}.out1' 2>&1