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,"~%");
format(out,"",Seq{self.getLink()});
format(out,"~S | ~%
~%",Seq{self.nodeText().asHTML()});
if constraint <> null
then
self.writeHTMLReport(out)
else
self.writeHTMLChildSummary(out,withLinks)
end;
format(out,"
~%");
// 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