Skip to content

Commit effff96

Browse files
authored
LLM Surving Mutant Anlaysis (#4)
* feat: add LLM surving mutant anlaysis report * feat: update version
1 parent 7ac6108 commit effff96

File tree

5 files changed

+91
-27
lines changed

5 files changed

+91
-27
lines changed

README.md

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313

1414
## Table of Contents
1515

16-
- [Overview](#overview)
1716
- [Features](#features)
17+
- [Recommended Mutation Testing Process](#recommended-mutation-testing-process)
1818
- [Getting Started](#getting-started)
19+
- [LLM Survivng Mutant Analysis Report](#mutant-report)
20+
- [Examples](#examples)
1921
- [CI/CD Integration](#cicd-integration)
20-
- [Roadmap](#roadmap)
21-
- [Cash Bounty Program](#cash-bounty-program)
22-
23-
## Overview
2422

2523
Mutahunter uses LLM models to inject context-aware faults into your codebase. This AI-driven approach produces fewer equivalent mutants, mutants with higher fault detection potential, and those with higher coupling and semantic similarity to real faults, ensuring comprehensive and effective testing.
2624

@@ -30,12 +28,14 @@ Mutahunter uses LLM models to inject context-aware faults into your codebase. Th
3028
- **LLM Context-aware Mutations:** Utilizes LLM models to generate context-aware mutants. [Research](https://arxiv.org/abs/2406.09843) indicates that LLM-generated mutants have higher fault detection potential, fewer equivalent mutants, and higher coupling and semantic similarity to real faults. It uses a map of your entire git repository to generate contextually relevant mutants using [aider's repomap](https://aider.chat/docs/repomap.html). Supports self-hosted LLMs, Anthropic, OpenAI, and any LLM models via [LiteLLM](https://github.com/BerriAI/litellm).
3129
- **Change-Based Testing:** Runs mutation tests on modified files and lines based on the latest commit or pull request changes, ensuring that only relevant parts of the code are tested.
3230
- **Language Agnostic:** Compatible with languages that provide coverage reports in Cobertura XML, Jacoco XML, and lcov formats. Extensible to additional languages and testing frameworks.
33-
- **Detailed Mutant Reports:** Provides comprehensive reports on mutation coverage, killed mutants, and survived mutants.
31+
- **LLM Surviving Mutants Analysis:** Automatically analyzes survived mutants to identify potential weaknesses in the test suite, vulnerabilities, and areas for improvement.
3432

3533
## Recommended Mutation Testing Process
3634

3735
![Workflow](/images/diagram.svg)
3836

37+
We recommend running Mutahunter per test file. This approach ensures that the mutation testing is focused on the test suite's effectiveness and efficiency. Here are some best practices to follow:
38+
3939
1. **Achieve High Line Coverage:** Ensure your test suite has high line coverage, preferably 100%.
4040

4141
2. **Strict Mutation Testing:** Use strict mutation testing during development to improve mutation coverage during development without additional cost. Utilize the `--only-mutate-file-paths` flag for targeted testing on critical files.
@@ -97,6 +97,11 @@ Check the logs directory to view the report:
9797
9898
- `mutants.json` - Contains the list of mutants generated.
9999
- `coverage.txt` - Contains information about mutation coverage.
100+
- `audit.md` - Contains the analysis of survived mutants
101+
102+
### Survivng Mutant Analysis Audit Report
103+
104+
![Report](/images/audit.png)
100105
101106
## CI/CD Integration
102107
@@ -154,26 +159,6 @@ jobs:
154159
filePath: logs/_latest/coverage.txt
155160
```
156161
157-
## Roadmap
158-
159-
- [x] **Fault Injection:** Utilize advanced LLM models to inject context-aware faults into the codebase, ensuring comprehensive mutation testing.
160-
- [x] **Language Support:** Expand support to include various programming languages.
161-
- [x] **Support for Other Coverage Report Formats:** Add compatibility for various coverage report formats.
162-
- [x] **Change-Based Testing:** Implement mutation testing on modified files based on the latest commit or pull request changes.
163-
- [x] **Extreme Mutation Testing:** Apply mutations to the codebase without using LLMs to detect pseudo-tested methods with significantly lower computational cost.
164-
- [x] **CI/CD Integration:** Display mutation coverage in pull requests and automate mutation testing using GitHub Actions.
165-
- [ ] **Mutant Analysis:** Automatically analyze survived mutants to identify potential weaknesses in the test suite.
166-
167162
## Cash Bounty Program
168163
169164
Help us improve Mutahunter and get rewarded! We have a cash bounty program to incentivize contributions to the project. Check out the [bounty board](https://docs.google.com/spreadsheets/d/1cT2_O55m5txrUgZV81g1gtqE_ZDu9LlzgbpNa_HIisc/edit?gid=0#gid=0) to see the available bounties and claim one today!
170-
171-
## Acknowledgements
172-
173-
Mutahunter makes use of the following open-source libraries:
174-
175-
- [aider](https://github.com/paul-gauthier/aider) by Paul Gauthier, licensed under the Apache-2.0 license.
176-
- [TreeSitter](https://github.com/tree-sitter/tree-sitter) by TreeSitter, MIT License.
177-
- [LiteLLM](https://github.com/BerriAI/litellm) by BerriAI, MIT License.
178-
179-
For more details, please refer to the LICENSE file in the repository.

images/audit.png

239 KB
Loading

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
66
name = 'mutahunter'
77
description = "LLM Mutation Testing for any programming language"
88
requires-python = ">= 3.11"
9-
version = "1.0.0"
9+
version = "1.1.0"
1010
dependencies = [
1111
"tree-sitter==0.21.3",
1212
'tree_sitter_languages==1.10.2',

src/mutahunter/core/mutator.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import time
55
from typing import Any, Dict, List
66

7+
from jinja2 import Template
78
from tqdm import tqdm
89

910
from mutahunter.core.analyzer import Analyzer
@@ -13,6 +14,7 @@
1314
from mutahunter.core.error_parser import extract_error_message
1415
from mutahunter.core.llm_mutation_engine import LLMMutationEngine
1516
from mutahunter.core.logger import logger
17+
from mutahunter.core.prompts.user import MUTANT_ANALYSIS
1618
from mutahunter.core.report import MutantReport
1719
from mutahunter.core.router import LLMRouter
1820
from mutahunter.core.runner import TestRunner
@@ -149,6 +151,9 @@ def run(self) -> None:
149151
total_cost=self.router.total_cost,
150152
line_rate=self.coverage_processor.line_coverage_rate,
151153
)
154+
if not self.config.extreme:
155+
self.run_mutant_analysis()
156+
152157
self.logger.info(
153158
f"Mutation Testing Ended. Took {round(time.time() - start)}s"
154159
)
@@ -456,3 +461,35 @@ def get_modified_lines(self, file_path: str) -> List[int]:
456461
except subprocess.CalledProcessError as e:
457462
self.logger.error(f"Error identifying modified lines in {file_path}: {e}")
458463
return []
464+
465+
def run_mutant_analysis(self) -> None:
466+
"""
467+
Runs mutant analysis on the generated mutants.
468+
"""
469+
survived_mutants = [m for m in self.mutants if m.status == "SURVIVED"]
470+
471+
source_file_paths = []
472+
for mutant in survived_mutants:
473+
if mutant.source_path not in source_file_paths:
474+
source_file_paths.append(mutant.source_path)
475+
476+
src_code_list = []
477+
for file_path in source_file_paths:
478+
with open(file_path, "r", encoding="utf-8") as f:
479+
src_code = f.read()
480+
src_code_list.append(
481+
f"## Source File: {file_path}\n```{filename_to_lang(file_path)}\n{src_code}\n```"
482+
)
483+
484+
prompt = {
485+
"system": "",
486+
"user": Template(MUTANT_ANALYSIS).render(
487+
source_code="\n".join(src_code_list),
488+
surviving_mutants=survived_mutants,
489+
),
490+
}
491+
mode_response, _, _ = self.router.generate_response(
492+
prompt=prompt, streaming=False
493+
)
494+
with open("logs/_latest/mutant_analysis.md", "w") as f:
495+
f.write(mode_response)

src/mutahunter/core/prompts/user.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,45 @@ class Mutants(BaseModel):
4343
4444
Generate 1~{{maximum_num_of_mutants_per_function_block}} mutants for the function block provided to you. Ensure that the mutants are semantically different from the original code. Focus on critical areas such as error handling, boundary conditions, and logical branches.
4545
"""
46+
47+
48+
MUTANT_ANALYSIS = """
49+
## Related Source Code:
50+
```
51+
{{source_code}}
52+
```
53+
54+
## Surviving Mutants:
55+
```json
56+
{{surviving_mutants}}
57+
```
58+
59+
Based on the mutation testing results only showing the surviving mutants. Please analyze the following aspects:
60+
- Vulnerable Code Areas: Identification of critical areas in the code that are most vulnerable based on the surviving mutants.
61+
- Test Case Gaps: Analysis of specific reasons why the existing test cases failed to detect these mutants.
62+
- Improvement Recommendations: Suggestions for new or improved test cases to effectively target and eliminate the surviving mutants.
63+
64+
## Example Output:
65+
======
66+
### Vulnerable Code Areas
67+
**File:** `src/main/java/com/example/BankAccount.java`
68+
**Location:** Line 45
69+
**Description:** The method `withdraw` does not properly handle negative inputs, leading to potential incorrect account balances.
70+
71+
### Test Case Gaps
72+
**File:** `src/test/java/com/example/BankAccountTest.java`
73+
**Location:** Test method `testWithdraw`
74+
**Reason:** Existing test cases do not cover edge cases such as negative withdrawals or withdrawals greater than the account balance.
75+
76+
### Improvement Recommendations
77+
**New Test Cases Needed:**
78+
1. **Test Method:** `testWithdrawNegativeAmount`
79+
- **Description:** Add a test case to check behavior when attempting to withdraw a negative amount.
80+
2. **Test Method:** `testWithdrawExceedingBalance`
81+
- **Description:** Add a test case to ensure proper handling when withdrawing an amount greater than the current account balance.
82+
3. **Test Method:** `testWithdrawBoundaryConditions`
83+
- **Description:** Add boundary condition tests for withdrawal amounts exactly at zero and exactly equal to the account balance.
84+
====
85+
86+
To reduce cognitive load, focus on quality over quantity to ensure that the mutants analysis are meaningful and provide valuable insights into the code quality and test coverage. Output your analysis in a clear and concise manner, highlighting the key points for each aspect with less than 300 words.
87+
"""

0 commit comments

Comments
 (0)