First stage cleanup of YAML dungeon generator. Less hard-coded stuff.

Next stage will be rewrite so report object contains all of the keys
and coverage values, so we're not scribbling over DB all the time, and
we don't have to walk over things multiple times, and can keep HTML
generation in one place
This commit is contained in:
Aaron Traas 2017-07-15 13:10:39 -04:00
parent fefc1ff486
commit fb86d64b20
2 changed files with 183 additions and 296 deletions

View file

@ -21,202 +21,62 @@
}} }}
</style> </style>
</head> </head>
<body> <body>
<table width="100%" border=0 cellspacing=0 cellpadding=0> <table width="100%" border=0 cellspacing=0 cellpadding=0>
<tr><td class="title">adventure.yaml Coverage report</td></tr>
<tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr>
<tr> <tr>
<td width="100%"> <td class="title" colspan="2">adventure.yaml Coverage report</td>
<table cellpadding=1 border=0 width="100%">
<tr>
<td width="10%"></td>
<td width="35%"></td>
<td width="20%"></td>
<td width="5%"></td>
<td width="10%" class="headerCovTableHead">Total</td>
<td width="10%" class="headerCovTableHead">Covered</td>
<td width="10%" class="headerCovTableHead">% Coverage</td>
</tr> </tr>
<tr> <tr>
<td class="headerItem">Test:</a></td> <td class="ruler" colspan="2"><img src="glass.png" width=3 height=3 alt=""></td>
<td class="headerValue">adventure.yaml</td> </tr>
<td></td> <tr valign="top">
<td class="headerItem"><a href="#locations">Locations:</a></td> <td>
<td class="headerCovTableEntry">{}</td> <table cellpadding=1 border=0 width="100%">
<td class="headerCovTableEntry">{}</td> <tr>
<td class="headerCovTableEntry">{}%</td> <td width="10%" class="headerItem">Test:</a></td>
<td width="35%" class="headerValue">adventure.yaml</td>
<td width="65%"></td>
</tr> </tr>
<tr> <tr>
<td class="headerItem">Date:</a></td> <td class="headerItem">Date:</a></td>
<td class="headerValue">2017-07-07 21:47:56</td> <td class="headerValue">2017-07-07 21:47:56</td>
<td></td> <td></td>
<td class="headerItem"><a href="#arbitrary_messages">Arbitrary Messages:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr> </tr>
</table>
</td>
<td>
<table cellpadding=1 border=0 width="100%">
<tr> <tr>
<td></td> <td width="55%"></td>
<td></td> <td width="15%" class="headerCovTableHead">Total</td>
<td></td> <td width="15%" class="headerCovTableHead">Covered</td>
<td class="headerItem"><a href="#objects">Objects:</a></td> <td width="15%" class="headerCovTableHead">% Coverage</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr> </tr>
<tr> {summary}
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#hints">Hints:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#classes">Classes:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#turn_thresholds">Turn threshold:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#obituaries">Obituaries:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#actions">Actions:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="headerItem"><a href="#specials">Specials:</a></td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}</td>
<td class="headerCovTableEntry">{}%</td>
</tr>
<tr><td><img src="glass.png" width=3 height=3 alt=""></td></tr>
</table> </table>
</td> </td>
</tr> </tr>
<tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr> <tr>
<td><img src="glass.png" width=3 height=3 alt=""></td>
</tr>
<tr>
<td class="ruler" colspan="2"><img src="glass.png" width=3 height=3 alt=""></td>
</tr>
</table> </table>
<br> <br>
<center> <center>
<table id="locations" width="60%" cellpadding=1 cellspacing=1 border=0> <table width="60%" border=0 cellpadding=1 cellspacing=1>
<tr> {categories}
<td class="tableHead">Location</td>
<td class="tableHead">long</td>
<td class="tableHead">short</td>
</tr>
{}
</table> </table>
<br>
<table id="arbitrary_messages" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Arbitrary Message</td>
<td class="tableHead">Covered?</td>
</tr>
{}
</table>
<br>
<table id="objects" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Objects</td>
<td class="tableHead">Covered?</td>
</tr>
{}
</table>
<br>
<table id="hints" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Hint Name</td>
<td class="tableHead">Question</td>
<td class="tableHead">Hint</td>
</tr>
{}
</table>
<br>
<table id="classes" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Class threshold</td>
<td class="tableHead">Message</td>
</tr>
{}
</table>
<br>
<table id="turn_thresholds" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Turn threshold</td>
<td class="tableHead">Message</td>
</tr>
{}
</table>
<br>
<table id="obituaries" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Obituary</td>
<td class="tableHead">Query</td>
<td class="tableHead">Yes Response</td>
</tr>
{}
</table>
<br>
<table id="actions" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Action ID</td>
<td class="tableHead">Message</td>
</tr>
{}
</table>
<br>
<table id="specials" width="60%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td class="tableHead">Special ID</td>
<td class="tableHead">Message</td>
</tr>
{}
</table>
</center> </center>
<br> <br>
<table width="100%" border=0 cellspacing=0 cellpadding=0> <table width="100%" border=0 cellspacing=0 cellpadding=0>
<tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr> <tr>
<tr><td class="versionInfo">Generated by: <a href="https://gitlab.com/esr/open-adventure/blob/master/tests/coverage_dungeon.py">Open Adventure Dungeon Coverage Generator</a></td></tr> <td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td>
</tr>
<tr>
<td class="versionInfo">Generated by: <a href="https://gitlab.com/esr/open-adventure/blob/master/tests/coverage_dungeon.py">Open Adventure Dungeon Coverage Generator</a></td>
</tr>
</table> </table>
<br> <br>
</body> </body>

View file

@ -12,12 +12,46 @@ import sys
import yaml import yaml
import re import re
test_dir = "." TEST_DIR = "."
yaml_name = "../adventure.yaml" YAML_PATH = "../adventure.yaml"
html_template_path = "coverage_dungeon.html.tpl" HTML_TEMPLATE_PATH = "coverage_dungeon.html.tpl"
html_output_path = "../coverage/adventure.yaml.html" DEFAULT_HTML_OUTPUT_PATH = "../coverage/adventure.yaml.html"
row_3_fields = """ STDOUT_REPORT_CATEGORY = " {name:.<19}: {percent}% covered ({covered} of {total}))\n"
HTML_SUMMARY_ROW = """
<tr>
<td class="headerItem"><a href="#{name}">{name}:</a></td>
<td class="headerCovTableEntry">{total}</td>
<td class="headerCovTableEntry">{covered}</td>
<td class="headerCovTableEntry">{percent}%</td>
</tr>
"""
HTML_CATEGORY_TABLE = """
<tr id="{id}"></tr>
{rows}
<tr>
<td>&nbsp;</td>
</tr>
"""
HTML_CATEGORY_TABLE_HEADER_3_FIELDS = """
<tr>
<td class="tableHead" width="60%">{}</td>
<td class="tableHead" width="20%">{}</td>
<td class="tableHead" width="20%">{}</td>
</tr>
"""
HTML_CATEGORY_TABLE_HEADER_2_FIELDS = """
<tr>
<td class="tableHead" colspan="2">{}</td>
<td class="tableHead">{}</td>
</tr>
"""
HTML_CATEGORY_ROW_3_FIELDS = """
<tr> <tr>
<td class="coverFile">{}</td> <td class="coverFile">{}</td>
<td class="{}">&nbsp;</td> <td class="{}">&nbsp;</td>
@ -25,9 +59,9 @@ row_3_fields = """
</tr> </tr>
""" """
row_2_fields = """ HTML_CATEGORY_ROW_2_FIELDS = """
<tr> <tr>
<td class="coverFile">{}</td> <td class="coverFile" colspan="2">{}</td>
<td class="{}">&nbsp;</td> <td class="{}">&nbsp;</td>
</tr> </tr>
""" """
@ -88,13 +122,13 @@ def obj_coverage(objects, text):
def hint_coverage(hints, text): def hint_coverage(hints, text):
# hints have a "question" where the hint is offered, followed # hints have a "question" where the hint is offered, followed
# by the actual hint if the player requests it # by the actual hint if the player requests it
for name, hint in hints: for i, hint in enumerate(hints):
if hint["question"] != True: if hint["hint"]["question"] != True:
if search(hint["question"], text): if search(hint["hint"]["question"], text):
hint["question"] = True hint["hint"]["question"] = True
if hint["hint"] != True: if hint["hint"]["hint"] != True:
if search(hint["hint"], text): if search(hint["hint"]["hint"], text):
hint["hint"] = True hint["hint"]["hint"] = True
def obit_coverage(obituaries, text): def obit_coverage(obituaries, text):
# obituaries have a "query" where it asks the player for a resurrection, # obituaries have a "query" where it asks the player for a resurrection,
@ -127,29 +161,34 @@ def specials_actions_coverage(items, text):
item["message"] = True item["message"] = True
if __name__ == "__main__": if __name__ == "__main__":
with open(yaml_name, "r") as f: with open(YAML_PATH, "r") as f:
db = yaml.load(f) db = yaml.load(f)
with open(html_template_path, "r") as f: # Create report for each catagory, including HTML table, total items,
html_template = f.read() # and number of items covered
report = {}
for name in db.keys():
# initialize each catagory
report[name] = {
"name" : name, # convenience for string formatting
"html" : "",
"total" : 0,
"covered" : 0
}
motions = db["motions"] motions = db["motions"]
locations = db["locations"] locations = db["locations"]
arb_msgs = db["arbitrary_messages"] arb_msgs = db["arbitrary_messages"]
objects = db["objects"] objects = db["objects"]
hintsraw = db["hints"] hints = db["hints"]
classes = db["classes"] classes = db["classes"]
turn_thresholds = db["turn_thresholds"] turn_thresholds = db["turn_thresholds"]
obituaries = db["obituaries"] obituaries = db["obituaries"]
actions = db["actions"] actions = db["actions"]
specials = db["specials"] specials = db["specials"]
hints = []
for hint in hintsraw:
hints.append((hint["hint"]["name"], {"question" : hint["hint"]["question"],"hint" : hint["hint"]["hint"]}))
text = "" text = ""
for filename in os.listdir(test_dir): for filename in os.listdir(TEST_DIR):
if filename.endswith(".chk"): if filename.endswith(".chk"):
with open(filename, "r") as chk: with open(filename, "r") as chk:
text = chk.read() text = chk.read()
@ -163,9 +202,8 @@ if __name__ == "__main__":
specials_actions_coverage(actions, text) specials_actions_coverage(actions, text)
specials_actions_coverage(specials, text) specials_actions_coverage(specials, text)
location_html = "" report["locations"]["total"] = len(locations) * 2
location_total = len(locations) * 2 report["locations"]["html"] = HTML_CATEGORY_TABLE_HEADER_3_FIELDS.format("Location ID", "long", "short")
location_covered = 0
locations.sort() locations.sort()
for locouter in locations: for locouter in locations:
locname = locouter[0] locname = locouter[0]
@ -174,157 +212,146 @@ if __name__ == "__main__":
long_success = "uncovered" long_success = "uncovered"
else: else:
long_success = "covered" long_success = "covered"
location_covered += 1 report["locations"]["covered"] += 1
if loc["description"]["short"] != True: if loc["description"]["short"] != True:
short_success = "uncovered" short_success = "uncovered"
else: else:
short_success = "covered" short_success = "covered"
location_covered += 1 report["locations"]["covered"] += 1
location_html += row_3_fields.format(locname, long_success, short_success) report["locations"]["html"] += HTML_CATEGORY_ROW_3_FIELDS.format(locname, long_success, short_success)
location_percent = round((location_covered / float(location_total)) * 100, 1)
arb_msgs.sort() arb_msgs.sort()
arb_msg_html = "" report["arbitrary_messages"]["total"] = len(arb_msgs)
arb_total = len(arb_msgs) report["arbitrary_messages"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Arbitrary Message ID", "covered")
arb_covered = 0
for name, msg in arb_msgs: for name, msg in arb_msgs:
if msg != True: if msg != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
arb_covered += 1 report["arbitrary_messages"]["covered"] += 1
arb_msg_html += row_2_fields.format(name, success) report["arbitrary_messages"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format(name, success)
arb_percent = round((arb_covered / float(arb_total)) * 100, 1)
object_html = ""
objects_total = 0
objects_covered = 0
objects.sort() objects.sort()
report["objects"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Object ID", "covered")
for (obj_name, obj) in objects: for (obj_name, obj) in objects:
if obj["descriptions"]: if obj["descriptions"]:
for j, desc in enumerate(obj["descriptions"]): for j, desc in enumerate(obj["descriptions"]):
objects_total += 1 report["objects"]["total"] += 1
if desc != True: if desc != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
objects_covered += 1 report["objects"]["covered"] += 1
object_html += row_2_fields.format("%s[%d]" % (obj_name, j), success) report["objects"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format("%s[%d]" % (obj_name, j), success)
objects_percent = round((objects_covered / float(objects_total)) * 100, 1)
hints.sort() hints.sort()
hints_html = ""; report["hints"]["total"] = len(hints) * 2
hints_total = len(hints) * 2 report["hints"]["html"] = HTML_CATEGORY_TABLE_HEADER_3_FIELDS.format("Hint ID", "question", "hint")
hints_covered = 0 for i, hint in enumerate(hints):
for name, hint in hints: hintname = hint["hint"]["name"]
if hint["question"] != True: if hint["hint"]["question"] != True:
question_success = "uncovered" question_success = "uncovered"
else: else:
question_success = "covered" question_success = "covered"
hints_covered += 1 report["hints"]["covered"] += 1
if hint["hint"] != True: if hint["hint"]["hint"] != True:
hint_success = "uncovered" hint_success = "uncovered"
else: else:
hint_success = "covered" hint_success = "covered"
hints_covered += 1 report["hints"]["covered"] += 1
hints_html += row_3_fields.format(name, question_success, hint_success) report["hints"]["html"] += HTML_CATEGORY_ROW_3_FIELDS.format(name, question_success, hint_success)
hints_percent = round((hints_covered / float(hints_total)) * 100, 1)
class_html = "" report["classes"]["total"] = len(classes)
class_total = len(classes) report["classes"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Adventurer Class #", "covered")
class_covered = 0
for name, msg in enumerate(classes): for name, msg in enumerate(classes):
if msg["message"] != True: if msg["message"] != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
class_covered += 1 report["classes"]["covered"] += 1
class_html += row_2_fields.format(msg["threshold"], success) report["classes"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format(msg["threshold"], success)
class_percent = round((class_covered / float(class_total)) * 100, 1)
turn_html = "" report["turn_thresholds"]["total"] = len(turn_thresholds)
turn_total = len(turn_thresholds) report["turn_thresholds"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Turn Threshold", "covered")
turn_covered = 0
for name, msg in enumerate(turn_thresholds): for name, msg in enumerate(turn_thresholds):
if msg["message"] != True: if msg["message"] != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
turn_covered += 1 report["turn_thresholds"]["covered"] += 1
turn_html += row_2_fields.format(msg["threshold"], success) report["turn_thresholds"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format(msg["threshold"], success)
turn_percent = round((turn_covered / float(turn_total)) * 100, 1)
obituaries_html = ""; report["obituaries"]["total"] = len(obituaries) * 2
obituaries_total = len(obituaries) * 2 report["obituaries"]["html"] = HTML_CATEGORY_TABLE_HEADER_3_FIELDS.format("Obituary #", "query", "yes_response")
obituaries_covered = 0
for i, obit in enumerate(obituaries): for i, obit in enumerate(obituaries):
if obit["query"] != True: if obit["query"] != True:
query_success = "uncovered" query_success = "uncovered"
else: else:
query_success = "covered" query_success = "covered"
obituaries_covered += 1 report["obituaries"]["covered"] += 1
if obit["yes_response"] != True: if obit["yes_response"] != True:
obit_success = "uncovered" obit_success = "uncovered"
else: else:
obit_success = "covered" obit_success = "covered"
obituaries_covered += 1 report["obituaries"]["covered"] += 1
obituaries_html += row_3_fields.format(i, query_success, obit_success) report["obituaries"]["html"] += HTML_CATEGORY_ROW_3_FIELDS.format(i, query_success, obit_success)
obituaries_percent = round((obituaries_covered / float(obituaries_total)) * 100, 1)
actions.sort() actions.sort()
actions_html = ""; report["actions"]["total"] = len(actions)
actions_total = len(actions) report["actions"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Action ID", "covered")
actions_covered = 0
for name, action in actions: for name, action in actions:
if action["message"] != True: if action["message"] != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
actions_covered += 1 report["actions"]["covered"] += 1
actions_html += row_2_fields.format(name, success) report["actions"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format(name, success)
actions_percent = round((actions_covered / float(actions_total)) * 100, 1)
special_html = "" report["specials"]["total"] = len(specials)
special_total = len(specials) report["specials"]["html"] = HTML_CATEGORY_TABLE_HEADER_2_FIELDS.format("Special ID", "covered")
special_covered = 0
for name, special in specials: for name, special in specials:
if special["message"] != True: if special["message"] != True:
success = "uncovered" success = "uncovered"
else: else:
success = "covered" success = "covered"
special_covered += 1 report["specials"]["covered"] += 1
special_html += row_2_fields.format(name, success) report["specials"]["html"] += HTML_CATEGORY_ROW_2_FIELDS.format(name, success)
special_percent = round((special_covered / float(special_total)) * 100, 1)
# calculate percentages for each catagory and HTML for category tables
categories_html = ""
summary_html = ""
summary_stdout = "adventure.yaml coverage rate:\n"
for name, category in sorted(report.items()):
if(category["total"] > 0):
report[name]["percent"] = round((category["covered"] / float(category["total"])) * 100, 1)
summary_stdout += STDOUT_REPORT_CATEGORY.format(**report[name])
categories_html += HTML_CATEGORY_TABLE.format(id=name, rows=category["html"])
summary_html += HTML_SUMMARY_ROW.format(**report[name])
else:
report[name]["percent"] = 100;
# output some quick report stats # output some quick report stats
print("\nadventure.yaml coverage rate:") print(summary_stdout)
print(" locations..........: {}% covered ({} of {})".format(location_percent, location_covered, location_total))
print(" arbitrary_messages.: {}% covered ({} of {})".format(arb_percent, arb_covered, arb_total))
print(" objects............: {}% covered ({} of {})".format(objects_percent, objects_covered, objects_total))
print(" hints..............: {}% covered ({} of {})".format(hints_percent, hints_covered, hints_total))
print(" classes............: {}% covered ({} of {})".format(class_percent, class_covered, class_total))
print(" turn_thresholds....: {}% covered ({} of {})".format(turn_percent, turn_covered, turn_total))
print(" obituaries.........: {}% covered ({} of {})".format(obituaries_percent, obituaries_covered, obituaries_total))
print(" actions............: {}% covered ({} of {})".format(actions_percent, actions_covered, actions_total))
print(" specials...........: {}% covered ({} of {})".format(special_percent, special_covered, special_total))
if len(sys.argv) > 1: if len(sys.argv) > 1:
html_output_path = sys.argv[1] html_output_path = sys.argv[1]
else:
html_output_path = DEFAULT_HTML_OUTPUT_PATH
# render HTML report # render HTML report
try:
with open(HTML_TEMPLATE_PATH, "r") as f:
# read in HTML template
html_template = f.read()
except IOError as e:
print 'ERROR: reading HTML report template failed (%s)' % e.strerror
exit(-1)
# parse template with report and write it out
try:
with open(html_output_path, "w") as f: with open(html_output_path, "w") as f:
f.write(html_template.format( f.write(html_template.format(categories=categories_html, summary=summary_html))
location_total, location_covered, location_percent, except IOError as e:
arb_total, arb_covered, arb_percent, print 'ERROR: writing HTML report failed (%s)' % e.strerror
objects_total, objects_covered, objects_percent,
hints_total, hints_covered, hints_percent,
class_total, class_covered, class_percent,
turn_total, turn_covered, turn_percent,
obituaries_total, obituaries_covered, obituaries_percent,
actions_total, actions_covered, actions_percent,
special_total, special_covered, special_percent,
location_html, arb_msg_html, object_html, hints_html,
class_html, turn_html, obituaries_html, actions_html, special_html
))