Commit Diff


commit - 568de39969dba9780429ff37e612382ec145b9d6
commit + f20ac5dfb78a9af1b0691535ab6e4880c5d7ee4a
blob - 2464e4df4be4115e48c1f1f96155346ee5a64149
blob + 8ad3f666594e3a4d838684db12cd4c2ecbd3d3d6
--- generate.py
+++ generate.py
@@ -7,6 +7,22 @@ import os
 
 from jinja2 import Template
 
+STATUS_KILLED = "Killed"
+STATUS_SURVIVED = "Survived"
+STATUS_NO_COVERAGE = "NoCoverage"
+STATUS_COMPILE_ERROR = "CompileError"
+STATUS_RUNTIME_ERROR = "RuntimeError"
+STATUS_TIMEOUT = "Timeout"
+STATUS_IGNORED = "Ignored"
+
+LIST_STATUSES = [STATUS_KILLED,
+                STATUS_SURVIVED,
+                STATUS_NO_COVERAGE,
+                STATUS_COMPILE_ERROR,
+                STATUS_RUNTIME_ERROR,
+                STATUS_TIMEOUT,
+                STATUS_IGNORED]
+
 SUPPORTED_SCHEMA_VERSIONS = ["1.0"]
 
 DEFAULT_TEXT_TEMPLATE = """
@@ -20,7 +36,7 @@ Mutants:
 {% endfor %}
 {% endfor %}
 
-Schema version: {{ version }}
+Schema version: {{ json_data['schemaVersion'] }}
 Time of generation: {{ current_time.strftime('%d-%m-%Y %H:%M') }}
 """
 
@@ -37,26 +53,26 @@ DEFAULT_HTML_TEMPLATE = """
 <div>
 <div>Mutation states</div>
 <div>
-<div>Killed</div>
+<div>Killed</div> - {{ killed }}
 When at least one test failed while this mutant was active, the mutant is
-killed. This is what you want, good job!
+killed.
 </div>
 
 <div>
-<div>Survived</div>
+<div>Survived</div> - {{ survived }}
 When all tests passed while this mutant was active, the mutant survived. You're
 missing a test for it.
 </div>
 
 <div>
-<div>No coverage</div>
+<div>No coverage</div> - {{ no_coverage }}
 No tests were executed for this mutant. It probably is located in a part of the
 code not hit by any of your tests. This means the mutant survived and you are
 missing a test case for it.
 </div>
 
 <div>
-<div>Timeout</div>
+<div>Timeout</div> - {{ timeout }}
 The running of tests with this mutant active resulted in a timeout. For
 example, the mutant resulted in an infinite loop in your code. Don't spend too
 much attention to this mutant. It is counted as "detected". The logic here is
@@ -65,7 +81,7 @@ detect it because the tests will never complete.
 </div>
 
 <div>
-<div>Runtime error</div>
+<div>Runtime error</div> - {{ runtime_error }}
 The running of the tests resulted in an error (rather than a failed test). This
 can happen when the testrunner fails. For example, when a testrunner throws an
 OutOfMemoryError or for dynamic languages where the mutant resulted in
@@ -74,14 +90,14 @@ not represented in your mutation score.
 </div>
 
 <div>
-<div>Compile error</div>
+<div>Compile error</div> - {{ compile_error }}
 The mutant resulted in a compiler error. This can happen in compiled languages.
 Don't spend too much attention looking at this mutant. It is not represented in
 your mutation score.
 </div>
 
 <div>
-<div>Ignored</div>
+<div>Ignored</div> - {{ ignored }}
 The mutant was not tested because the config of the user asked for it to be
 ignored. This will not count against your mutation score but will show up in
 reports.
@@ -120,7 +136,7 @@ percentage of mutants that were killed based on the co
 {% endfor %}
 {% endfor %}
 
-<p>Schema version: {{ version }}</p>
+Schema version: {{ json_data['schemaVersion'] }}
 <p>Time of generation: {{ current_time.strftime('%d-%m-%Y %H:%M') }}</p>
 </body>
 </html>
@@ -143,12 +159,85 @@ def print_stdout(json_data):
 
 
 def render_template(json_data, template):
+	files_mutant_statuses = []
+	for file_name, properties in json_data.get("files", None).items():
+		files_mutant_statuses.append({file_name: file_mutant_statuses(properties)})
+	report_mutant_statuses = sum_statuses(files_mutant_statuses)
+
 	t = Template(template)
 	time = datetime.datetime.now()
-	schema_version = json_data.get("schemaVersion", None)
 
-	return t.render(json_data=json_data, version=schema_version, current_time=time)
+	return t.render(json_data=json_data,
+                    killed=report_mutant_statuses[STATUS_KILLED],
+                    survived=report_mutant_statuses[STATUS_SURVIVED],
+                    no_coverage=report_mutant_statuses[STATUS_NO_COVERAGE],
+                    compile_error=report_mutant_statuses[STATUS_COMPILE_ERROR],
+                    runtime_error=report_mutant_statuses[STATUS_RUNTIME_ERROR],
+                    timeout=report_mutant_statuses[STATUS_TIMEOUT],
+                    ignored=report_mutant_statuses[STATUS_IGNORED],
+                    current_time=time)
 
+
+def dict_statuses():
+	statuses = {STATUS_KILLED: 0,
+                STATUS_SURVIVED: 0,
+                STATUS_NO_COVERAGE: 0,
+                STATUS_COMPILE_ERROR: 0,
+                STATUS_RUNTIME_ERROR: 0,
+                STATUS_TIMEOUT: 0,
+                STATUS_IGNORED: 0}
+
+	return statuses
+
+
+def file_mutant_statuses(json_data):
+	"""
+	json_data: a dict that includes dicts "file" described in
+	'mutation-elements' schema.
+
+	returns: statuses, dict with a name of status and
+	a number mutants with that status.
+	"""
+
+	mutants = json_data.get("mutants", None)
+	statuses = dict_statuses()
+	for mutant in mutants:
+		status = mutant.get("status", None)
+		if not status: 
+			raise Exception("status is None")
+
+		if status == STATUS_KILLED:
+			statuses[STATUS_KILLED] += 1
+		elif status == STATUS_SURVIVED:
+			statuses[STATUS_SURVIVED] += 1
+		elif status == STATUS_NO_COVERAGE:
+			statuses[STATUS_NO_COVERAGE] += 1
+		elif status == STATUS_COMPILE_ERROR:
+			statuses[STATUS_COMPILE_ERROR] += 1
+		elif status == STATUS_RUNTIME_ERROR:
+			statuses[STATUS_RUNTIME_ERROR] += 1
+		elif status == STATUS_TIMEOUT:
+			statuses[STATUS_TIMEOUT] += 1
+		elif status == STATUS_IGNORED:
+			statuses[STATUS_IGNORED] += 1
+
+	return statuses
+
+
+def sum_statuses(list_of_statuses_per_file):
+	"""
+	list_of_statuses: list of dicts {file_name: dict with statuses}
+	"""
+	total_num_statuses = dict_statuses()
+	statuses = []
+	for d in list_of_statuses_per_file:
+		statuses += list(d.values())
+	for st in LIST_STATUSES:
+		total_num_statuses[st] = sum(d[st] for d in statuses)
+	
+	return total_num_statuses
+
+
 if __name__ == "__main__":
 	parser = argparse.ArgumentParser()
 	parser.add_argument("--data", dest="data_path", default="",