3 # This is the open-adventure dungeon text coverage report generator. It
4 # consumes a YAML description of the dungeon and determines whether the
5 # various strings contained are present within the test check files.
7 # Currently, only the location descriptions, arbitrary messages, object
8 # descriptions, hints, classes and turn thrusholds are supported. This will
9 # be expanded in the future.
16 yaml_name = "../adventure.yaml"
17 html_template_path = "coverage_dungeon.html.tpl"
18 html_output_path = "../coverage/adventure.yaml.html"
22 <td class="coverFile">{}</td>
23 <td class="{}"> </td>
24 <td class="{}"> </td>
30 <td class="coverFile">{}</td>
31 <td class="{}"> </td>
37 <td class="coverFile">{}</td>
38 <td class="{}"> </td>
42 def search(needle, haystack):
43 # Search for needle in haystack, first escaping needle for regex, then
44 # replacing %s, %d, etc. with regex wildcards, so the variable messages
45 # within the dungeon definition will actually match
46 needle = re.escape(needle) \
47 .replace("\\n", "\n") \
48 .replace("\\t", "\t") \
49 .replace("\%S", ".*") \
50 .replace("\%s", ".*") \
51 .replace("\%d", ".*") \
54 return re.search(needle, haystack)
56 def loc_coverage(locations, text):
57 for locname, loc in locations:
58 if loc["description"]["long"] == None or loc["description"]["long"] == '':
59 loc["description"]["long"] = True
60 if loc["description"]["long"] != True:
61 if search(loc["description"]["long"], text):
62 loc["description"]["long"] = True
63 if loc["description"]["short"] == None or loc["description"]["short"] == '':
64 loc["description"]["short"] = True
65 if loc["description"]["short"] != True:
66 if search(loc["description"]["short"], text):
67 loc["description"]["short"] = True
69 def arb_coverage(arb_msgs, text):
70 for i, msg in enumerate(arb_msgs):
71 (msg_name, msg_text) = msg
72 if msg_text == None or msg_text == '':
73 arb_msgs[i] = (msg_name, True)
74 elif msg_text != True:
75 if search(msg_text, text):
76 arb_msgs[i] = (msg_name, True)
78 def obj_coverage(objects, text):
79 for i, objouter in enumerate(objects):
80 (obj_name, obj) = objouter
81 if obj["descriptions"]:
82 for j, desc in enumerate(obj["descriptions"]):
83 if desc == None or desc == '':
84 obj["descriptions"][j] = True
85 objects[i] = (obj_name, obj)
87 if search(desc, text):
88 obj["descriptions"][j] = True
89 objects[i] = (obj_name, obj)
91 def hint_coverage(hints, text):
92 for name, hint in hints:
93 if hint["question"] != True:
94 if search(hint["question"], text):
95 hint["question"] = True
96 if hint["hint"] != True:
97 if search(hint["hint"], text):
100 def special_coverage(specials, text):
101 for name, special in specials:
102 if special["message"] == None:
103 special["message"] = True
104 if special["message"] != True:
105 if search(special["message"], text):
106 special["message"] = True
108 def threshold_coverage(classes, text):
109 for i, msg in enumerate(classes):
110 if msg["message"] == None:
111 msg["message"] = True
112 elif msg["message"] != True:
113 if search(msg["message"], text):
114 msg["message"] = True
116 def obit_coverage(obituaries, text):
117 for i, obit in enumerate(obituaries):
118 if obit["query"] != True:
119 if search(obit["query"], text):
121 if obit["yes_response"] != True:
122 if search(obit["yes_response"], text):
123 obit["yes_response"] = True
125 def actions_coverage(actions, text):
126 for name, action in actions:
127 if action["message"] == None or action["message"] == "NO_MESSAGE":
128 action["message"] = True
129 if action["message"] != True:
130 if search(action["message"], text):
131 action["message"] = True
133 if __name__ == "__main__":
134 with open(yaml_name, "r") as f:
137 with open(html_template_path, "r") as f:
138 html_template = f.read()
140 motions = db["motions"]
141 locations = db["locations"]
142 arb_msgs = db["arbitrary_messages"]
143 objects = db["objects"]
144 hintsraw = db["hints"]
145 classes = db["classes"]
146 turn_thresholds = db["turn_thresholds"]
147 obituaries = db["obituaries"]
148 actions = db["actions"]
149 specials = db["specials"]
152 for hint in hintsraw:
153 hints.append((hint["hint"]["name"], {"question" : hint["hint"]["question"],"hint" : hint["hint"]["hint"]}))
156 for filename in os.listdir(test_dir):
157 if filename.endswith(".chk"):
158 with open(filename, "r") as chk:
160 loc_coverage(locations, text)
161 arb_coverage(arb_msgs, text)
162 obj_coverage(objects, text)
163 hint_coverage(hints, text)
164 threshold_coverage(classes, text)
165 threshold_coverage(turn_thresholds, text)
166 obit_coverage(obituaries, text)
167 actions_coverage(actions, text)
168 special_coverage(specials, text)
171 location_total = len(locations) * 2
174 for locouter in locations:
175 locname = locouter[0]
177 if loc["description"]["long"] != True:
178 long_success = "uncovered"
180 long_success = "covered"
181 location_covered += 1
183 if loc["description"]["short"] != True:
184 short_success = "uncovered"
186 short_success = "covered"
187 location_covered += 1
189 location_html += location_row.format(locname, long_success, short_success)
190 location_percent = round((location_covered / float(location_total)) * 100, 1)
194 arb_total = len(arb_msgs)
196 for name, msg in arb_msgs:
198 success = "uncovered"
202 arb_msg_html += arb_msg_row.format(name, success)
203 arb_percent = round((arb_covered / float(arb_total)) * 100, 1)
209 for (obj_name, obj) in objects:
210 if obj["descriptions"]:
211 for j, desc in enumerate(obj["descriptions"]):
214 success = "uncovered"
218 object_html += object_row.format("%s[%d]" % (obj_name, j), success)
219 objects_percent = round((objects_covered / float(objects_total)) * 100, 1)
223 hints_total = len(hints) * 2
225 for name, hint in hints:
226 if hint["question"] != True:
227 question_success = "uncovered"
229 question_success = "covered"
231 if hint["hint"] != True:
232 hint_success = "uncovered"
234 hint_success = "covered"
236 hints_html += location_row.format(name, question_success, hint_success)
237 hints_percent = round((hints_covered / float(hints_total)) * 100, 1)
240 class_total = len(classes)
242 for name, msg in enumerate(classes):
243 if msg["message"] != True:
244 success = "uncovered"
248 class_html += arb_msg_row.format(msg["threshold"], success)
249 class_percent = round((class_covered / float(class_total)) * 100, 1)
252 turn_total = len(turn_thresholds)
254 for name, msg in enumerate(turn_thresholds):
255 if msg["message"] != True:
256 success = "uncovered"
260 turn_html += arb_msg_row.format(msg["threshold"], success)
261 turn_percent = round((turn_covered / float(turn_total)) * 100, 1)
263 obituaries_html = "";
264 obituaries_total = len(obituaries) * 2
265 obituaries_covered = 0
266 for i, obit in enumerate(obituaries):
267 if obit["query"] != True:
268 query_success = "uncovered"
270 query_success = "covered"
271 obituaries_covered += 1
272 if obit["yes_response"] != True:
273 obit_success = "uncovered"
275 obit_success = "covered"
276 obituaries_covered += 1
277 obituaries_html += location_row.format(i, query_success, obit_success)
278 obituaries_percent = round((obituaries_covered / float(obituaries_total)) * 100, 1)
282 actions_total = len(actions)
284 for name, action in actions:
285 if action["message"] != True:
286 success = "uncovered"
290 actions_html += arb_msg_row.format(name, success)
291 actions_percent = round((actions_covered / float(actions_total)) * 100, 1)
294 special_total = len(specials)
296 for name, special in specials:
297 if special["message"] != True:
298 success = "uncovered"
302 special_html += arb_msg_row.format(name, success)
303 special_percent = round((special_covered / float(special_total)) * 100, 1)
305 # output some quick report stats
306 print("\nadventure.yaml coverage rate:")
307 print(" locations..........: {}% covered ({} of {})".format(location_percent, location_covered, location_total))
308 print(" arbitrary_messages.: {}% covered ({} of {})".format(arb_percent, arb_covered, arb_total))
309 print(" objects............: {}% covered ({} of {})".format(objects_percent, objects_covered, objects_total))
310 print(" hints..............: {}% covered ({} of {})".format(hints_percent, hints_covered, hints_total))
311 print(" classes............: {}% covered ({} of {})".format(class_percent, class_covered, class_total))
312 print(" turn_thresholds....: {}% covered ({} of {})".format(turn_percent, turn_covered, turn_total))
313 print(" obituaries.........: {}% covered ({} of {})".format(obituaries_percent, obituaries_covered, obituaries_total))
314 print(" actions............: {}% covered ({} of {})".format(actions_percent, actions_covered, actions_total))
315 print(" specials...........: {}% covered ({} of {})".format(special_percent, special_covered, special_total))
318 with open(html_output_path, "w") as f:
319 f.write(html_template.format(
320 location_total, location_covered, location_percent,
321 arb_total, arb_covered, arb_percent,
322 objects_total, objects_covered, objects_percent,
323 hints_total, hints_covered, hints_percent,
324 class_total, class_covered, class_percent,
325 turn_total, turn_covered, turn_percent,
326 obituaries_total, obituaries_covered, obituaries_percent,
327 actions_total, actions_covered, actions_percent,
328 special_total, special_covered, special_percent,
329 location_html, arb_msg_html, object_html, hints_html,
330 class_html, turn_html, obituaries_html, actions_html, special_html