X-Git-Url: http://nitlanguage.org diff --git a/src/nitunit.nit b/src/nitunit.nit index 05cdcc5..e2404ca 100644 --- a/src/nitunit.nit +++ b/src/nitunit.nit @@ -23,8 +23,8 @@ import parser_util class NitUnitExecutor super Doc2Mdwn - # The name of the module to import - var modname: String + # The module to import + var mmodule: MModule # The prefix of the generated Nit source-file var prefix: String @@ -33,16 +33,16 @@ class NitUnitExecutor var testsuite: HTMLTag # Initialize a new e - init(toolcontext: ToolContext, prefix: String, modname: String, testsuite: HTMLTag) + init(toolcontext: ToolContext, prefix: String, mmodule: MModule, testsuite: HTMLTag) do super(toolcontext) self.prefix = prefix - self.modname = modname + self.mmodule = mmodule self.testsuite = testsuite end # All blocks of code from a same `ADoc` - var block = new Array[String] + var blocks = new Array[Array[String]] redef fun process_code(n: HTMLTag, text: String) do @@ -50,17 +50,39 @@ class NitUnitExecutor var ast = toolcontext.parse_something(text) # We want executable code - if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then return + 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 return + 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 - block.add(text) + blocks.last.add(text) end + # The associated node to localize warnings + var ndoc: nullable ADoc + # used to generate distinct names var cpt = 0 @@ -68,16 +90,27 @@ class NitUnitExecutor # Fill the prepated `tc` (testcase) XTM node fun extract(ndoc: ADoc, tc: HTMLTag) do - block.clear + blocks.clear - work(ndoc) + self.ndoc = ndoc + + work(ndoc.to_mdoc) + toolcontext.check_errors - if block.is_empty then return + 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 {tc.attrs["classname"]}.{tc.attrs["name"]} in {file}", 2) + toolcontext.info("Execute {tc.attrs["name"]} in {file}", 1) var dir = file.dirname if dir != "" then dir.mkdir @@ -85,15 +118,22 @@ class NitUnitExecutor f = new OFStream.open(file) f.write("# GENERATED FILE\n") f.write("# Example extracted from a documentation\n") - var modname = self.modname - f.write("import {modname}\n") + f.write("import {mmodule.name}\n") f.write("\n") for text in block do f.write(text) end f.close - var cmd = "../bin/nitg --no-color '{file}' -I . >'{file}.out1' 2>&1 ") - tc.attr("name", "") - 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 - var ndoc = nclassdef.n_doc - if ndoc != null then - tc = new HTMLTag("testcase") - tc.attr("classname", mmodule.full_name + "." + mclassdef.mclass.full_name) - tc.attr("name", "") - d2m.extract(ndoc, tc) - end + 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 + ".") + tc.attr("name", "") + 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", "") + d2m.extract(ndoc, tc) end - for npropdef in nclassdef.n_propdefs do - var mpropdef = npropdef.mpropdef.as(not null) - var ndoc = npropdef.n_doc - if ndoc != null then - 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 + 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 @@ -212,20 +269,16 @@ 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.option_context.add_option(toolcontext.opt_full, toolcontext.opt_output, toolcontext.opt_dir, toolcontext.opt_noact) +toolcontext.tooldescription = "Usage: nitunit [OPTION]... ...\nExecutes the unit tests from Nit source files." -toolcontext.process_options +toolcontext.process_options(args) var args = toolcontext.option_context.rest -if args.is_empty or toolcontext.opt_help.value then - print "usage: nitunit [options] file.nit..." - toolcontext.option_context.usage - return -end var model = new Model var modelbuilder = new ModelBuilder(model, toolcontext) @@ -243,4 +296,12 @@ end var file = toolcontext.opt_output.value if file == null then file = "nitunit.xml" -page.save(file) +page.write_to_file(file) +print "Results saved in {file}" + +if modelbuilder.unit_entities == 0 then + print "No nitunits found" +else if modelbuilder.failed_entities == 0 and not toolcontext.opt_noact.value then + print "Success" +end +print "Entities: {modelbuilder.total_entities}; Documented ones: {modelbuilder.doc_entities}; With nitunits: {modelbuilder.unit_entities}; Failures: {modelbuilder.failed_entities}"