parserImport XOCL; parserImport Aspects; /****************************************************************************** * * * Constraint Reporting * * -------------------- * * * * When a candidate is checked by a classifier, a constraint report is * * produced that contains the checks and whether they passed or failed. The * * constraint report is an instance of ConstraintReport and can be * * transformed into HTML via the aspect defined in this file. * * * ******************************************************************************/ import IO; context AllAspects::ToHTML @Class XCore::String @Operation stripNonAlphaChars() : String @Doc Strips all non-alphanumeric characters from a string. end let newSeq = Seq{} in @For c in self.asSeq() do if (c>=65 and c<=90) or (c>=97 and c<=122) then newSeq := newSeq->including(c) end end; newSeq.asString() end end end context AllAspects::ToHTML @Class XCore::String @Operation stripIllegalChars() : String @Doc Strips all illegal characters from a string. end let newSeq = Seq{} in @For c in self.asSeq() do if (c>=48 and c<=57) or c=95 or (c>=65 and c<=90) or (c>=97 and c<=122) then newSeq := newSeq->including(c) end end; newSeq.asString() end end end context AllAspects::ToHTML @Class ConstraintReport @Operation nodeText() : String if constraint<>null then "Constraint "+constraint.name else "Checks for "+candidate.toString() end end @Operation satisfiedHTMLColour():String let green = "#64C832"; red = "#FA6E64" in if satisfied then green else red end end end @Operation getLink() : String let basicString = candidate.toString() + if constraint<>null then constraint.name else "Checks" end in basicString.stripNonAlphaChars() end end @Operation writeHTML(path:String) // Write out the reports as an HTML file. let fout = FileOutputChannel(path) in format(fout,"~%"); format(fout,"~%~%~%Constraint Report~%~%~%"); format(fout,"Constraint Report (~S)


~%",Seq{xmf.date()}); self.writeHTMLChecks(fout,true); format(fout,"~%"); fout.close() end end @Operation toHTMLDoc(fout:OutputChannel) // Write out the reports as an HTML file. format(fout,"~%"); format(fout,"~%~%~%Constraint Report~%~%~%"); format(fout,"Constraint Report (~S)


~%",Seq{xmf.date()}); self.writeHTMLChecks(fout,false); format(fout,"~%") end @Operation writeHTMLChecks(out:OutputChannel,withLinks:Boolean) // If I am an internal node then write links to the children // and write out the children. Otherwise write out the object // and the check that was performed... // Start report node table format(out,"~%"); format(out,"~%",Seq{self.satisfiedHTMLColour()}); format(out,"~%~%",Seq{self.nodeText().asHTML()}); if constraint <> null then self.writeHTMLReport(out) else self.writeHTMLChildSummary(out,withLinks) end; format(out,"
~%"); format(out,"",Seq{self.getLink()}); format(out,"~S


~%"); // Finish report node table. Write out tables for child nodes... @For child in children do child.writeHTMLChecks(out,withLinks) end end @Operation writeHTMLReport(out:OutputChannel):Element format(out,"~%"); format(out,"~%"); format(out,"Candidate ~S~%~%",Seq{candidate.toString().asHTML()}); @For slot in candidate.getStructuralFeatureNames()->asSeq do format(out,"~S~S~%",Seq{slot,candidate.get(slot).toString().asHTML()}) end; format(out,"~%"); format(out,"~%"); format(out,"Invariant
~S
~%~%",Seq{constraint.body.source().asHTML()}); if not satisfied then format(out,"~%"); format(out,"~%"); format(out,"Failure Reason
~S
~%~%",Seq{reason.asHTML()}) end end @Operation writeHTMLChildSummary(out:OutputChannel,withLinks:Boolean):Element format(out,"~%"); format(out,"~%"); format(out,"Dependent checks~%~%",Seq{}); @For child in children do let nodeText = child.nodeText() then unlinkedNodeText = nodeText.asHTML(); nodeLink = "#"+child.getLink() then linkedNodeText = "" + unlinkedNodeText + "" then actualNodeText = if withLinks then linkedNodeText else unlinkedNodeText end; satisfiedText = if child.satisfied then "successful" else "failed" end in format(out,"~S~S~%",Seq{actualNodeText,child.satisfiedHTMLColour(),satisfiedText.asHTML()}) end end end end