Skip to content

Added mutator choice for web and cli #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ we click on [example.cpp](http://127.0.0.1:5000/projects/1/files/1), we see the

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

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

### `generate_patches.py`
This script will generate patches for all files in a project.
This script will generate patches for files in a project using selected mutators.

Example usage:
```bash
venv/bin/python3 cli/generate_patches.py --project "Example project"
```

Example usage with files and mutators:
```bash
venv/bin/python3 cli/generate_patches.py \
--project "Example project" \
--files /tmp/cmake-example/src/example.cpp:13:-1 \
--mutators logicalOperator,lineDeletion
```

### `queue_control.py`
This script allows you to control the queue and view its state.

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

## List of mutators

| Mutator | Description |
|----------|-------------|
| lineDeletion | Deletes a whole line |
| logicalOperator | Replaces logical operators (&&, \|\|, and, or, !, not) |
| comparisonOperator | Replaces comparison operators (==, !=, <, >, <=, >=) |
| incDecOperator | Swaps increment and decrement operators (++, --) |
| assignmentOperator | Replaces assignment operators (=, +=, -=, *=, /=, %=) |
| booleanAssignmentOperator | Replaces Boolean assignment operators (=, &=, \|=, ^=, <<=, >>=) |
| arithmeticOperator | Replaces arithmetic operators (+, -, *, /, %) |
| booleanArithmeticOperator | Replaces Boolean arithmetic operators (&, \|, ^, <<, >>) |
| booleanLiteral | Swaps the Boolean literals true and false |
| stdInserter | Changes the position where elements are inserted (front_inserter, back_inserter) |
| stdRangePredicate | Changes the semantics of an STL range predicate (all_of, any_of, none_of) |
| stdMinMax | Swaps STL minimum by maximum calls (min, max) |
| decimalNumberLiteral | Replaces decimal number literals with different values |
| hexNumberLiteral | Replaces hex number literals with different values |
| iteratorRange | Changes an iterator range (begin, end) |

## Help!

Mutate++ is in a very early stage, and there is a lot to do. In particular, we are aware of severe limitations:
Expand Down
7 changes: 5 additions & 2 deletions app/utils/Mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def find_mutations(self, line):
return self.pattern.mutate(line)


def get_mutators():
def get_mutators(mutator_ids=None):
mutators = [
LineDeletionMutator(),
LogicalOperatorMutator(),
Expand All @@ -358,4 +358,7 @@ def get_mutators():
IteratorRangeMutator()
]

return {mutator.mutator_id: mutator for mutator in mutators}
if mutator_ids:
mutators = [mutator for mutator in mutators if mutator.mutator_id in mutator_ids]

return {mutator.mutator_id: mutator for mutator in mutators}
4 changes: 2 additions & 2 deletions app/utils/SourceFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def __init__(self, file: File, first_line, last_line):
# read the relevant content
self.content = '\n'.join(self.full_content[self.first_line - 1:self.last_line]) # type: str

def generate_patches(self):
mutators = get_mutators()
def generate_patches(self, mutator_ids):
mutators = get_mutators(mutator_ids)

for line_number, line_raw in self.__get_lines():
for mutator_name, mutator in mutators.items():
Expand Down
3 changes: 2 additions & 1 deletion app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,9 @@ def route_v2_project_project_id_files_file_id_generate(project_id, file_id):
except ValueError:
last_line = -1

mutators = [key for key in request.form if key not in ['first_line', 'last_line']]
s = SourceFile(file, first_line, last_line)
s.generate_patches()
s.generate_patches(mutators)
flash('Successfully created patches.', category='message')
return redirect(url_for('route_v2_project_project_id', project_id=project.id))

Expand Down
31 changes: 28 additions & 3 deletions cli/generate_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ def main():
"--project", type=str, required=True,
help="The name of the project. If not provided, all projects will be processed."
)
# TODO allow selection of first/last line + which patches to generate
argument_parser.add_argument(
"--files", type=str,
help='File list in format: "file1@start:end;file2@start:end". If not provided, all files in project will be used.'
)
argument_parser.add_argument(
"--mutators", type=str,
help="Comma-separated list of mutators to use. If not provided, all mutators will be used."
)
arguments = argument_parser.parse_args()

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

# Parse mutators if specified
mutator_ids = arguments.mutators.split(',') if arguments.mutators else None

# Parse file filters if specified
file_filters = {}
if arguments.files:
for file_spec in arguments.files.split(';'):
filename, line_range = file_spec.split('@')
first_line, last_line = map(int, line_range.split(':'))
file_filters[filename] = (first_line, last_line)

# Process files
for file in files:
if file_filters and file.filename not in file_filters:
continue

print(f"Generating patches for '{file.filename}'...")
source_file = SourceFile(file, 1, -1)
source_file.generate_patches()

# If file_filters is empty use all lines of every file
first_line, last_line = file_filters.get(file.filename, (1, -1))
source_file = SourceFile(file, first_line, last_line)
source_file.generate_patches(mutator_ids)

print("Done")
exit(0)
Expand Down