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.
Files changed (68) hide show
  1. testgen/__init__.py +0 -0
  2. testgen/analyzer/__init__.py +0 -0
  3. testgen/analyzer/ast_analyzer.py +149 -0
  4. testgen/analyzer/contracts/__init__.py +0 -0
  5. testgen/analyzer/contracts/contract.py +13 -0
  6. testgen/analyzer/contracts/no_exception_contract.py +16 -0
  7. testgen/analyzer/contracts/nonnull_contract.py +15 -0
  8. testgen/analyzer/fuzz_analyzer.py +106 -0
  9. testgen/analyzer/random_feedback_analyzer.py +291 -0
  10. testgen/analyzer/reinforcement_analyzer.py +75 -0
  11. testgen/analyzer/test_case_analyzer.py +46 -0
  12. testgen/analyzer/test_case_analyzer_context.py +58 -0
  13. testgen/controller/__init__.py +0 -0
  14. testgen/controller/cli_controller.py +194 -0
  15. testgen/controller/docker_controller.py +169 -0
  16. testgen/docker/Dockerfile +22 -0
  17. testgen/docker/poetry.lock +361 -0
  18. testgen/docker/pyproject.toml +22 -0
  19. testgen/generator/__init__.py +0 -0
  20. testgen/generator/code_generator.py +66 -0
  21. testgen/generator/doctest_generator.py +208 -0
  22. testgen/generator/generator.py +55 -0
  23. testgen/generator/pytest_generator.py +77 -0
  24. testgen/generator/test_generator.py +26 -0
  25. testgen/generator/unit_test_generator.py +84 -0
  26. testgen/inspector/__init__.py +0 -0
  27. testgen/inspector/inspector.py +61 -0
  28. testgen/main.py +13 -0
  29. testgen/models/__init__.py +0 -0
  30. testgen/models/analysis_context.py +56 -0
  31. testgen/models/function_metadata.py +61 -0
  32. testgen/models/generator_context.py +63 -0
  33. testgen/models/test_case.py +8 -0
  34. testgen/presentation/__init__.py +0 -0
  35. testgen/presentation/cli_view.py +12 -0
  36. testgen/q_table/global_q_table.json +1 -0
  37. testgen/reinforcement/__init__.py +0 -0
  38. testgen/reinforcement/abstract_state.py +7 -0
  39. testgen/reinforcement/agent.py +153 -0
  40. testgen/reinforcement/environment.py +215 -0
  41. testgen/reinforcement/statement_coverage_state.py +33 -0
  42. testgen/service/__init__.py +0 -0
  43. testgen/service/analysis_service.py +260 -0
  44. testgen/service/cfg_service.py +55 -0
  45. testgen/service/generator_service.py +169 -0
  46. testgen/service/service.py +389 -0
  47. testgen/sqlite/__init__.py +0 -0
  48. testgen/sqlite/db.py +84 -0
  49. testgen/sqlite/db_service.py +219 -0
  50. testgen/tree/__init__.py +0 -0
  51. testgen/tree/node.py +7 -0
  52. testgen/tree/tree_utils.py +79 -0
  53. testgen/util/__init__.py +0 -0
  54. testgen/util/coverage_utils.py +168 -0
  55. testgen/util/coverage_visualizer.py +154 -0
  56. testgen/util/file_utils.py +110 -0
  57. testgen/util/randomizer.py +122 -0
  58. testgen/util/utils.py +143 -0
  59. testgen/util/z3_utils/__init__.py +0 -0
  60. testgen/util/z3_utils/ast_to_z3.py +99 -0
  61. testgen/util/z3_utils/branch_condition.py +72 -0
  62. testgen/util/z3_utils/constraint_extractor.py +36 -0
  63. testgen/util/z3_utils/variable_finder.py +10 -0
  64. testgen/util/z3_utils/z3_test_case.py +94 -0
  65. testgenie_py-0.1.0.dist-info/METADATA +24 -0
  66. testgenie_py-0.1.0.dist-info/RECORD +68 -0
  67. testgenie_py-0.1.0.dist-info/WHEEL +4 -0
  68. testgenie_py-0.1.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,208 @@
1
+ import inspect
2
+ from typing import Optional, List, Set, Tuple
3
+
4
+ import astor
5
+ from testgen.generator.test_generator import TestGenerator
6
+ from testgen.models.generator_context import GeneratorContext
7
+
8
+ class DocTestGenerator(TestGenerator):
9
+ def __init__(self, generator_context: GeneratorContext):
10
+ super().__init__(generator_context)
11
+
12
+ # Implementing abstract methods from TestGenerator
13
+ def generate_test_header(self):
14
+ pass
15
+
16
+ def generate_test_function(self, unique_func_name, func_name, cases) -> None:
17
+ """Generate a test function with doctests."""
18
+ doctest_examples = []
19
+
20
+ for inputs, expected in cases:
21
+ input_args = ', '.join(map(repr, inputs))
22
+
23
+ if self._generator_context.class_name:
24
+ test_call = f"{self._generator_context.class_name}().{func_name}({input_args})"
25
+ else:
26
+ test_call = f"{func_name}({input_args})"
27
+
28
+ result_str = repr(expected)
29
+ # Format with >>> and proper spacing
30
+ doctest = f">>> {test_call}\n{result_str}"
31
+ doctest_examples.append(doctest)
32
+
33
+ # Inject the doctests into the original function's docstring
34
+ self._inject_docstring(func_name, doctest_examples)
35
+
36
+ def save_file(self):
37
+ """Save the generated test content to a file."""
38
+ return self._generator_context.filepath
39
+
40
+ def _inject_docstring(self, func_name, doctest_examples):
41
+ """Inject doctest examples into the function's docstring."""
42
+ module_path = self._generator_context.filepath
43
+
44
+ # Read the source file
45
+ with open(module_path, 'r') as f:
46
+ lines = f.readlines()
47
+
48
+ func_line_num, func_indent = self._get_func_line_num_and_indent(lines, func_name)
49
+
50
+ if func_line_num == -1:
51
+ print(f"Function {func_name} not found in {module_path}")
52
+ return
53
+
54
+ has_docstring, docstring_end = self._get_docstring_end(func_line_num, lines)
55
+
56
+ all_examples, seen_examples = self._collect_existing_docstrings(func_line_num, lines, has_docstring, docstring_end)
57
+
58
+
59
+ all_examples, seen_examples = self._add_new_docstrings(doctest_examples, all_examples, seen_examples)
60
+
61
+ docstring_lines = self._create_docstrings(func_indent, all_examples)
62
+
63
+ # Modify the source code
64
+ if has_docstring:
65
+ # Replace existing docstring
66
+ lines = lines[:func_line_num + 1] + [line + '\n' for line in docstring_lines] + lines[docstring_end + 1:]
67
+ else:
68
+ # Insert new docstring after function definition
69
+ lines = lines[:func_line_num + 1] + [line + '\n' for line in docstring_lines] + lines[func_line_num + 1:]
70
+
71
+ # Write back to the file
72
+ with open(module_path, 'w') as f:
73
+ f.writelines(lines)
74
+
75
+ def _extract_doctest_examples(self, docstring_lines: List[str]) -> List[Tuple[str, str]]:
76
+ examples = []
77
+ current_call = None
78
+ current_result_lines = []
79
+
80
+ # Process docstring line by line
81
+ for line in docstring_lines:
82
+ stripped_line = line.strip()
83
+
84
+ # Check if this is a test call line (starts with >>>)
85
+ if stripped_line.startswith('>>>'):
86
+ # If we were already collecting a test, save it
87
+ if current_call is not None:
88
+ result = '\n'.join([line.strip() for line in current_result_lines if line.strip()])
89
+ examples.append((current_call, result))
90
+ current_result_lines = []
91
+
92
+ # Extract the call part (everything after >>>)
93
+ current_call = stripped_line[3:].strip()
94
+
95
+ # Otherwise, if we have a current call, add to the result
96
+ elif current_call is not None:
97
+ current_result_lines.append(stripped_line)
98
+
99
+ # Don't forget the last example if there is one
100
+ if current_call is not None and current_result_lines:
101
+ result = '\n'.join([line.strip() for line in current_result_lines if line.strip()])
102
+ examples.append((current_call, result))
103
+
104
+ return examples
105
+
106
+
107
+ def _is_class_method(self, function_name: str) -> bool:
108
+ """Check if a function is a method of a class in the module."""
109
+ for name, obj in inspect.getmembers(self._generator_context.module):
110
+ if inspect.isclass(obj) and hasattr(obj, function_name):
111
+ return True
112
+ return False
113
+
114
+ def _get_class_name(self, method_name: str) -> Optional[str]:
115
+ """Get the name of the class that contains the method."""
116
+ for name, obj in inspect.getmembers(self._generator_context.module):
117
+ if inspect.isclass(obj) and hasattr(obj, method_name):
118
+ return name
119
+ return None
120
+
121
+ def _get_func_line_num_and_indent(self, lines: List[str], func_name: str) -> Tuple[int, str]:
122
+ func_line_num = -1
123
+ func_indent = ""
124
+
125
+ for i, line in enumerate(lines):
126
+ line_stripped = line.lstrip()
127
+ if line_stripped.startswith('def '):
128
+ # Extract function name
129
+ potential_name = line_stripped[4:].split('(')[0].strip()
130
+ if potential_name == func_name:
131
+ func_line_num = i
132
+ # Calculate indentation by counting spaces before 'def'
133
+ func_indent = line[:len(line) - len(line_stripped)]
134
+ break
135
+ return (func_line_num, func_indent)
136
+
137
+ def _get_docstring_end(self, func_line_num: int, lines: List[str]) -> Tuple[bool, int]:
138
+ has_docstring = False
139
+ docstring_end = -1
140
+
141
+ if func_line_num + 1 < len(lines) and '"""' in lines[func_line_num + 1]:
142
+ has_docstring = True
143
+ # Find the end of the docstring
144
+ for i in range(func_line_num + 2, len(lines)):
145
+ if '"""' in lines[i]:
146
+ docstring_end = i
147
+ break
148
+ return (has_docstring, docstring_end)
149
+
150
+ def _create_docstrings(self, func_indent: int, all_examples: List[str]) -> List[str]:
151
+ # Create the new docstring with all examples
152
+ docstring_lines = []
153
+ docstring_lines.append(func_indent + ' """')
154
+
155
+ # Add all examples with consistent indentation
156
+ for i, example in enumerate(all_examples):
157
+ # Split example into lines
158
+ example_lines = example.split('\n')
159
+
160
+ # Add each line with proper indentation
161
+ for j, line in enumerate(example_lines):
162
+ docstring_lines.append(func_indent + ' ' + line)
163
+
164
+ # Add blank line between examples (not after the last one)
165
+ if i < len(all_examples) - 1:
166
+ docstring_lines.append('')
167
+
168
+ # Close the docstring
169
+ docstring_lines.append(func_indent + ' """')
170
+ return docstring_lines
171
+
172
+ def _collect_existing_docstrings(self, func_line_num: int, lines: List[str], has_docstring: bool, docstring_end: int) -> Tuple[List[str], Set[str]]:
173
+ # Collect all examples (existing)
174
+ all_examples = []
175
+ seen_examples = set()
176
+
177
+ if has_docstring and docstring_end > 0:
178
+ # Extract existing examples from docstring
179
+ existing_examples = self._extract_doctest_examples(lines[func_line_num + 2:docstring_end])
180
+
181
+ for call, result in existing_examples:
182
+ # Create normalized example
183
+ example = f">>> {call}\n{result}"
184
+
185
+ if example not in seen_examples:
186
+ all_examples.append(example)
187
+ seen_examples.add(example)
188
+
189
+ return (all_examples, seen_examples)
190
+
191
+ def _add_new_docstrings(self, doctest_examples: List[str], all_examples: List[str], seen_examples: Set[str]) -> Tuple[List[str], Set[str]]:
192
+ # Add new examples
193
+ for example in doctest_examples:
194
+ # Normalize the example format
195
+ parts = example.split('\n', 1)
196
+ if len(parts) == 2:
197
+ call_line, result = parts
198
+ call = call_line[4:].strip() # Remove >>> prefix and whitespace
199
+ result = result.strip()
200
+
201
+ # Create normalized example
202
+ normalized_example = f">>> {call}\n{result}"
203
+
204
+ if normalized_example not in seen_examples:
205
+ all_examples.append(normalized_example)
206
+ seen_examples.add(normalized_example)
207
+
208
+ return (all_examples, seen_examples)
@@ -0,0 +1,55 @@
1
+ from typing import List
2
+ from testgen.tree.node import Node
3
+ from testgen.tree.tree_utils import apply_operation
4
+
5
+
6
+ class CodeGenerator:
7
+
8
+ def __init__(self):
9
+ self = self
10
+
11
+ def generate_code_from_tree(self, func_name: str, root: Node, params: List[str], operation) -> str:
12
+ def traverse(node, depth, path=[], indent_level=1):
13
+ base_indent = " " * indent_level
14
+
15
+ if depth == len(params):
16
+ path = path + [node.value]
17
+ result = operation(self, *path)
18
+ return f"{base_indent}return {result}\n"
19
+
20
+ param = params[depth]
21
+
22
+ if isinstance(node.value, bool):
23
+ path = path + [node.value]
24
+
25
+ true_branch = f"{base_indent}if {param} == True:\n"
26
+ false_branch = f"{base_indent}else:\n"
27
+
28
+ true_code = traverse(node.children[0], depth + 1, path, indent_level + 1)
29
+ false_code = traverse(node.children[1], depth + 1, path, indent_level + 1)
30
+
31
+ return f"{true_branch}{true_code}{false_branch}{false_code}"
32
+
33
+ function_code = f"def {func_name}_generated_function({', '.join(params)}):\n"
34
+ body_code = traverse(root, 0)
35
+
36
+ return function_code + body_code
37
+
38
+ def generate_class(self, class_name):
39
+ branched_class_name = f"Generated{class_name}"
40
+ file_path = f"generated_{class_name.lower()}.py"
41
+ class_file = open(f"{file_path}", "w")
42
+ class_file.write(f"class {branched_class_name}:\n")
43
+ return class_file
44
+
45
+ """def generate_all_functions_code(self, class_name, operation):
46
+ functions = self.inspect_class(class_name)
47
+ trees = self.build_func_trees(functions)
48
+ all_functions_code = {}
49
+
50
+ for func, root, params in trees:
51
+ code = self.generate_code_from_tree(root, params, operation)
52
+ all_functions_code[func.__name__] = code
53
+ print(f"Generated code for function '{func.__name__}':\n{code}\n")
54
+
55
+ return all_functions_code"""
@@ -0,0 +1,77 @@
1
+ from testgen.generator.test_generator import TestGenerator
2
+ from testgen.util.file_utils import get_import_info
3
+ from testgen.models.generator_context import GeneratorContext
4
+
5
+
6
+ class PyTestGenerator(TestGenerator):
7
+ def __init__(self, generator_context: GeneratorContext):
8
+ super().__init__(generator_context)
9
+ self.test_code = []
10
+
11
+ def generate_test_header(self):
12
+ self.test_code.append("import pytest\n")
13
+ import_info = get_import_info(self._generator_context.filepath)
14
+ if self._generator_context.class_name == "" or self._generator_context.class_name is None:
15
+ if import_info['is_package']:
16
+ self.test_code.append(f"import {import_info['import_path']} as {self._generator_context.module.__name__}\n")
17
+ else:
18
+ self.test_code.append(f"import {import_info['import_path']} as {self._generator_context.module.__name__}\n")
19
+ else:
20
+ if import_info['is_package']:
21
+ self.test_code.append(f"from {import_info['import_path']} import {self._generator_context.class_name}\n")
22
+ else:
23
+ self.test_code.append(f"from {import_info['import_path']} import {self._generator_context.class_name}\n")
24
+
25
+ def generate_test_function(self, unique_func_name, func_name, cases):
26
+ self.test_code.append(f"def test_{unique_func_name}():")
27
+ for inputs, expected in cases:
28
+ args_str: str = self.generate_args_statement(inputs)
29
+ expected_str: str = self.generate_expected_statement(expected)
30
+ is_class: bool = self._generator_context.class_name != "" and self._generator_context.class_name is not None
31
+ class_or_mod_name: str = self.generate_class_or_mod_name(is_class)
32
+ result_statement: str = self.generate_result_statement(class_or_mod_name, func_name, inputs)
33
+ assert_statement: str = self.generate_assert_statement()
34
+
35
+ self.test_code.append(args_str)
36
+ self.test_code.append(expected_str)
37
+ self.test_code.append(result_statement)
38
+ self.test_code.append(assert_statement)
39
+
40
+ def save_file(self):
41
+ with open(self._generator_context.output_path, "w") as f:
42
+ f.write("\n".join(self.test_code))
43
+
44
+
45
+ def generate_class_or_mod_name(self, is_class: bool) -> str:
46
+ if is_class:
47
+ return f"{self._generator_context.class_name}()"
48
+ else:
49
+ return f"{self._generator_context.module.__name__}"
50
+
51
+ @staticmethod
52
+ def generate_args_statement(inputs) -> str:
53
+ input_args = ', '.join(map(repr, inputs))
54
+ if len(inputs) == 1:
55
+ return f" args = {input_args}"
56
+ else:
57
+ return f" args = ({input_args})"
58
+
59
+ @staticmethod
60
+ def generate_expected_statement(expected) -> str:
61
+ if isinstance(expected, str):
62
+ return f" expected = '{expected}'"
63
+ else:
64
+ return f" expected = {expected}"
65
+
66
+
67
+ @staticmethod
68
+ def generate_result_statement(class_or_mod_name, func_name, inputs) -> str:
69
+ if len(inputs) == 1:
70
+ return f" result = {class_or_mod_name}.{func_name}(args)"
71
+ else:
72
+ return f" result = {class_or_mod_name}.{func_name}(*args)"
73
+
74
+ @staticmethod
75
+ def generate_assert_statement() -> str:
76
+ return f" assert result == expected\n"
77
+
@@ -0,0 +1,26 @@
1
+ from abc import ABC, abstractmethod
2
+ from testgen.models.generator_context import GeneratorContext
3
+
4
+ class TestGenerator(ABC):
5
+ def __init__(self, generator_context: GeneratorContext):
6
+ self._generator_context = generator_context
7
+
8
+ @property
9
+ def generator_context(self) -> GeneratorContext:
10
+ return self._generator_context
11
+
12
+ @generator_context.setter
13
+ def generator_context(self, value: GeneratorContext):
14
+ self._generator_context = value
15
+
16
+ @abstractmethod
17
+ def generate_test_header(self):
18
+ pass
19
+
20
+ @abstractmethod
21
+ def generate_test_function(self, unique_func_name, func_name, cases):
22
+ pass
23
+
24
+ @abstractmethod
25
+ def save_file(self):
26
+ pass
@@ -0,0 +1,84 @@
1
+ from testgen.util.file_utils import get_import_info
2
+ from testgen.generator.test_generator import TestGenerator
3
+ from testgen.models.generator_context import GeneratorContext
4
+
5
+ AST_STRAT = 1
6
+ FUZZ_STRAT = 2
7
+ RANDOM_STRAT = 3
8
+
9
+ class UnitTestGenerator(TestGenerator):
10
+ def __init__(self, generator_context: GeneratorContext):
11
+ super().__init__(generator_context)
12
+ self.test_code = []
13
+
14
+ def generate_test_header(self):
15
+
16
+ import_info = get_import_info(self._generator_context.filepath)
17
+
18
+ self.test_code.append("import unittest\n")
19
+ if self._generator_context.class_name == "" or self._generator_context.class_name is None:
20
+ if import_info['is_package']:
21
+ self.test_code.append(f"import {import_info['import_path']} as {self._generator_context.module.__name__}\n")
22
+ else:
23
+ self.test_code.append(f"import {import_info['import_path']} as {self._generator_context.module.__name__}\n")
24
+ else:
25
+ if import_info['is_package']:
26
+ self.test_code.append(f"from {import_info['import_path']} import {self._generator_context.class_name}\n")
27
+ else:
28
+ self.test_code.append(f"from {import_info['import_path']} import {self._generator_context.class_name}\n")
29
+ self.test_code.append(f"class Test{self._generator_context.class_name}(unittest.TestCase): \n")
30
+
31
+ def generate_test_function(self, unique_func_name, func_name, cases):
32
+ print(f"Cases: {cases}")
33
+ self.test_code.append(f" def test_{unique_func_name}(self):")
34
+ for inputs, expected in cases:
35
+ args_str: str = self.generate_args_statement(inputs)
36
+ expected_str: str = self.generate_expected_statement(expected)
37
+ is_class: bool = self._generator_context.class_name != "" and self._generator_context.class_name is not None
38
+ class_or_mod_name: str = self.generate_class_or_mod_name(is_class)
39
+ result_statement: str = self.generate_result_statement(class_or_mod_name, func_name, inputs)
40
+ assert_statement: str = self.generate_assert_statement()
41
+
42
+
43
+ self.test_code.append(args_str)
44
+ self.test_code.append(expected_str)
45
+ self.test_code.append(result_statement)
46
+ self.test_code.append(assert_statement)
47
+
48
+ def save_file(self):
49
+ with open(self._generator_context.output_path, "w") as f:
50
+ f.write("\n".join(self.test_code))
51
+
52
+ def generate_class_or_mod_name(self, is_class: bool) -> str:
53
+ if is_class:
54
+ return f"{self._generator_context.class_name}()"
55
+ else:
56
+ return f"{self._generator_context.module.__name__}"
57
+
58
+ @staticmethod
59
+ def generate_args_statement(inputs) -> str:
60
+ input_args = ', '.join(map(repr, inputs))
61
+ if len(inputs) == 1:
62
+ return f" args = {input_args}"
63
+ else:
64
+ return f" args = ({input_args})"
65
+
66
+ @staticmethod
67
+ def generate_expected_statement(expected) -> str:
68
+ if isinstance(expected, str):
69
+ return f" expected = '{expected}'"
70
+ else:
71
+ return f" expected = {expected}"
72
+
73
+
74
+ @staticmethod
75
+ def generate_result_statement(class_or_mod_name, func_name, inputs) -> str:
76
+ if len(inputs) == 1:
77
+ return f" result = {class_or_mod_name}.{func_name}(args)"
78
+ else:
79
+ return f" result = {class_or_mod_name}.{func_name}(*args)"
80
+
81
+ @staticmethod
82
+ def generate_assert_statement() -> str:
83
+ return f" self.assertEqual(result, expected)\n"
84
+
File without changes
@@ -0,0 +1,61 @@
1
+ from ast import FunctionType
2
+ import inspect
3
+ from testgen.code_to_test import sample_code_bin
4
+
5
+
6
+ class Inspector:
7
+
8
+ @staticmethod
9
+ def get_functions(file):
10
+ return inspect.getmembers(file, inspect.isfunction)
11
+
12
+ @staticmethod
13
+ def get_signature(func: FunctionType):
14
+ return inspect.signature(func)
15
+
16
+ @staticmethod
17
+ def get_code(func: FunctionType):
18
+ return inspect.getsource(func)
19
+
20
+ @staticmethod
21
+ def get_params(sig: inspect.Signature):
22
+ return sig.parameters
23
+
24
+ @staticmethod
25
+ def get_params_not_self(sig: inspect.Signature):
26
+ params = sig.parameters
27
+ return [param for param, value in params.items() if param != 'self']
28
+
29
+ def func_inspect(self) -> list[tuple]:
30
+ test_cases: list[tuple] = []
31
+
32
+ functions = inspect.getmembers(sample_code_bin, inspect.isfunction)
33
+
34
+ for name, func in functions:
35
+ print(f"Function Name: {name}")
36
+ signature = inspect.signature(func)
37
+ print(f"Signature: {signature}")
38
+ for param in signature.parameters:
39
+ print(f"Param: {param}")
40
+ print(f"Function Code: {inspect.getsource(func)}")
41
+
42
+ docstring: str = inspect.getdoc(func)
43
+ print(f"Docstring: {docstring}")
44
+
45
+ cases: list[str] = docstring.split(",")
46
+
47
+ for case in cases:
48
+ io: list[str] = case.split("-")
49
+ input: str = io[0][7:].strip()
50
+ output: str = io[1][8:].strip()
51
+ print(f"Input: {input}")
52
+ print(f"Output: {output}")
53
+ test_cases.append((name, (input, output)))
54
+
55
+ return test_cases
56
+
57
+
58
+ if __name__ == "__main__":
59
+ inspector = Inspector()
60
+ test_cases = inspector.func_inspect()
61
+ print(f"Collected Test Cases: {test_cases}")
testgen/main.py ADDED
@@ -0,0 +1,13 @@
1
+ from testgen.service.service import Service
2
+ from testgen.controller.cli_controller import CLIController
3
+ from testgen.generator.unit_test_generator import UnitTestGenerator
4
+ from testgen.presentation.cli_view import CLIView
5
+
6
+ def main():
7
+ service = Service()
8
+ view = CLIView()
9
+ controller = CLIController(service, view)
10
+ controller.run()
11
+
12
+ if __name__ == '__main__':
13
+ main()
File without changes
@@ -0,0 +1,56 @@
1
+ from types import ModuleType
2
+ from typing import List
3
+
4
+ from testgen.models.function_metadata import FunctionMetadata
5
+
6
+
7
+ class AnalysisContext:
8
+ def __init__(self, filepath: str, filename: str, class_name: str, module: ModuleType, function_data: List[FunctionMetadata] = None):
9
+ self._filepath: str = filepath
10
+ self._filename: str = filename
11
+ self._class_name: str = class_name
12
+ self._module: ModuleType = module
13
+ self._function_data: List[FunctionMetadata] = function_data
14
+
15
+ @property
16
+ def filepath(self) -> str:
17
+ return self._filepath
18
+
19
+ @filepath.setter
20
+ def filepath(self, value: str):
21
+ self._filepath = value
22
+
23
+ @property
24
+ def filename(self) -> str:
25
+ return self._filename
26
+
27
+ @filename.setter
28
+ def filename(self, value: str):
29
+ self._filename = value
30
+
31
+ @property
32
+ def class_name(self) -> str:
33
+ return self._class_name
34
+
35
+ @class_name.setter
36
+ def class_name(self, value: str):
37
+ self._class_name = value
38
+
39
+ @property
40
+ def module(self) -> ModuleType:
41
+ return self._module
42
+
43
+ @module.setter
44
+ def module(self, value: ModuleType):
45
+ self._module = value
46
+
47
+ @property
48
+ def function_data(self) -> List[FunctionMetadata]:
49
+ return self._function_data
50
+
51
+ @function_data.setter
52
+ def function_data(self, value: List[FunctionMetadata]):
53
+ self._function_data = value
54
+
55
+
56
+
@@ -0,0 +1,61 @@
1
+ import ast
2
+ from types import ModuleType
3
+
4
+
5
+ class FunctionMetadata:
6
+ def __init__(self, filename: str, module: ModuleType, class_name: str, function_name: str, func_def: ast.FunctionDef, params: dict):
7
+ self._filename: str = filename
8
+ self._module: ModuleType = module
9
+ self._class_name: str = class_name
10
+ self._function_name: str = function_name
11
+ self._func_def: ast.FunctionDef = func_def
12
+ self._params: dict = params
13
+
14
+ @property
15
+ def filename(self) -> str:
16
+ return self._filename
17
+
18
+ @filename.setter
19
+ def filename(self, filename: str):
20
+ self._filename = filename
21
+
22
+ @property
23
+ def module(self) -> ModuleType:
24
+ return self._module
25
+
26
+ @module.setter
27
+ def module(self, module: ModuleType):
28
+ self._module = module
29
+
30
+ @property
31
+ def class_name(self) -> str:
32
+ return self._class_name
33
+
34
+ @class_name.setter
35
+ def class_name(self, class_name: str):
36
+ self._class_name = class_name
37
+
38
+ @property
39
+ def function_name(self) -> str:
40
+ return self._function_name
41
+
42
+ @function_name.setter
43
+ def function_name(self, func_name: str):
44
+ self._function_name = func_name
45
+
46
+ @property
47
+ def func_def(self) -> ast.FunctionDef:
48
+ return self._func_def
49
+
50
+ @func_def.setter
51
+ def func_def(self, func_def: ast.FunctionDef):
52
+ self._func_def = func_def
53
+
54
+ @property
55
+ def params(self) -> dict:
56
+ return self._params
57
+
58
+ @params.setter
59
+ def params(self, params: dict):
60
+ self._params = params
61
+