-
Notifications
You must be signed in to change notification settings - Fork 57
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
Is it possible to define a mutation operator that takes arguments? #528
Comments
There is not currently a way to do that. I guess broadly speaking you'd want to be able to do some per-operator configuration in the configuration file and have it take effect when you exec your session. This seems totally reasonable. A few things come to mind which we'd need to think about.
There are probably other angles to this that I'm not seeing right now. Does any of this sound reasonable to you, or along the lines of what you had in mind? I don't know when I'd be able to work on this, but it feels like a good "airplane project"...I just need a long trip somewhere! |
An example might help with this decision. I have implemented a Here's the implementation: """Implementation of the variable-replacement operator."""
from .operator import Operator
from parso.python.tree import Name, Number
from random import randint
class VariableReplacer(Operator):
"""An operator that replaces usages of named variables."""
def __init__(self, cause_variable, effect_variable=None):
self.cause_variable = cause_variable
self.effect_variable = effect_variable
def mutation_positions(self, node):
"""Mutate usages of the specified cause variable. If an effect variable is also
specified, then only mutate usages of the cause variable in definitions of the
effect variable."""
if isinstance(node, Name) and node.value == self.cause_variable:
# Confirm that name node is used on right hand side of the expression
expr_node = node.search_ancestor('expr_stmt')
if expr_node:
cause_variables = expr_node.get_rhs().children
if node in cause_variables:
mutation_position = (node.start_pos, node.end_pos)
# If an effect variable is specified, confirm that it appears on left hand
# side of the expression
if self.effect_variable:
effect_variable_names = [v.value for v in expr_node.get_defined_names()]
if self.effect_variable in effect_variable_names:
yield mutation_position
# If no effect variable is specified, any occurrence of the cause variable
# on the right hand side of an expression can be mutated
else:
yield mutation_position
def mutate(self, node, index):
"""Replace cause variable with random constant."""
assert isinstance(node, Name)
return Number(start_pos=node.start_pos, value=str(randint(-100, 100)))
@classmethod
def examples(cls):
return (
# for cause_variable='x'
('y = x + z', 'y = 10 + z'),
# for cause_variable='x' and effect_variable='y'
('j = x + z\ny = x + z', 'j = x + z\ny = -2 + z'),
# for cause_variable='x' and effect_variable='j',
('j = x + z\ny = x + z', 'j = 1 + z\ny = x + z'),
# for cause_variable='x'
('y = 2*x + 10 + j + x**2', 'y=2*10 + 10 + j + -4**2'),
) The class works if I manually modify # cause_variable='x'
# effect_variable='y'
--- mutation diff ---
--- acalculator.py
+++ bcalculator.py
@@ -1,5 +1,5 @@
def mul(x, z):
j = x * z
- y = x * j
+ y =28 * j
return y Now we need a way to pass two variables to instances of [[cosmic-ray.operators]]
name = "variable_replacer"
args = [{ cause_variable = "x", effect_variable = "y"},
{ cause_variable = "x", effect_variable = "j"}]
[[cosmic-ray.operators]]
name = "number_replacer" Then, for every unique set of arguments defined for an operator, a What are your thoughts? |
* Created a variable replacer mutation operator * Fixed typo in variable replacer operator examples * Work item now stores parameter information * Work DB now stores operator args and applies them * Initialisation only tries mutation operators without args if none are specified * Mutate and test now robust to lack of operator_args * Added a variable inserter mutation operator * Updated VariableInserter documentation * Removed unneccessary comment from variable inserter * VariableReplacer now replaces all usages of variable in statement * Example dataclass added and tests updated * Added exception to TypeError to catch operator args typos * Refactored getting operator args in init * Config is now loaded with a configuration or None
I would like to define a custom mutation operator that looks for particular variables in the program-under-test and replaces them with random constants. For example, I might want to replace all uses of a variable named
x1
with some randomly sampled int.Is there a straightforward way to achieve this using cosmic-ray? I have tried defining my own
Operator
sub-class but I need a way to pass the target variable to the mutation operator.Thanks in advance.
The text was updated successfully, but these errors were encountered: