Skip to content

Commit 4211e59

Browse files
committed
Added mutator choice for web and cli
1 parent a7b2647 commit 4211e59

File tree

5 files changed

+67
-11
lines changed

5 files changed

+67
-11
lines changed

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ we click on [example.cpp](http://127.0.0.1:5000/projects/1/files/1), we see the
145145

146146
- Next to "example.cpp", click on ["generate patches"](http://127.0.0.1:5000/projects/1/files/1/generate).
147147
- Leave "first line" and "last line" empty to mutate the whole file.
148-
- Right now, none of the check boxes are actually implemented, so you can ignore all of them - all mutations will be
149-
used by default.
148+
- Select check boxes of mutations you want to use. If none is selected, all mutations will be used by default.
150149
- Click on "Generate patches".
151150

152151
Back in the [project overview](http://127.0.0.1:5000/projects/1), you see that 14 patches have been generated. You can
@@ -275,13 +274,21 @@ venv/bin/python3 cli/add_files.py --project "Example project" /tmp/cmake-example
275274
```
276275

277276
### `generate_patches.py`
278-
This script will generate patches for all files in a project.
277+
This script will generate patches for files in a project using selected mutators.
279278

280279
Example usage:
281280
```bash
282281
venv/bin/python3 cli/generate_patches.py --project "Example project"
283282
```
284283

284+
Example usage with files and mutators:
285+
```bash
286+
venv/bin/python3 cli/generate_patches.py \
287+
--project "Example project" \
288+
--files /tmp/cmake-example/src/example.cpp:13:-1 \
289+
--mutators logicalOperator,lineDeletion
290+
```
291+
285292
### `queue_control.py`
286293
This script allows you to control the queue and view its state.
287294

@@ -290,6 +297,26 @@ Example usage:
290297
venv/bin/python3 cli/queue_control.py start
291298
```
292299

300+
## List of mutators
301+
302+
| Mutator | Description |
303+
|----------|-------------|
304+
| lineDeletion | Deletes a whole line |
305+
| logicalOperator | Replaces logical operators (&&, \|\|, and, or, !, not) |
306+
| comparisonOperator | Replaces comparison operators (==, !=, <, >, <=, >=) |
307+
| incDecOperator | Swaps increment and decrement operators (++, --) |
308+
| assignmentOperator | Replaces assignment operators (=, +=, -=, *=, /=, %=) |
309+
| booleanAssignmentOperator | Replaces Boolean assignment operators (=, &=, \|=, ^=, <<=, >>=) |
310+
| arithmeticOperator | Replaces arithmetic operators (+, -, *, /, %) |
311+
| booleanArithmeticOperator | Replaces Boolean arithmetic operators (&, \|, ^, <<, >>) |
312+
| booleanLiteral | Swaps the Boolean literals true and false |
313+
| stdInserter | Changes the position where elements are inserted (front_inserter, back_inserter) |
314+
| stdRangePredicate | Changes the semantics of an STL range predicate (all_of, any_of, none_of) |
315+
| stdMinMax | Swaps STL minimum by maximum calls (min, max) |
316+
| decimalNumberLiteral | Replaces decimal number literals with different values |
317+
| hexNumberLiteral | Replaces hex number literals with different values |
318+
| iteratorRange | Changes an iterator range (begin, end) |
319+
293320
## Help!
294321

295322
Mutate++ is in a very early stage, and there is a lot to do. In particular, we are aware of severe limitations:

app/utils/Mutation.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def find_mutations(self, line):
339339
return self.pattern.mutate(line)
340340

341341

342-
def get_mutators():
342+
def get_mutators(mutator_ids=None):
343343
mutators = [
344344
LineDeletionMutator(),
345345
LogicalOperatorMutator(),
@@ -358,4 +358,7 @@ def get_mutators():
358358
IteratorRangeMutator()
359359
]
360360

361-
return {mutator.mutator_id: mutator for mutator in mutators}
361+
if mutator_ids:
362+
mutators = [mutator for mutator in mutators if mutator.mutator_id in mutator_ids]
363+
364+
return {mutator.mutator_id: mutator for mutator in mutators}

app/utils/SourceFile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def __init__(self, file: File, first_line, last_line):
2525
# read the relevant content
2626
self.content = '\n'.join(self.full_content[self.first_line - 1:self.last_line]) # type: str
2727

28-
def generate_patches(self):
29-
mutators = get_mutators()
28+
def generate_patches(self, mutator_ids):
29+
mutators = get_mutators(mutator_ids)
3030

3131
for line_number, line_raw in self.__get_lines():
3232
for mutator_name, mutator in mutators.items():

app/views.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,9 @@ def route_v2_project_project_id_files_file_id_generate(project_id, file_id):
351351
except ValueError:
352352
last_line = -1
353353

354+
mutators = [key for key in request.form if key not in ['first_line', 'last_line']]
354355
s = SourceFile(file, first_line, last_line)
355-
s.generate_patches()
356+
s.generate_patches(mutators)
356357
flash('Successfully created patches.', category='message')
357358
return redirect(url_for('route_v2_project_project_id', project_id=project.id))
358359

cli/generate_patches.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ def main():
1919
"--project", type=str, required=True,
2020
help="The name of the project. If not provided, all projects will be processed."
2121
)
22-
# TODO allow selection of first/last line + which patches to generate
22+
argument_parser.add_argument(
23+
"--files", type=str,
24+
help='File list in format: "file1@start:end;file2@start:end". If not provided, all files in project will be used.'
25+
)
26+
argument_parser.add_argument(
27+
"--mutators", type=str,
28+
help="Comma-separated list of mutators to use. If not provided, all mutators will be used."
29+
)
2330
arguments = argument_parser.parse_args()
2431

2532
# Verify that the project exists
@@ -35,10 +42,28 @@ def main():
3542
print("No files found to process.")
3643
exit(2)
3744

45+
# Parse mutators if specified
46+
mutator_ids = arguments.mutators.split(',') if arguments.mutators else None
47+
48+
# Parse file filters if specified
49+
file_filters = {}
50+
if arguments.files:
51+
for file_spec in arguments.files.split(';'):
52+
filename, line_range = file_spec.split('@')
53+
first_line, last_line = map(int, line_range.split(':'))
54+
file_filters[filename] = (first_line, last_line)
55+
56+
# Process files
3857
for file in files:
58+
if file_filters and file.filename not in file_filters:
59+
continue
60+
3961
print(f"Generating patches for '{file.filename}'...")
40-
source_file = SourceFile(file, 1, -1)
41-
source_file.generate_patches()
62+
63+
# If file_filters is empty use all lines of every file
64+
first_line, last_line = file_filters.get(file.filename, (1, -1))
65+
source_file = SourceFile(file, first_line, last_line)
66+
source_file.generate_patches(mutator_ids)
4267

4368
print("Done")
4469
exit(0)

0 commit comments

Comments
 (0)