mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
IfcTester now supports HTML reports
This commit is contained in:
@@ -51,6 +51,8 @@ if args.reporter == "Console":
|
|||||||
engine = reporter.Console(specs, use_colour=not args.no_color)
|
engine = reporter.Console(specs, use_colour=not args.no_color)
|
||||||
elif args.reporter == "Json":
|
elif args.reporter == "Json":
|
||||||
engine = reporter.Json(specs)
|
engine = reporter.Json(specs)
|
||||||
|
elif args.reporter == "Html":
|
||||||
|
engine = reporter.Html(specs)
|
||||||
|
|
||||||
engine.report()
|
engine.report()
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,11 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import math
|
||||||
import logging
|
import logging
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
class Reporter:
|
class Reporter:
|
||||||
def __init__(self, ids):
|
def __init__(self, ids):
|
||||||
@@ -150,11 +153,14 @@ class Json(Reporter):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
total = len(specification.applicable_entities)
|
total = len(specification.applicable_entities)
|
||||||
|
total_successes = total - len(specification.failed_entities)
|
||||||
|
percentage = math.floor((total_successes / total) * 100) if total else "N/A"
|
||||||
return {
|
return {
|
||||||
"name": specification.name,
|
"name": specification.name,
|
||||||
"status": specification.status,
|
"status": specification.status,
|
||||||
"total_successes": total - len(specification.failed_entities),
|
"total_successes": total_successes,
|
||||||
"total": total,
|
"total": total,
|
||||||
|
"percentage": percentage,
|
||||||
"required": specification.minOccurs != 0,
|
"required": specification.minOccurs != 0,
|
||||||
"requirements": requirements,
|
"requirements": requirements,
|
||||||
}
|
}
|
||||||
@@ -171,6 +177,32 @@ class Json(Reporter):
|
|||||||
return json.dump(self.results, outfile)
|
return json.dump(self.results, outfile)
|
||||||
|
|
||||||
|
|
||||||
|
class Html(Json):
|
||||||
|
def __init__(self, ids):
|
||||||
|
super().__init__(ids)
|
||||||
|
self.results = {}
|
||||||
|
|
||||||
|
def report(self):
|
||||||
|
self.results["title"] = self.ids.info.get("title", "Untitled IDS")
|
||||||
|
self.results["time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
self.results["specifications"] = []
|
||||||
|
for specification in self.ids.specifications:
|
||||||
|
self.results["specifications"].append(self.report_specification(specification))
|
||||||
|
return self.results
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
import pystache
|
||||||
|
|
||||||
|
with open(os.path.join(cwd, "templates", "report.html"), "r") as file:
|
||||||
|
return pystache.render(file.read(), self.results)
|
||||||
|
|
||||||
|
def to_file(self, filepath):
|
||||||
|
import pystache
|
||||||
|
|
||||||
|
with open(os.path.join(cwd, "templates", "report.html"), "r") as file:
|
||||||
|
with open(filepath, "w") as outfile:
|
||||||
|
return outfile.write(pystache.render(file.read(), self.results))
|
||||||
|
|
||||||
|
|
||||||
class BcfHandler(logging.StreamHandler):
|
class BcfHandler(logging.StreamHandler):
|
||||||
"""Logging handler for creation of BCF report files.
|
"""Logging handler for creation of BCF report files.
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<!--
|
||||||
|
IfcTester - IDS based model auditing
|
||||||
|
Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
|
||||||
|
This file is part of IfcTester.
|
||||||
|
|
||||||
|
IfcTester is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
IfcTester is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with IfcTester. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang={{_lang}}>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="foobaro">
|
||||||
|
<title>{{name}}</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Comfortaa|Inconsolata|Open+Sans&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Arial', sans-serif; padding: 10px 40px; }
|
||||||
|
span.time { color: #999; font-style: italic; float: right; }
|
||||||
|
span.step-time { float: right; color: #555; font-size: 0.8em; font-style: italic; }
|
||||||
|
span.success { background-color: #97cc64; padding: 5px; border-radius: 5px; color: #FFF; font-weight: bold; }
|
||||||
|
span.failure { background-color: #fb5a3e; padding: 5px; border-radius: 5px; color: #FFF; font-weight: bold; }
|
||||||
|
p.failure { background-color: #fb5a3e; padding: 5px; border-radius: 5px; color: #fff; }
|
||||||
|
p.unspecified { background-color: #994f00; padding: 5px; border-radius: 5px; color: #fff; }
|
||||||
|
p.skipped { background-color: #8b8d8f; padding: 5px; border-radius: 5px; color: #fff; }
|
||||||
|
p.description { background-color: #eee; border-radius: 5px; padding: 20px; margin-left: auto; margin-right: auto; display: inline-block; font-weight: bold;}
|
||||||
|
li { padding: 10px; font-family: monospace; }
|
||||||
|
li.success { background-color: #b6cca1; color: #333; }
|
||||||
|
li.failure { background-color: #fbb4a8; color: #900; }
|
||||||
|
li.unspecified { background-color: #ffd37f; color: #a30; }
|
||||||
|
li.skipped { background-color: #f5f5f5; color: #333; }
|
||||||
|
li p { margin-bottom: 0px; }
|
||||||
|
footer { color: #999; font-size: 0.8em; }
|
||||||
|
header { text-align: center; }
|
||||||
|
hr { margin: 20px; margin-left: 0px; margin-right: 0px; border: none; border-top: 1px solid #ccc; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
<p><strong>{{time}}</strong></p>
|
||||||
|
</header>
|
||||||
|
{{#specifications}}
|
||||||
|
<section>
|
||||||
|
<h2>{{name}}</h2>
|
||||||
|
<p>
|
||||||
|
<span class="{{#status}}success{{/status}}{{^status}}failure{{/status}}">{{#status}}Pass{{/status}}{{^status}}Fail{{/status}}</span>
|
||||||
|
Passed: <strong>{{total_successes}} / {{total}}</strong> ({{percentage}}%)
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
{{#requirements}}
|
||||||
|
<li class="{{#status}}success{{/status}}{{^status}}failure{{/status}}">
|
||||||
|
{{description}}
|
||||||
|
{{^status}}{{#total}}
|
||||||
|
<p class="failure{{#is_unspecified}} unspecified{{/is_unspecified}}{{#is_skipped}} skipped{{/is_skipped}}">
|
||||||
|
{{#failed_entities}}
|
||||||
|
{{reason}} <em style="color: #fbb4a8;">{{element}}</em><br />
|
||||||
|
{{/failed_entities}}
|
||||||
|
</p>
|
||||||
|
{{/total}}{{/status}}
|
||||||
|
</li>
|
||||||
|
{{/requirements}}
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
{{/specifications}}
|
||||||
|
<hr>
|
||||||
|
<footer>
|
||||||
|
<p>
|
||||||
|
Report by <a href="https://blenderbim.org/">BlenderBIM</a> and <a href="http://ifcopenshell.org/">IfcOpenShell</a>.
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user