Skip to content

Commit

Permalink
report generator (#12)
Browse files Browse the repository at this point in the history
* feat: path issue when loading Jinja template

* fix: modify to package loader

* feat: Update Jinja template loading to use package loader

* update tempalte dir

* fix package

* feat: add __init__.py for templates

* fix directory

* feat: add default templates
  • Loading branch information
jungs1 authored Jul 29, 2024
1 parent 541d29f commit cf3300a
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 9 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ vendor
*.lcov
dist*

*.html
*.log
logs/*
*.db
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include src/mutahunter/core/queries/*.scm
include src/mutahunter/core/html/*.html
include src/mutahunter/core/templates/*.html
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ authors = [{ name = "Steven Jung" }]
maintainers = [{ name = "Steven Jung" }]

[project.urls]
Homepage = "https://www.mutahunter.ai"
Homepage = "https://mutahunter.ai"
Repository = "https://github.com/codeintegrity-ai/mutahunter"

[project.optional-dependencies]
Expand All @@ -39,5 +39,5 @@ mutahunter = "mutahunter.main:run"
[tool.setuptools.package-data]
mutahunter = [
'src/mutahunter/core/queries/*.scm',
'src/mutahunter/core/html/*.html',
'src/mutahunter/core/templates/*.html',
]
16 changes: 11 additions & 5 deletions src/mutahunter/core/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import os
from typing import Any, Dict, List

from jinja2 import Environment, FileSystemLoader
from jinja2 import (
Environment,
PackageLoader,
FileSystemLoader,
select_autoescape,
)
from importlib import resources

from mutahunter.core.db import MutationDatabase
from mutahunter.core.logger import logger

Expand All @@ -24,10 +28,12 @@ class MutantReport:
def __init__(self, db: MutationDatabase) -> None:
self.log_file = "logs/_latest/coverage.txt"
self.db = db
module_dir = os.path.dirname(__file__)
templates_dir = os.path.join(module_dir, "html")
self.template_env = Environment(loader=FileSystemLoader(templates_dir))
os.makedirs("logs/_latest/html", exist_ok=True)
self.template_env = Environment(
loader=FileSystemLoader(resources.files(__package__).joinpath("templates"))
)
assert self.template_env.get_template("report_template.html")
assert self.template_env.get_template("file_detail_template.html")

def generate_report(self, total_cost: float, line_rate: float) -> None:
"""
Expand Down
Empty file.
134 changes: 134 additions & 0 deletions src/mutahunter/core/templates/file_detail_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ file_name }} - MutaHunter Report</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
padding: 20px;
color: #333;
background: #f0f0f0;
}
h1 {
color: #333;
}
.source-code {
font-family: 'Courier New', monospace;
background-color: #fff;
padding: 10px;
border-radius: 5px;
box-shadow: 0 2px 15px rgba(0,0,0,0.1);
}
.line {
display: flex;
align-items: flex-start;
padding: 4px 2px;
position: relative;
}
.line-number, .mutation-links {
width: 50px;
flex-shrink: 0;
text-align: right;
padding-right: 10px;
color: #666;
font-size: 14px;
}
.mutation-links {
flex-shrink: 0;
padding-left: 5px;
text-align: left;
}
.mutation-link {
color: #2196F3;
font-weight: bold;
margin-right: 10px;
}
.code {
flex: 1;
white-space: pre-wrap; /* respects indentation inside code */
}
.survived {
background-color: #ffcccb;
}
.killed {
background-color: #90ee90;
}
.mutation-details {
background-color: #fff;
padding: 15px;
margin-top: 20px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 15px rgba(0,0,0,0.1);
}
.mutation-details ol {
list-style-type: none;
padding: 0;
margin-left: 0;
}
.mutation-details li {
margin: 10px 0;
}
.footer {
margin-top: 30px;
text-align: center;
}
.footer a {
text-decoration: none;
background-color: #2196F3;
color: white;
padding: 10px 15px;
border-radius: 5px;
}
code {
background-color: #f4f4f4;
border-radius: 5px;
padding: 2px 6px;
font-size: 90%;
}
</style>
</head>
<body>
<h1>{{ file_name }}</h1>
<div class="source-code">
{% for line in source_lines %}
<div class="line {% if line.mutations %}{{ 'survived' if line.mutations[0].status == 'SURVIVED' else 'killed' }}{% endif %}">
<span class="line-number">{{ loop.index }}</span>
<span class="mutation-links">
{% for mutation in line.mutations %}
<a href="#mutation-details-{{ mutation.id }}" class="mutation-link">M{{ mutation.id }}</a>
{% endfor %}
</span>
<span class="code">{{ line.code | e }}</span>
</div>
{% endfor %}
</div>
<div class="mutation-details" id="mutation-details">
<h2>Mutation Details</h2>
<ol>
{% for line in source_lines %}
{% for mutation in line.mutations %}
<li id="mutation-details-{{ mutation.id }}" class="{{ 'survived' if mutation.status == 'SURVIVED' else 'killed' }}">
<strong>M{{ mutation.id }}</strong>:
<ul>
<li><strong>Type:</strong> <span class="mutation-type">{{ mutation.type }}</span></li>
<li><strong>Modification:</strong> Changed <code>{{ mutation.original_code }}</code> to <code>{{ mutation.mutated_code }}</code></li>
<li><strong>Status:</strong> {{ 'Survived' if mutation.status == 'SURVIVED' else 'Killed' }}</li>
<li><strong>Impact:</strong> {{ mutation.description }}</li>
{% if mutation.error_msg %}
<!-- <li><strong>Error:</strong> {{mutation.error_msg}} </li>
{% endif %} -->
</ul>
</li>
{% endfor %}
{% endfor %}
</ol>
</div>
<div class="footer">
<a href="mutation_report.html">Back to Summary</a>
</div>
</body>
</html>
101 changes: 101 additions & 0 deletions src/mutahunter/core/templates/report_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mutahunter Report</title>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; }
h1 { color: #333; }
.summary, .file-list { margin-bottom: 30px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.progress-bar { background-color: #e0e0e0; height: 20px; border-radius: 10px; }
.progress-bar-fill { height: 100%; border-radius: 10px; }
.summary {
background: #fff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 16px rgba(0,0,0,0.1);
margin-top: 20px;
}

.summary h2 {
color: #333;
margin-bottom: 20px;
}

.metrics > div {
margin-bottom: 10px;
display: flex;
align-items: center;
}

.metrics label {
flex: 1;
font-weight: bold;
}

.progress-bar {
flex: 2;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
overflow: hidden;
margin: 10px 10px;
}

.progress-bar-fill {
height: 100%;
border-radius: 10px;
transition: width 0.3s ease-in-out;
}

.metrics span {
min-width: 50px;
text-align: right;
}
</style>
</head>
<body>
<h1>Mutahunter Mutation Testing Report</h1>
<div class="summary">
<h2>Overall Summary</h2>
<p>Line Coverage: {{ line_coverage }}%</p>
<div class="progress-bar">
<div class="progress-bar-fill" style="width: {{ line_coverage }}
%; background-color: #2196F3;"></div>
</div>
<p>Mutation Coverage: {{ mutation_coverage }}%</p>
<div class="progress-bar">
<div class="progress-bar-fill" style="width: {{ mutation_coverage }}%; background-color: #2196F3;"></div>
</div>
<div><label>Total Mutants:</label> {{ total_mutants }}</div>
<div><label>Killed Mutants:</label> {{ killed_mutants }}</div>
<div><label>Survived Mutants:</label> {{ survived_mutants }}</div>
<div><label>Timeout Mutants:</label> {{ timeout_mutants }}</div>
<div><label>Compile Error Mutants:</label> {{ compile_error_mutants }}</div>
<div><label>Total Cost:</label> ${{ total_cost }} USD</div>
</div>
<div class="file-list">
<h2>File List</h2>
<table>
<tr>
<th>File Name</th>
<th>Mutants</th>
<th>Mutation Coverage</th>
<th>Survived Mutants</th>
</tr>
{% for file in file_data %}
<tr>
<td><a href="{{ file.id }}.html">{{ file.name }}</a></td>
<td>{{ file.totalMutants }}</td>
<td>{{ file.mutationCoverage }}%</td>
<td>{{ file.survivedMutants }}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>

0 comments on commit cf3300a

Please sign in to comment.