X-Git-Url: http://nitlanguage.org diff --git a/src/testing/testing_doc.nit b/src/testing/testing_doc.nit index 6bd8f0b..75e0830 100644 --- a/src/testing/testing_doc.nit +++ b/src/testing/testing_doc.nit @@ -36,11 +36,8 @@ class NitUnitExecutor # The XML node associated to the module var testsuite: HTMLTag - # All blocks of code from a same `ADoc` - var blocks = new Array[Buffer] - - # All failures from a same `ADoc` - var failures = new Array[String] + # The name of the suite + var name: String # Markdown processor used to parse markdown comments and extract code. var mdproc = new MarkdownProcessor @@ -55,56 +52,89 @@ class NitUnitExecutor # used to generate distinct names var cpt = 0 + # The last docunit extracted from a mdoc. + # + # Is used because a new code-block might just be added to it. + var last_docunit: nullable DocUnit = null + + var xml_classname: String is noautoinit + + var xml_name: String is noautoinit + # The entry point for a new `ndoc` node # Fill `docunits` with new discovered unit of tests. - # - # `tc` (testcase) is the pre-filled XML node - fun extract(mdoc: MDoc, tc: HTMLTag) + fun extract(mdoc: MDoc, xml_classname, xml_name: String) do - blocks.clear - failures.clear + last_docunit = null + self.xml_classname = xml_classname + self.xml_name = xml_name self.mdoc = mdoc # Populate `blocks` from the markdown decorator mdproc.process(mdoc.content.join("\n")) - - toolcontext.check_errors - - if not failures.is_empty then - for msg in failures do - var ne = new HTMLTag("failure") - ne.attr("message", msg) - tc.add ne - toolcontext.modelbuilder.unit_entities += 1 - toolcontext.modelbuilder.failed_entities += 1 - end - if blocks.is_empty then testsuite.add(tc) - end - - if blocks.is_empty then return - for block in blocks do - docunits.add new DocUnit(mdoc, tc, block.write_to_string) - end end # All extracted docunits var docunits = new Array[DocUnit] + fun show_status + do + toolcontext.show_unit_status(name, docunits) + end + + fun mark_done(du: DocUnit) + do + du.is_done = true + toolcontext.clear_progress_bar + toolcontext.show_unit(du) + show_status + end + # Execute all the docunits fun run_tests do + if docunits.is_empty then + return + end + + # Try to group each nitunit into a single source file to fasten the compilation var simple_du = new Array[DocUnit] + show_status for du in docunits do + # Skip existing errors + if du.error != null then + continue + end + var ast = toolcontext.parse_something(du.block) if ast isa AExpr then simple_du.add du + end + end + test_simple_docunits(simple_du) + + # Now test them in order + for du in docunits do + if du.error != null then + # Nothing to execute. Conclude + else if du.test_file != null then + # Already compiled. Execute it. + execute_simple_docunit(du) else + # Need to try to compile it, then execute it test_single_docunit(du) end + mark_done(du) end - test_simple_docunits(simple_du) + # Final status + show_status + print "" + + for du in docunits do + testsuite.add du.to_xml + end end # Executes multiples doc-units in a shared program. @@ -128,7 +158,7 @@ class NitUnitExecutor i += 1 f.write("fun run_{i} do\n") - f.write("# {du.testcase.attrs["name"]}\n") + f.write("# {du.full_name}\n") f.write(du.block) f.write("end\n") end @@ -144,43 +174,35 @@ class NitUnitExecutor if res != 0 then # Compilation error. - # Fall-back to individual modes: - for du in dus do - test_single_docunit(du) - end + # They will be executed independently return end + # Compilation was a success. + # Store what need to be executed for each one. i = 0 for du in dus do - var tc = du.testcase - toolcontext.modelbuilder.unit_entities += 1 i += 1 - toolcontext.info("Execute doc-unit {du.testcase.attrs["name"]} in {file} {i}", 1) - var res2 = sys.system("{file.to_program_name}.bin {i} >>'{file}.out1' 2>&1 '{file}.out1' 2>&1 >'{file}.out1' 2>&1 '{file}.out1' 2>&1 '{file}.out1' 2>&1 '{file}.out1' 2>&1 1 then + res += "#{number}" + end + return res + else + return xml_classname + "." + xml_name + end + end + + # The text of the code to execute. + # + # This is the verbatim content on one, or more, code-blocks from `mdoc` var block: String + + # For each line in `block`, the associated line in the mdoc + # + # Is used to give precise locations + var lines = new Array[Int] + + # For each line in `block`, the associated column in the mdoc + # + # Is used to give precise locations + var columns = new Array[Int] + + # The location of the whole docunit. + # + # If `self` is made of multiple code-blocks, then the location + # starts at the first code-books and finish at the last one, thus includes anything between. + redef var location is lazy do + return new Location(mdoc.location.file, lines.first, lines.last+1, columns.first+1, 0) + end + + # Compute the real location of a node on the `ast` based on `mdoc.location` + # + # The result is basically: ast_location + markdown location of the piece + mdoc.location + # + # The fun is that a single docunit can be made of various pieces of code blocks. + fun real_location(ast_location: Location): Location + do + var mdoc = self.mdoc + var res = new Location(mdoc.location.file, lines[ast_location.line_start-1], + lines[ast_location.line_end-1], + columns[ast_location.line_start-1] + ast_location.column_start, + columns[ast_location.line_end-1] + ast_location.column_end) + return res + end + + redef fun to_xml + do + var res = super + res.open("system-out").append(block) + return res + end + + redef var xml_classname + redef var xml_name end redef class ModelBuilder @@ -368,9 +499,7 @@ redef class ModelBuilder var prefix = toolcontext.test_dir prefix = prefix.join_path(mmodule.to_s) - var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts) - - var tc + var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of module {mmodule.full_name}") do total_entities += 1 @@ -379,11 +508,8 @@ redef class ModelBuilder 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", "nitunit." + mmodule.full_name + ".") - tc.attr("name", "") - d2m.extract(ndoc.to_mdoc, tc) + d2m.extract(ndoc.to_mdoc, "nitunit." + mmodule.full_name + ".", "") end label x for nclassdef in nmodule.n_classdefs do var mclassdef = nclassdef.mclassdef @@ -393,10 +519,7 @@ redef class ModelBuilder var ndoc = nclassdef.n_doc if ndoc != null then doc_entities += 1 - tc = new HTMLTag("testcase") - tc.attr("classname", "nitunit." + mmodule.full_name + "." + mclassdef.mclass.full_name) - tc.attr("name", "") - d2m.extract(ndoc.to_mdoc, tc) + d2m.extract(ndoc.to_mdoc, "nitunit." + mmodule.full_name + "." + mclassdef.mclass.full_name, "") end end for npropdef in nclassdef.n_propdefs do @@ -406,10 +529,7 @@ redef class ModelBuilder var ndoc = npropdef.n_doc if ndoc != null then doc_entities += 1 - tc = new HTMLTag("testcase") - tc.attr("classname", "nitunit." + mmodule.full_name + "." + mclassdef.mclass.full_name) - tc.attr("name", mpropdef.mproperty.full_name) - d2m.extract(ndoc.to_mdoc, tc) + d2m.extract(ndoc.to_mdoc, "nitunit." + mmodule.full_name + "." + mclassdef.mclass.full_name, mpropdef.mproperty.full_name) end end end @@ -433,20 +553,15 @@ redef class ModelBuilder var prefix = toolcontext.test_dir prefix = prefix.join_path(mgroup.to_s) - var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts) - - var tc + var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of group {mgroup.full_name}") total_entities += 1 var mdoc = mgroup.mdoc if mdoc == null then return ts doc_entities += 1 - tc = new HTMLTag("testcase") # NOTE: jenkins expects a '.' in the classname attr - tc.attr("classname", "nitunit." + mgroup.full_name) - tc.attr("name", "") - d2m.extract(mdoc, tc) + d2m.extract(mdoc, "nitunit." + mgroup.full_name, "") d2m.run_tests @@ -457,26 +572,20 @@ redef class ModelBuilder fun test_mdoc(mdoc: MDoc): HTMLTag do var ts = new HTMLTag("testsuite") - var file = mdoc.location.to_s + var file = mdoc.location.file.filename toolcontext.info("nitunit: doc-unit file {file}", 2) ts.attr("package", file) var prefix = toolcontext.test_dir / "file" - var d2m = new NitUnitExecutor(toolcontext, prefix, null, ts) - - var tc + var d2m = new NitUnitExecutor(toolcontext, prefix, null, ts, "Docunits of file {file}") total_entities += 1 doc_entities += 1 - tc = new HTMLTag("testcase") # NOTE: jenkins expects a '.' in the classname attr - tc.attr("classname", "nitunit.") - tc.attr("name", file) - - d2m.extract(mdoc, tc) + d2m.extract(mdoc, "nitunit.", file) d2m.run_tests return ts