Java implementation of a GenProg-style Automated Program Repair (APR) engine for Task 03.
- Group 7
- Tim Greller
- Jonas Heitz
- Rafail Venediktov
This tool takes a buggy Java program, a test suite, and fault-localization weights, then searches for a patch using a genetic programming loop.
High-level flow:
- Load benchmark metadata and source files.
- Build initial patch population.
- Evaluate candidates by compile + test execution.
- Select better candidates.
- Generate offspring with crossover + mutation.
- Repeat until all tests pass or limits are reached.
Implemented pipeline is assignment-oriented and close to GenProg pseudocode:
- weighted fault localization guides mutation target choice
- patch population is evolved over generations
- fitness is test-based
- stop criteria: full test pass, generation cap, time cap
Core GenProg edit operators:
DELETEINSERTSWAP
Additional generic expression-level operators (for practical Java repairability):
REPLACE_EXPRMUTATE_BINARY_OPERATORNEGATE_EXPRESSION
The current repository behavior is strict with respect to FL weights:
- suspiciousness values come only from
fault-localization.json - expected levels are
1.0,0.1,0.0 - no fallback exploration of
0.0statements in statement selection - no suspiciousness normalization in selection probability
.
├── src/main/java/edu/passau/apr/
│ ├── Main.java # CLI entrypoint, run orchestration
│ ├── algorithm/
│ │ └── GeneticAlgorithm.java # Evolution loop (init/select/crossover/mutate/evaluate)
│ ├── config/
│ │ └── Config.java # Runtime parameters + defaults
│ ├── evaluator/
│ │ └── FitnessEvaluator.java # Compile + JUnit execution + fitness calculation
│ ├── model/
│ │ ├── BenchmarkConfig.java # Parsed benchmark metadata
│ │ ├── Edit.java # Edit representation
│ │ ├── FitnessResult.java # Fitness tuple/state
│ │ ├── Patch.java # Patch object + mutation/apply logic
│ │ └── StatementWeight.java # FL weight model
│ ├── operator/
│ │ ├── PatchGenerator.java # Random/guided patch generation + crossover
│ │ └── PatchGeneratorTest.java # Generator-focused tests
│ └── util/
│ ├── AstUtils.java # Shared AST safety/compatibility checks
│ ├── BenchmarkLoader.java # JSON loading for benchmark/fl config
│ └── Pair.java # Utility pair
├── benchmarks/ # Benchmark suite B01..B12
├── docs/
│ ├── assignment/ # Task PDF + declaration template
│ └── papers/ # GenProg papers
├── test_quick.sh # Sweep script for all benchmarks
├── README.md
└── REPORT.md
Current benchmark set:
B01_OffByOneB02_DuplicateLineB03_MissingStatementB04_WrongPredicatesB05_WrongIndexB06_InventoryNormalizationB07_IntervalPlannerB08_LogReportBuilderB09_ShippingTierSwitchB10_BillingProrationB11_ConsecutiveBatcherB12_TagSanitizer
Each benchmark directory contains:
buggy/— buggy sourcefixed/— reference fixed sourcetests/— JUnit testsbenchmark.json— paths + test class namesfault-localization.json— suspiciousness weights
- Java 17+
- macOS/Linux shell (examples use
bash) - Gradle Wrapper included (
./gradlew)
./gradlew build./gradlew run --args="--benchmark benchmarks/B01_OffByOne --seed 42 --maxGenerations 80 --timeLimitSec 120" --no-daemon./test_quick.sh
# or explicitly:
./test_quick.sh 42 80 120--benchmark <path>required--seed <long>--maxGenerations <int>--timeLimitSec <long>--populationSize <int>--positiveTestWeight <double>--negativeTestWeight <double>--mutationWeight <double>--runTests <buggy|fixed>(compile+run tests only)--verbose
Defaults are defined in /Users/rafailvv/Учеба/University of Passau/Program Repair/Task 3/src/main/java/edu/passau/apr/config/Config.java.
./gradlew run --args="--benchmark benchmarks/B01_OffByOne --runTests buggy" --no-daemon
./gradlew run --args="--benchmark benchmarks/B01_OffByOne --runTests fixed" --no-daemonPatched source output:
out/<benchmark>/patch_<timestamp>/<MainClass>.java
Status: OKmeans the APR process exited with code0.- Actual repair success is indicated by:
SUCCESS: Found a patch that passes all tests!
No solution found within limits.means no full repair was found under given search budget.
- If runs are unstable between launches, keep seed fixed and increase
--maxGenerations/--timeLimitSec. - If runs look stuck, verify FL file points to correct buggy lines.
- If output is very verbose, redirect stderr or use filtered script output.
- If Gradle daemon state is noisy, use
--no-daemonas in examples.
- APR is stochastic by design; outcomes can vary by seed and budget.
- The implementation remains benchmark-agnostic at algorithm level (no benchmark-specific hardcoded fixes).