testgenie-py 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- testgen/__init__.py +0 -0
- testgen/analyzer/__init__.py +0 -0
- testgen/analyzer/ast_analyzer.py +149 -0
- testgen/analyzer/contracts/__init__.py +0 -0
- testgen/analyzer/contracts/contract.py +13 -0
- testgen/analyzer/contracts/no_exception_contract.py +16 -0
- testgen/analyzer/contracts/nonnull_contract.py +15 -0
- testgen/analyzer/fuzz_analyzer.py +106 -0
- testgen/analyzer/random_feedback_analyzer.py +291 -0
- testgen/analyzer/reinforcement_analyzer.py +75 -0
- testgen/analyzer/test_case_analyzer.py +46 -0
- testgen/analyzer/test_case_analyzer_context.py +58 -0
- testgen/controller/__init__.py +0 -0
- testgen/controller/cli_controller.py +194 -0
- testgen/controller/docker_controller.py +169 -0
- testgen/docker/Dockerfile +22 -0
- testgen/docker/poetry.lock +361 -0
- testgen/docker/pyproject.toml +22 -0
- testgen/generator/__init__.py +0 -0
- testgen/generator/code_generator.py +66 -0
- testgen/generator/doctest_generator.py +208 -0
- testgen/generator/generator.py +55 -0
- testgen/generator/pytest_generator.py +77 -0
- testgen/generator/test_generator.py +26 -0
- testgen/generator/unit_test_generator.py +84 -0
- testgen/inspector/__init__.py +0 -0
- testgen/inspector/inspector.py +61 -0
- testgen/main.py +13 -0
- testgen/models/__init__.py +0 -0
- testgen/models/analysis_context.py +56 -0
- testgen/models/function_metadata.py +61 -0
- testgen/models/generator_context.py +63 -0
- testgen/models/test_case.py +8 -0
- testgen/presentation/__init__.py +0 -0
- testgen/presentation/cli_view.py +12 -0
- testgen/q_table/global_q_table.json +1 -0
- testgen/reinforcement/__init__.py +0 -0
- testgen/reinforcement/abstract_state.py +7 -0
- testgen/reinforcement/agent.py +153 -0
- testgen/reinforcement/environment.py +215 -0
- testgen/reinforcement/statement_coverage_state.py +33 -0
- testgen/service/__init__.py +0 -0
- testgen/service/analysis_service.py +260 -0
- testgen/service/cfg_service.py +55 -0
- testgen/service/generator_service.py +169 -0
- testgen/service/service.py +389 -0
- testgen/sqlite/__init__.py +0 -0
- testgen/sqlite/db.py +84 -0
- testgen/sqlite/db_service.py +219 -0
- testgen/tree/__init__.py +0 -0
- testgen/tree/node.py +7 -0
- testgen/tree/tree_utils.py +79 -0
- testgen/util/__init__.py +0 -0
- testgen/util/coverage_utils.py +168 -0
- testgen/util/coverage_visualizer.py +154 -0
- testgen/util/file_utils.py +110 -0
- testgen/util/randomizer.py +122 -0
- testgen/util/utils.py +143 -0
- testgen/util/z3_utils/__init__.py +0 -0
- testgen/util/z3_utils/ast_to_z3.py +99 -0
- testgen/util/z3_utils/branch_condition.py +72 -0
- testgen/util/z3_utils/constraint_extractor.py +36 -0
- testgen/util/z3_utils/variable_finder.py +10 -0
- testgen/util/z3_utils/z3_test_case.py +94 -0
- testgenie_py-0.1.0.dist-info/METADATA +24 -0
- testgenie_py-0.1.0.dist-info/RECORD +68 -0
- testgenie_py-0.1.0.dist-info/WHEEL +4 -0
- testgenie_py-0.1.0.dist-info/entry_points.txt +3 -0
testgen/util/utils.py
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
|
2
|
+
import ast
|
3
|
+
import string
|
4
|
+
import sys
|
5
|
+
import random
|
6
|
+
from typing import List
|
7
|
+
|
8
|
+
from atheris import FuzzedDataProvider
|
9
|
+
|
10
|
+
from testgen.util.file_utils import load_and_parse_file_for_tree
|
11
|
+
|
12
|
+
|
13
|
+
def get_func(module, func_name:str):
|
14
|
+
return getattr(module, func_name)
|
15
|
+
|
16
|
+
def extract_parameter_types(func_node):
|
17
|
+
"""Extract parameter types from a function node."""
|
18
|
+
param_types = {}
|
19
|
+
for arg in func_node.args.args:
|
20
|
+
param_name = arg.arg
|
21
|
+
if arg.annotation:
|
22
|
+
param_type = ast.unparse(arg.annotation)
|
23
|
+
param_types[param_name] = param_type
|
24
|
+
else:
|
25
|
+
if param_name != 'self':
|
26
|
+
param_types[param_name] = None
|
27
|
+
return param_types
|
28
|
+
|
29
|
+
def generate_random_inputs(param_types):
|
30
|
+
"""Generate inputs for fuzzing based on parameter types."""
|
31
|
+
inputs = {}
|
32
|
+
for param, param_type in param_types.items():
|
33
|
+
if param_type == "int":
|
34
|
+
# Try using sys.maxsize for minsize and maxsize
|
35
|
+
minsize = -sys.maxsize - 1
|
36
|
+
maxsize = sys.maxsize
|
37
|
+
random_integer = random.randint(minsize, maxsize)
|
38
|
+
inputs[param] = random_integer
|
39
|
+
elif param_type == "bool":
|
40
|
+
random_choice = random.choice([True, False])
|
41
|
+
inputs[param] = random_choice
|
42
|
+
elif param_type == "float":
|
43
|
+
random_float = random.random()
|
44
|
+
inputs[param] = random_float
|
45
|
+
# TODO: Random String and Random bytes; Random objects?
|
46
|
+
elif param_type == "str":
|
47
|
+
inputs[param] = "abc"
|
48
|
+
#elif param_type == "bytes":
|
49
|
+
# inputs[param] = fdp.ConsumeBytes(10)
|
50
|
+
else:
|
51
|
+
inputs[param] = None
|
52
|
+
return inputs
|
53
|
+
|
54
|
+
def generate_extreme_inputs(param_types):
|
55
|
+
inputs = {}
|
56
|
+
for param, param_type in param_types.items():
|
57
|
+
if param_type == "int":
|
58
|
+
# int is unbounded in Python, but sys.maxsize is the max value representable by a signed word
|
59
|
+
inputs[param] = sys.maxsize
|
60
|
+
if param_type == "bool":
|
61
|
+
random_choice = random.choice([1, 0])
|
62
|
+
inputs[param] = random_choice
|
63
|
+
if param_type == "float":
|
64
|
+
random_choice = random.choice([sys.float_info.min, sys.float_info.max])
|
65
|
+
inputs[param] = random_choice
|
66
|
+
if param_type == "str":
|
67
|
+
inputs[param] = ''.join(random.choice([string.ascii_letters, string.digits, string.punctuation, string.whitespace]) for _ in range(100))
|
68
|
+
|
69
|
+
def generate_inputs_from_fuzz_data(fdp: FuzzedDataProvider, param_types):
|
70
|
+
"""Generate fuzzed inputs based on parameter types."""
|
71
|
+
inputs = []
|
72
|
+
for param_type in param_types.values():
|
73
|
+
if param_type == "int":
|
74
|
+
inputs.append(fdp.ConsumeInt(4))
|
75
|
+
elif param_type == "bool":
|
76
|
+
inputs.append(fdp.ConsumeBool())
|
77
|
+
elif param_type == "float":
|
78
|
+
inputs.append(fdp.ConsumeFloat())
|
79
|
+
elif param_type == "str":
|
80
|
+
inputs.append(fdp.ConsumeString(10))
|
81
|
+
elif param_type == "bytes":
|
82
|
+
inputs.append(fdp.ConsumeBytes(10))
|
83
|
+
else:
|
84
|
+
inputs.append(None)
|
85
|
+
return tuple(inputs)
|
86
|
+
|
87
|
+
def get_functions(tree) -> List[ast.FunctionDef]:
|
88
|
+
functions = []
|
89
|
+
for node in tree.body:
|
90
|
+
if isinstance(node, ast.FunctionDef):
|
91
|
+
functions.append(node)
|
92
|
+
if isinstance(node, ast.ClassDef):
|
93
|
+
for class_node in node.body:
|
94
|
+
if isinstance(class_node, ast.FunctionDef):
|
95
|
+
functions.append(class_node)
|
96
|
+
return functions
|
97
|
+
|
98
|
+
def get_function_boundaries(file_name: str, func_name: str) -> tuple:
|
99
|
+
tree = load_and_parse_file_for_tree(file_name)
|
100
|
+
for i, node in enumerate(tree.body):
|
101
|
+
if isinstance(node, ast.FunctionDef) and node.name == func_name:
|
102
|
+
func_start = node.lineno
|
103
|
+
|
104
|
+
if i == len(tree.body) - 1:
|
105
|
+
max_lines = [line.lineno for line in ast.walk(node) if hasattr(line, 'lineno') and line.lineno]
|
106
|
+
func_end = max(max_lines) if max_lines else func_start
|
107
|
+
else:
|
108
|
+
next_node = tree.body[i + 1]
|
109
|
+
if hasattr(next_node, 'lineno'):
|
110
|
+
func_end = next_node.lineno - 1
|
111
|
+
else:
|
112
|
+
max_lines = [line.lineno for line in ast.walk(node) if hasattr(line, 'lineno') and line.lineno]
|
113
|
+
func_end = max(max_lines) if max_lines else func_start
|
114
|
+
|
115
|
+
return func_start, func_end
|
116
|
+
|
117
|
+
# For classes
|
118
|
+
for node in tree.body:
|
119
|
+
if isinstance(node, ast.ClassDef):
|
120
|
+
for i, method in enumerate(node.body):
|
121
|
+
if isinstance(method, ast.FunctionDef) and method.name == func_name:
|
122
|
+
func_start = method.lineno
|
123
|
+
|
124
|
+
# Find end of method
|
125
|
+
if i == len(node.body) - 1:
|
126
|
+
max_lines = [line.lineno for line in ast.walk(method)
|
127
|
+
if hasattr(line, 'lineno') and line.lineno]
|
128
|
+
func_end = max(max_lines) if max_lines else func_start
|
129
|
+
else:
|
130
|
+
next_method = node.body[i + 1]
|
131
|
+
if hasattr(next_method, 'lineno'):
|
132
|
+
func_end = next_method.lineno - 1
|
133
|
+
else:
|
134
|
+
max_lines = [line.lineno for line in ast.walk(method)
|
135
|
+
if hasattr(line, 'lineno') and line.lineno]
|
136
|
+
func_end = max(max_lines) if max_lines else func_start
|
137
|
+
|
138
|
+
return func_start, func_end
|
139
|
+
|
140
|
+
raise ValueError(f"Function {func_name} not found in {file_name}")
|
141
|
+
|
142
|
+
|
143
|
+
|
File without changes
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import ast
|
2
|
+
from typing import Dict
|
3
|
+
import z3
|
4
|
+
|
5
|
+
class ASTToZ3(ast.NodeVisitor):
|
6
|
+
def __init__(self, param_types: Dict[str, str]):
|
7
|
+
self.param_types = param_types
|
8
|
+
self.z3_vars = {}
|
9
|
+
|
10
|
+
def create_z3_var(self, name: str, type_hint: str = None):
|
11
|
+
if name in self.z3_vars:
|
12
|
+
return self.z3_vars[name]
|
13
|
+
|
14
|
+
if type_hint == "int" or type_hint is None:
|
15
|
+
z3_var = z3.Int(name)
|
16
|
+
elif type_hint == "float":
|
17
|
+
z3_var = z3.Real(name)
|
18
|
+
elif type_hint == "bool":
|
19
|
+
z3_var = z3.Bool(name)
|
20
|
+
elif type_hint == "str":
|
21
|
+
z3_var = z3.String(name)
|
22
|
+
else:
|
23
|
+
z3_var = z3.Int(name)
|
24
|
+
|
25
|
+
self.z3_vars[name] = z3_var
|
26
|
+
return z3_var
|
27
|
+
|
28
|
+
def visit_Name(self, node):
|
29
|
+
if node.id in self.param_types:
|
30
|
+
return self.create_z3_var(node.id, self.param_types[node.id])
|
31
|
+
return self.create_z3_var(node.id)
|
32
|
+
|
33
|
+
def visit_Constant(self, node):
|
34
|
+
return node.value
|
35
|
+
|
36
|
+
def visit_BinOp(self, node):
|
37
|
+
left = self.visit(node.left)
|
38
|
+
right = self.visit(node.right)
|
39
|
+
|
40
|
+
if isinstance(node.op, ast.Add):
|
41
|
+
return left + right
|
42
|
+
elif isinstance(node.op, ast.Sub):
|
43
|
+
return left - right
|
44
|
+
elif isinstance(node.op, ast.Mult):
|
45
|
+
return left * right
|
46
|
+
elif isinstance(node.op, ast.Div):
|
47
|
+
return left / right
|
48
|
+
elif isinstance(node.op, ast.Mod):
|
49
|
+
return left % right
|
50
|
+
else:
|
51
|
+
raise NotImplementedError(f"Operation {node.op} not implemented")
|
52
|
+
|
53
|
+
def visit_Compare(self, node):
|
54
|
+
left = self.visit(node.left)
|
55
|
+
|
56
|
+
result = None
|
57
|
+
for i, (op, right) in enumerate(zip(node.ops, node.comparators)):
|
58
|
+
right_val = self.visit(right)
|
59
|
+
|
60
|
+
if isinstance(op, ast.Eq):
|
61
|
+
condition = left == right_val
|
62
|
+
elif isinstance(op, ast.NotEq):
|
63
|
+
condition = left != right_val
|
64
|
+
elif isinstance(op, ast.Lt):
|
65
|
+
condition = left < right_val
|
66
|
+
elif isinstance(op, ast.LtE):
|
67
|
+
condition = left <= right_val
|
68
|
+
elif isinstance(op, ast.Gt):
|
69
|
+
condition = left > right_val
|
70
|
+
elif isinstance(op, ast.GtE):
|
71
|
+
condition = left >= right_val
|
72
|
+
|
73
|
+
if result is None:
|
74
|
+
result = condition
|
75
|
+
else:
|
76
|
+
result = z3.And(result, condition)
|
77
|
+
|
78
|
+
return result
|
79
|
+
|
80
|
+
def visit_BoolOp(self, node):
|
81
|
+
values = [self.visit(value) for value in node.values]
|
82
|
+
|
83
|
+
if isinstance(node.op, ast.And):
|
84
|
+
return z3.And(*values)
|
85
|
+
elif isinstance(node.op, ast.Or):
|
86
|
+
return z3.Or(*values)
|
87
|
+
else:
|
88
|
+
raise NotImplementedError(f"Operation {node.op} not implemented")
|
89
|
+
|
90
|
+
def convert(self, ast_node):
|
91
|
+
return self.visit(ast_node)
|
92
|
+
|
93
|
+
def ast_to_z3_constraint(branch_condition, param_types):
|
94
|
+
converter = ASTToZ3(param_types)
|
95
|
+
z3_expr = converter.convert(branch_condition.condition_ast)
|
96
|
+
branch_condition.z3_expr = z3_expr
|
97
|
+
return z3_expr, converter.z3_vars
|
98
|
+
|
99
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import ast
|
2
|
+
|
3
|
+
class BranchCondition:
|
4
|
+
def __init__(self, condition_ast, line_number, variables):
|
5
|
+
self._condition_ast = condition_ast
|
6
|
+
self._line_number = line_number
|
7
|
+
self._variables = variables
|
8
|
+
self._z3_expr = None
|
9
|
+
|
10
|
+
@property
|
11
|
+
def condition_ast(self):
|
12
|
+
"""Get the AST node representing the condition"""
|
13
|
+
return self._condition_ast
|
14
|
+
|
15
|
+
@condition_ast.setter
|
16
|
+
def condition_ast(self, value):
|
17
|
+
"""Set the AST node representing the condition"""
|
18
|
+
self._condition_ast = value
|
19
|
+
|
20
|
+
@property
|
21
|
+
def line_number(self):
|
22
|
+
"""Get the line number where this condition appears"""
|
23
|
+
return self._line_number
|
24
|
+
|
25
|
+
@line_number.setter
|
26
|
+
def line_number(self, value):
|
27
|
+
"""Set the line number where this condition appears"""
|
28
|
+
self._line_number = value
|
29
|
+
|
30
|
+
@property
|
31
|
+
def variables(self):
|
32
|
+
"""Get the variables used in this condition"""
|
33
|
+
return self._variables
|
34
|
+
|
35
|
+
@variables.setter
|
36
|
+
def variables(self, value):
|
37
|
+
"""Set the variables used in this condition"""
|
38
|
+
self._variables = value
|
39
|
+
|
40
|
+
@property
|
41
|
+
def z3_expr(self):
|
42
|
+
"""Get the Z3 expression for this condition"""
|
43
|
+
return self._z3_expr
|
44
|
+
|
45
|
+
@z3_expr.setter
|
46
|
+
def z3_expr(self, value):
|
47
|
+
"""Set the Z3 expression for this condition"""
|
48
|
+
self._z3_expr = value
|
49
|
+
|
50
|
+
def __str__(self):
|
51
|
+
"""Return a string representation of this branch condition"""
|
52
|
+
condition_text = ast.unparse(self.condition_ast) if self.condition_ast else "None"
|
53
|
+
vars_text = ", ".join(sorted(self.variables)) if self.variables else "None"
|
54
|
+
z3_text = str(self.z3_expr) if self.z3_expr else "None"
|
55
|
+
|
56
|
+
return (f"BranchCondition(line={self.line_number}, "
|
57
|
+
f"condition='{condition_text}', "
|
58
|
+
f"variables=[{vars_text}], "
|
59
|
+
f"z3_expr={z3_text})")
|
60
|
+
|
61
|
+
def __repr__(self):
|
62
|
+
"""Return a string representation for debugging"""
|
63
|
+
return self.__str__()
|
64
|
+
|
65
|
+
def to_dict(self):
|
66
|
+
"""Convert this branch condition to a dictionary"""
|
67
|
+
return {
|
68
|
+
'line_number': self.line_number,
|
69
|
+
'condition': ast.unparse(self.condition_ast) if self.condition_ast else None,
|
70
|
+
'variables': sorted(list(self.variables)) if self.variables else [],
|
71
|
+
'z3_expr': str(self.z3_expr) if self.z3_expr else None
|
72
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import ast
|
2
|
+
from _ast import FunctionDef
|
3
|
+
from typing import List, Tuple
|
4
|
+
from testgen.util.z3_utils.branch_condition import BranchCondition
|
5
|
+
from testgen.util.z3_utils.variable_finder import VariableFinder
|
6
|
+
|
7
|
+
class ConstraintExtractor(ast.NodeVisitor):
|
8
|
+
def __init__(self):
|
9
|
+
self.branch_conditions = []
|
10
|
+
self.current_function = None
|
11
|
+
self.param_types = {}
|
12
|
+
|
13
|
+
def visit_FunctionDef(self, node: FunctionDef):
|
14
|
+
prev_function = self.current_function
|
15
|
+
self.current_function = node.name
|
16
|
+
|
17
|
+
for arg in node.args.args:
|
18
|
+
if arg.arg != 'self' and arg.annotation:
|
19
|
+
self.param_types[arg.arg] = ast.unparse(arg.annotation)
|
20
|
+
|
21
|
+
self.generic_visit(node)
|
22
|
+
self.current_function = prev_function
|
23
|
+
|
24
|
+
def visit_If(self, node):
|
25
|
+
variable_finder = VariableFinder()
|
26
|
+
variable_finder.visit(node.test)
|
27
|
+
variables = variable_finder.variables
|
28
|
+
|
29
|
+
self.branch_conditions.append(BranchCondition(node.test, node.test.lineno, variables))
|
30
|
+
|
31
|
+
self.generic_visit(node)
|
32
|
+
|
33
|
+
def extract_branch_conditions(func_node: ast.FunctionDef) -> Tuple[List[BranchCondition], dict]:
|
34
|
+
extractor = ConstraintExtractor()
|
35
|
+
extractor.visit(func_node)
|
36
|
+
return extractor.branch_conditions, extractor.param_types
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import ast
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
import z3
|
5
|
+
|
6
|
+
import testgen.util.file_utils
|
7
|
+
from testgen.models.test_case import TestCase
|
8
|
+
from testgen.util.z3_utils import ast_to_z3
|
9
|
+
from testgen.util.z3_utils.constraint_extractor import extract_branch_conditions
|
10
|
+
|
11
|
+
|
12
|
+
def solve_branch_condition(file_name: str, func_node: ast.FunctionDef, uncovered_lines: List[int]) -> List[TestCase]:
|
13
|
+
branch_conditions, param_types = extract_branch_conditions(func_node)
|
14
|
+
uncovered_conditions = [bc for bc in branch_conditions if bc.line_number in uncovered_lines]
|
15
|
+
test_cases = []
|
16
|
+
|
17
|
+
for branch_condition in uncovered_conditions:
|
18
|
+
z3_expr, z3_vars = ast_to_z3.ast_to_z3_constraint(branch_condition, param_types)
|
19
|
+
solver = z3.Solver()
|
20
|
+
solver.add(z3_expr)
|
21
|
+
|
22
|
+
if solver.check() == z3.sat:
|
23
|
+
model = solver.model()
|
24
|
+
|
25
|
+
# Create default values for all parameters
|
26
|
+
param_values = {}
|
27
|
+
for param_name in param_types:
|
28
|
+
# Set default values based on type
|
29
|
+
if param_types[param_name] == "int":
|
30
|
+
param_values[param_name] = 0
|
31
|
+
elif param_types[param_name] == "float":
|
32
|
+
param_values[param_name] = 0.0
|
33
|
+
elif param_types[param_name] == "bool":
|
34
|
+
param_values[param_name] = False
|
35
|
+
elif param_types[param_name] == "str":
|
36
|
+
param_values[param_name] = ""
|
37
|
+
else:
|
38
|
+
param_values[param_name] = None
|
39
|
+
|
40
|
+
# Update with model values where available
|
41
|
+
for var_name, z3_var in z3_vars.items():
|
42
|
+
if var_name in param_types and z3_var in model:
|
43
|
+
try:
|
44
|
+
if param_types[var_name] == "int":
|
45
|
+
param_values[var_name] = model[z3_var].as_long()
|
46
|
+
elif param_types[var_name] == "float":
|
47
|
+
param_values[var_name] = float(model[z3_var].as_decimal())
|
48
|
+
elif param_types[var_name] == "bool":
|
49
|
+
param_values[var_name] = z3.is_true(model[z3_var])
|
50
|
+
elif param_types[var_name] == "str":
|
51
|
+
param_values[var_name] = str(model[z3_var])
|
52
|
+
else:
|
53
|
+
param_values[var_name] = model[z3_var].as_long()
|
54
|
+
except Exception as e:
|
55
|
+
print(f"Error converting Z3 model value for {var_name}: {e}")
|
56
|
+
|
57
|
+
# Ensure all parameters are included in correct order
|
58
|
+
ordered_params = []
|
59
|
+
for arg in func_node.args.args:
|
60
|
+
arg_name = arg.arg
|
61
|
+
if arg_name == 'self': # Skip self parameter for class methods
|
62
|
+
continue
|
63
|
+
if arg_name in param_values:
|
64
|
+
ordered_params.append(param_values[arg_name])
|
65
|
+
else:
|
66
|
+
print(f"Warning: Missing value for parameter {arg_name}")
|
67
|
+
# Provide default values based on annotation if available
|
68
|
+
if hasattr(arg, 'annotation') and arg.annotation:
|
69
|
+
if isinstance(arg.annotation, ast.Name):
|
70
|
+
if arg.annotation.id == 'int':
|
71
|
+
ordered_params.append(0)
|
72
|
+
elif arg.annotation.id == 'float':
|
73
|
+
ordered_params.append(0.0)
|
74
|
+
elif arg.annotation.id == 'bool':
|
75
|
+
ordered_params.append(False)
|
76
|
+
elif arg.annotation.id == 'str':
|
77
|
+
ordered_params.append('')
|
78
|
+
else:
|
79
|
+
ordered_params.append(None)
|
80
|
+
else:
|
81
|
+
ordered_params.append(None)
|
82
|
+
else:
|
83
|
+
ordered_params.append(None)
|
84
|
+
|
85
|
+
func_name = func_node.name
|
86
|
+
try:
|
87
|
+
module = testgen.util.file_utils.load_module(file_name)
|
88
|
+
func = getattr(module, func_name)
|
89
|
+
result = func(*ordered_params)
|
90
|
+
test_cases.append(TestCase(func_name, tuple(ordered_params), result))
|
91
|
+
except Exception as e:
|
92
|
+
print(f"Error executing function with Z3 solution for {func_name}: {e}")
|
93
|
+
|
94
|
+
return test_cases
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: testgenie-py
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary:
|
5
|
+
Author: cjseitz
|
6
|
+
Author-email: charlesjseitz@gmail.com
|
7
|
+
Requires-Python: >=3.10,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
13
|
+
Requires-Dist: ConfigArgParse (==1.7)
|
14
|
+
Requires-Dist: astor (==0.8.1)
|
15
|
+
Requires-Dist: atheris (==2.3.0)
|
16
|
+
Requires-Dist: coverage (==7.6.4)
|
17
|
+
Requires-Dist: klara (==0.6.3)
|
18
|
+
Requires-Dist: pytest (>=8.3.5,<9.0.0)
|
19
|
+
Requires-Dist: staticfg (>=0.9.5,<0.10.0)
|
20
|
+
Requires-Dist: typed-ast (==1.5.5)
|
21
|
+
Requires-Dist: z3-solver (==4.13.3.0)
|
22
|
+
Description-Content-Type: text/markdown
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
testgen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
testgen/analyzer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
testgen/analyzer/ast_analyzer.py,sha256=JmqiosxgZJm2fhNDr5VUBpKKHmf8S2HP9Jm0Xl7NnnI,6783
|
4
|
+
testgen/analyzer/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
testgen/analyzer/contracts/contract.py,sha256=6rNYJOy_2GrOhGtaXTDIOX6pTEOqo856FxG0yTc8amI,369
|
6
|
+
testgen/analyzer/contracts/no_exception_contract.py,sha256=rTWTuu5XKmvzBPD6yNAqiNehk9lbWn_Z8zFj-_djZ_w,512
|
7
|
+
testgen/analyzer/contracts/nonnull_contract.py,sha256=uurnrVptImYTVpSnu8ckdlU6c94AbiOWFoH1YnAQU0w,508
|
8
|
+
testgen/analyzer/fuzz_analyzer.py,sha256=ktkDdh3mgHjcC4ZitGo9fa9RjnGqkdehaYJeSKssWss,4299
|
9
|
+
testgen/analyzer/random_feedback_analyzer.py,sha256=S_8iRNmgNa2wIlhLZV798H5QWY9zwKpSs2MFE61uV60,13114
|
10
|
+
testgen/analyzer/reinforcement_analyzer.py,sha256=U6W7g-xDFS_P0aqxjPRnaXjGp2gOC9TMdfWaetFV7eE,3568
|
11
|
+
testgen/analyzer/test_case_analyzer.py,sha256=foHRbz9K6WAn711sXbp-smJHDjI8GTG8F2TpovLZVEo,1530
|
12
|
+
testgen/analyzer/test_case_analyzer_context.py,sha256=7umDPHBjoTaCRvZOdNynpnWsr14Gy0E2hpMBPK8mz3Q,2128
|
13
|
+
testgen/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
testgen/controller/cli_controller.py,sha256=dKtqQMGw1IYRQox5gmQr53KAxEtrhesUdvI0KJkMjBo,8242
|
15
|
+
testgen/controller/docker_controller.py,sha256=fBRJFdY5NU6ipRY7Gihs-IA-EcpSa79Xu6GVh6_eaxk,6601
|
16
|
+
testgen/docker/Dockerfile,sha256=_xr3CWP9hhBIZbf4qRzWewBUAIkXoZGAh36g3yXpAbc,513
|
17
|
+
testgen/docker/poetry.lock,sha256=Xg2WyFgruylJ51Pvfi03Hc-VDeKj3f5DhM56XIXRBpI,30057
|
18
|
+
testgen/docker/pyproject.toml,sha256=QToniOghAyI6Hp5V-OWknO3Mo7cpa_HCV5lqynYYuPA,438
|
19
|
+
testgen/generator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
+
testgen/generator/code_generator.py,sha256=V5Donxz3r3ZW56xyyldJwOuDBaX6e8NOyPc8UzllQs8,2467
|
21
|
+
testgen/generator/doctest_generator.py,sha256=Dkaf2l72ENk1mqNP3WkOnIY-iqrTHh-443AWtxzRWGY,8806
|
22
|
+
testgen/generator/generator.py,sha256=9M9zg8DO0uU5W5s9hsz2oPCL7bz7sAD087M5TYottSs,2007
|
23
|
+
testgen/generator/pytest_generator.py,sha256=ZjQKPHlizFK2yx9WabAxkW9sM-xa64d08IIQibnvwuk,3369
|
24
|
+
testgen/generator/test_generator.py,sha256=D2Y3DaWH4fdIc5_9Xrznrkm0urFfhpYxuhL81M7RRaw,710
|
25
|
+
testgen/generator/unit_test_generator.py,sha256=yXg7_A0nOR0jhOfz7yzL6C_6pwoNCwf19Bpr_RW_41I,3596
|
26
|
+
testgen/inspector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
+
testgen/inspector/inspector.py,sha256=llDy03j8cz6Bk6HwSm20B8XvR5QaSxGXyNYyQxom25E,1816
|
28
|
+
testgen/main.py,sha256=zpLLi8HtPB6p3uMTKPrsRQDREP4i-ZqrOBwroW0XekM,385
|
29
|
+
testgen/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
|
+
testgen/models/analysis_context.py,sha256=-mhw_hn26MgF6aJnmj6Hub5jfCi8gmvcf4QNM4l7G2s,1442
|
31
|
+
testgen/models/function_metadata.py,sha256=t2lNSycFamuec7q3fiabq6aVO5XN0bylEU7mdup7Ezc,1587
|
32
|
+
testgen/models/generator_context.py,sha256=V-T9i-3Ar-gdBzQqidyqBb05PTmOu2LtdQdAIX3aaGk,1693
|
33
|
+
testgen/models/test_case.py,sha256=jwodn-6fKHCh4SO2qycbrFyggCb9UlwTZ8k3RdTObDQ,216
|
34
|
+
testgen/presentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
+
testgen/presentation/cli_view.py,sha256=2fZrsvZ-Wi4j37UvogsK9_yQV5o3A20jowIr6iFRu-s,296
|
36
|
+
testgen/q_table/global_q_table.json,sha256=T1EOATQ6L9FJL8bI3HxavYBdH8l95qGC5AdiUFz2ohM,6528
|
37
|
+
testgen/reinforcement/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
testgen/reinforcement/abstract_state.py,sha256=M9Kp8fyJzsTzpyL3ca4HjjYpGXy9DRMw-IG7OgFVisY,154
|
39
|
+
testgen/reinforcement/agent.py,sha256=wvgbi-OVoVJMwhasGgsP2y1TKLiC5qjjTwZBNqKNRns,6098
|
40
|
+
testgen/reinforcement/environment.py,sha256=z9ENIkbiB0N9Dbhm8yruQeSV1h4sK0QDkDRF_IO1VtI,8601
|
41
|
+
testgen/reinforcement/statement_coverage_state.py,sha256=hyoxkpOi_vdtjuAZ3PDz_fECurqWeNjeIhtng5TARCk,1523
|
42
|
+
testgen/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
|
+
testgen/service/analysis_service.py,sha256=SvQEhwbE_lWTRrWdT70C4kbh-H2xxf0mP8zlqSX_xqI,10670
|
44
|
+
testgen/service/cfg_service.py,sha256=7QWNM7WgX6iEwAV1qJuacKEAYihHyDqsOEMlu5Z3aA0,2207
|
45
|
+
testgen/service/generator_service.py,sha256=iKDPyCDlektRDLD6pLrR0CWiAF81xezkFHGyT31mre8,6920
|
46
|
+
testgen/service/service.py,sha256=WcCf8SOYAoElwFoYFpsWfZk8V675AY0pot5-QQp7AP4,15407
|
47
|
+
testgen/sqlite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
|
+
testgen/sqlite/db.py,sha256=RUt88ndT4CQRo9aZzLGXPHRK1iw0LyDEGnoWlOLzKGM,2390
|
49
|
+
testgen/sqlite/db_service.py,sha256=i87YkhMP0VNyug5p1tWUvnzHB8isFcSIRe9vJJTmFLA,8954
|
50
|
+
testgen/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
|
+
testgen/tree/node.py,sha256=ONJtbACShN4yNj1X-UslFRgLyBP6mrbg7qZr3c6dWyA,165
|
52
|
+
testgen/tree/tree_utils.py,sha256=gT7jucky6_GWVOlDI6jpv6RMeWCkntGOHIYLvHxD85k,2122
|
53
|
+
testgen/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
|
+
testgen/util/coverage_utils.py,sha256=lmta8F-ASsZpaAOs_YucSTHNHHEn4M0rUR7eeboZtZc,6044
|
55
|
+
testgen/util/coverage_visualizer.py,sha256=rYmwV4uTo02YAVPy3KKlLyKofr3IuhytFBNanu0z6Ok,5668
|
56
|
+
testgen/util/file_utils.py,sha256=P6zzABvuTlO2EAJdgFKwNxKNF_HHD0vcSkROeHrYTbg,3699
|
57
|
+
testgen/util/randomizer.py,sha256=hAW9szYhPWyQEkn7NTFuJRRIoYcVmvnzMf3dDwWdMKM,4479
|
58
|
+
testgen/util/utils.py,sha256=_TPXveAcI_TR9XLU8qaDx63CrZJDvpzSWl_gfYchJz0,5665
|
59
|
+
testgen/util/z3_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
|
+
testgen/util/z3_utils/ast_to_z3.py,sha256=V87cvlH2OlO7_owuVTqygymMmK_FyesBovi6qe-BUcg,3180
|
61
|
+
testgen/util/z3_utils/branch_condition.py,sha256=N9FNR-iJmxIC62NpDQNVZ1OP14rXXqYzdA_NODPDUm4,2453
|
62
|
+
testgen/util/z3_utils/constraint_extractor.py,sha256=RXJLpmk6dAvHZ27839VXKXNtdy9St1F-17-pSEFu4bM,1285
|
63
|
+
testgen/util/z3_utils/variable_finder.py,sha256=dUh3F9_L_BDMz1ybiGss09LLcM_egbitgj0FT5Nh9u4,245
|
64
|
+
testgen/util/z3_utils/z3_test_case.py,sha256=cAafR5x7YMsWnqVFYU21h2jHO-SiaTDPdKe44cGQ5_M,4409
|
65
|
+
testgenie_py-0.1.0.dist-info/METADATA,sha256=Cs5-bhHuOerWHIaHz4xK84JHOQoALkFzU8xGUes08RE,764
|
66
|
+
testgenie_py-0.1.0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
67
|
+
testgenie_py-0.1.0.dist-info/entry_points.txt,sha256=K52WcOoqyoG657-9IdKsDCBS_nJyuV4BhVtGzoomkL4,39
|
68
|
+
testgenie_py-0.1.0.dist-info/RECORD,,
|