testgenie-py 0.2.0__tar.gz → 0.2.1__tar.gz

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 (83) hide show
  1. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/PKG-INFO +1 -1
  2. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/pyproject.toml +1 -1
  3. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/.coverage +0 -0
  4. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/controller/docker_controller.py +56 -38
  5. testgenie_py-0.2.1/testgen/docker/Dockerfile +31 -0
  6. testgenie_py-0.2.1/testgen/tests/test_boolean.py +69 -0
  7. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/file_utils.py +40 -10
  8. testgenie_py-0.2.0/testgen/docker/Dockerfile +0 -22
  9. testgenie_py-0.2.0/testgen/docker/poetry.lock +0 -599
  10. testgenie_py-0.2.0/testgen/docker/pyproject.toml +0 -29
  11. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/README.md +0 -0
  12. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/__init__.py +0 -0
  13. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/__init__.py +0 -0
  14. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/ast_analyzer.py +0 -0
  15. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/contracts/__init__.py +0 -0
  16. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/contracts/contract.py +0 -0
  17. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/contracts/no_exception_contract.py +0 -0
  18. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/contracts/nonnull_contract.py +0 -0
  19. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/fuzz_analyzer.py +0 -0
  20. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/random_feedback_analyzer.py +0 -0
  21. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/reinforcement_analyzer.py +0 -0
  22. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/test_case_analyzer.py +0 -0
  23. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/analyzer/test_case_analyzer_context.py +0 -0
  24. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/__init__.py +0 -0
  25. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/boolean.py +0 -0
  26. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/calculator.py +0 -0
  27. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/code_to_fuzz.py +0 -0
  28. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/code_to_fuzz_lite.py +0 -0
  29. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/decisions.py +0 -0
  30. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/math_utils.py +0 -0
  31. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/no_types.py +0 -0
  32. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/code_to_test/sample_code_bin.py +0 -0
  33. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/controller/__init__.py +0 -0
  34. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/controller/cli_controller.py +0 -0
  35. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/__init__.py +0 -0
  36. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/code_generator.py +0 -0
  37. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/doctest_generator.py +0 -0
  38. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/generator.py +0 -0
  39. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/pytest_generator.py +0 -0
  40. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/test_generator.py +0 -0
  41. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/generator/unit_test_generator.py +0 -0
  42. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/inspector/__init__.py +0 -0
  43. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/inspector/inspector.py +0 -0
  44. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/main.py +0 -0
  45. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/models/__init__.py +0 -0
  46. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/models/analysis_context.py +0 -0
  47. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/models/function_metadata.py +0 -0
  48. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/models/generator_context.py +0 -0
  49. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/models/test_case.py +0 -0
  50. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/presentation/__init__.py +0 -0
  51. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/presentation/cli_view.py +0 -0
  52. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/q_table/global_q_table.json +0 -0
  53. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/reinforcement/__init__.py +0 -0
  54. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/reinforcement/abstract_state.py +0 -0
  55. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/reinforcement/agent.py +0 -0
  56. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/reinforcement/environment.py +0 -0
  57. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/reinforcement/statement_coverage_state.py +0 -0
  58. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/__init__.py +0 -0
  59. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/analysis_service.py +0 -0
  60. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/cfg_service.py +0 -0
  61. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/generator_service.py +0 -0
  62. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/logging_service.py +0 -0
  63. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/service/service.py +0 -0
  64. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/sqlite/__init__.py +0 -0
  65. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/sqlite/db.py +0 -0
  66. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/sqlite/db_service.py +0 -0
  67. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/testgen.db +0 -0
  68. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/tests/__init__.py +0 -0
  69. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/tests/test_decisions.py +0 -0
  70. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/tree/__init__.py +0 -0
  71. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/tree/node.py +0 -0
  72. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/tree/tree_utils.py +0 -0
  73. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/__init__.py +0 -0
  74. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/coverage_utils.py +0 -0
  75. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/coverage_visualizer.py +0 -0
  76. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/randomizer.py +0 -0
  77. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/utils.py +0 -0
  78. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/__init__.py +0 -0
  79. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/ast_to_z3.py +0 -0
  80. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/branch_condition.py +0 -0
  81. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/constraint_extractor.py +0 -0
  82. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/variable_finder.py +0 -0
  83. {testgenie_py-0.2.0 → testgenie_py-0.2.1}/testgen/util/z3_utils/z3_test_case.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: testgenie-py
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary:
5
5
  Author: cjseitz
6
6
  Author-email: charlesjseitz@gmail.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "testgenie-py"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = ""
5
5
  authors = ["cjseitz <charlesjseitz@gmail.com>"]
6
6
  readme = "README.md"
@@ -30,6 +30,7 @@ class DockerController:
30
30
  def run_in_docker(self, project_root: str, docker_client: DockerClient, args: Namespace) -> bool:
31
31
  self.args = args
32
32
  self.debug_mode = True if args.debug else False
33
+
33
34
  os.environ["RUNNING_IN_DOCKER"] = "1"
34
35
 
35
36
  # Check if Docker image exists, build it if not
@@ -41,6 +42,7 @@ class DockerController:
41
42
  return False
42
43
 
43
44
  docker_args = [args.file_path] + [arg for arg in sys.argv[2:] if arg != "--safe"]
45
+ docker_args[0] = f"/controller/testgen/code_to_test/{os.path.basename(docker_args[0])}"
44
46
 
45
47
  # Run the container with the same arguments
46
48
  try:
@@ -51,48 +53,44 @@ class DockerController:
51
53
  logs_output = self.get_logs(container)
52
54
  self.debug(logs_output)
53
55
 
54
- try:
55
- # Create the target directory if it doesn't exist
56
- if args.output is None:
57
- target_path = os.path.join(os.getcwd(), 'tests')
58
- else:
59
- target_path = args.output
60
- os.makedirs(target_path, exist_ok=True)
56
+ except Exception as e:
57
+ print(f"Error running container: {e}")
58
+ sys.exit(1)
61
59
 
62
- self.debug(f"SERVICE target path after logs: {target_path}")
60
+ # Create the target directory if it doesn't exist
61
+ if args.output is None:
62
+ target_path = os.path.join(os.getcwd(), 'tests')
63
+ else:
64
+ target_path = args.output
65
+ os.makedirs(target_path, exist_ok=True)
63
66
 
64
- test_cases = self.service.parse_test_cases_from_logs(logs_output)
67
+ self.debug(f"SERVICE target path after logs: {target_path}")
65
68
 
66
- print(f"Extracted {len(test_cases)} test cases from container.")
69
+ test_cases = self.service.parse_test_cases_from_logs(logs_output)
67
70
 
68
- file_path = os.path.abspath(args.file_path)
69
- self.debug(f"Filepath in CLI CONTROLLER: {file_path}")
70
- self.service.set_file_path(file_path)
71
+ print(f"Extracted {len(test_cases)} test cases from container.")
71
72
 
72
- if args.test_format == "pytest":
73
- self.service.set_test_generator_format(PYTEST_FORMAT)
74
- elif args.test_format == "doctest":
75
- self.service.set_test_generator_format(DOCTEST_FORMAT)
76
- else:
77
- self.service.set_test_generator_format(UNITTEST_FORMAT)
73
+ file_path = os.path.abspath(args.file_path)
74
+ self.debug(f"Filepath in CLI CONTROLLER: {file_path}")
75
+ self.service.set_file_path(file_path)
78
76
 
79
- test_file = self.service.generate_test_file(test_cases, target_path)
80
- print(f"Unit tests saved to: {test_file}")
77
+ if args.test_format == "pytest":
78
+ self.service.set_test_generator_format(PYTEST_FORMAT)
79
+ elif args.test_format == "doctest":
80
+ self.service.set_test_generator_format(DOCTEST_FORMAT)
81
+ else:
82
+ self.service.set_test_generator_format(UNITTEST_FORMAT)
81
83
 
82
- if not args.generate_only:
83
- print("Running coverage...")
84
- self.service.run_coverage(test_file)
85
-
86
- # Add explicit return True here
87
- return True
84
+ test_file = self.service.generate_test_file(test_cases, target_path)
85
+ print(f"Unit tests saved to: {test_file}")
88
86
 
89
- except Exception as e:
90
- print(f"Error running container: {e}")
91
- sys.exit(1)
87
+ if not args.generate_only:
88
+ print("Running coverage...")
89
+ self.service.run_coverage(test_file)
90
+
91
+ # Add explicit return True here
92
+ return True
92
93
 
93
- except Exception as e:
94
- print(f"Error running container: {e}")
95
- sys.exit(1)
96
94
 
97
95
  def get_image(self, docker_client: DockerClient, image_name: str, project_root: str):
98
96
  try:
@@ -129,15 +127,30 @@ class DockerController:
129
127
  # Create Docker-specific environment variables
130
128
  docker_env = {
131
129
  "RUNNING_IN_DOCKER": "1",
132
- "PYTHONPATH": "/controller",
133
- "COVERAGE_FILE": "/tmp/.coverage", # Move coverage file to /tmp
134
- "DB_PATH": "/tmp/testgen.db" # Move DB to /tmp
130
+ "PYTHONPATH": "/controller"
135
131
  }
136
132
 
133
+ # Join arguments with proper escaping
134
+ args_str = ' '.join(f'"{arg}"' for arg in docker_args)
135
+
136
+ print(f"Docker args: {docker_args}")
137
+ print(f"Project root: {project_root}")
138
+
139
+ # Debug command to find file and then run testgenie with args
140
+ debug_cmd = f'find /controller -type f -name "*.py" | grep -i boolean || echo "File not found"; ' \
141
+ f'ls -la /controller; ' \
142
+ f'testgenie /controller/testgen/code_to_test/boolean.py --test-mode=fuzz --test-format=pytest'
143
+
137
144
  return docker_client.containers.run(
138
145
  image=image_name,
139
- command=["python", "-m", "testgen.main"] + docker_args,
140
- volumes={project_root: {"bind": "/controller", "mode": "rw"}},
146
+ command=["sh", "-c", debug_cmd],
147
+ volumes={
148
+ os.path.abspath(project_root): {
149
+ "bind": "/controller",
150
+ "mode": "rw"
151
+ }
152
+ },
153
+ working_dir="/controller",
141
154
  environment=docker_env,
142
155
  detach=True,
143
156
  remove=True,
@@ -203,6 +216,11 @@ class DockerController:
203
216
  print("Dockerfile not found in local project or package.")
204
217
  sys.exit(1)
205
218
 
219
+ @staticmethod
220
+ def is_inside_docker() -> bool:
221
+ """Check if the current process is running inside a Docker container."""
222
+ return os.environ.get("RUNNING_IN_DOCKER") in ("1", "true", "True")
223
+
206
224
  def debug(self, message: str):
207
225
  """Log debug message"""
208
226
  if self.debug_mode:
@@ -0,0 +1,31 @@
1
+ # Use Python 3.10 image
2
+ FROM python:3.10
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ graphviz \
8
+ libgraphviz-dev \
9
+ pkg-config \
10
+ curl
11
+
12
+ # Install Poetry (optional, in case you ever need it)
13
+ RUN curl -sSL https://install.python-poetry.org | python3 - && \
14
+ ln -s /root/.local/bin/poetry /usr/local/bin/poetry
15
+
16
+ # Set environment variables
17
+ ENV POETRY_VIRTUALENVS_CREATE=false \
18
+ PYTHONUNBUFFERED=1 \
19
+ RUNNING_IN_DOCKER=true
20
+
21
+ # Install your package from PyPI
22
+ RUN python3 -m pip install --no-cache-dir testgenie-py
23
+
24
+ # Set a working directory (where your code will be mounted at runtime)
25
+ WORKDIR /controller
26
+
27
+ # Set up PYTHONPATH
28
+ ENV PYTHONPATH=/controller:/controller/testgen
29
+
30
+ # Default command
31
+ CMD ["testgenie"]
@@ -0,0 +1,69 @@
1
+ import pytest
2
+
3
+ import testgen.code_to_test.boolean as boolean
4
+
5
+ def test_bin_and_0():
6
+ args = (False, False)
7
+ expected = False
8
+ result = boolean.bin_and(*args)
9
+ assert result == expected
10
+
11
+ def test_bin_and_1():
12
+ args = (True, True)
13
+ expected = True
14
+ result = boolean.bin_and(*args)
15
+ assert result == expected
16
+
17
+ def test_bin_and_2():
18
+ args = (True, False)
19
+ expected = False
20
+ result = boolean.bin_and(*args)
21
+ assert result == expected
22
+
23
+ def test_bin_xor_3():
24
+ args = (True, True)
25
+ expected = False
26
+ result = boolean.bin_xor(*args)
27
+ assert result == expected
28
+
29
+ def test_bin_xor_4():
30
+ args = (True, False)
31
+ expected = True
32
+ result = boolean.bin_xor(*args)
33
+ assert result == expected
34
+
35
+ def test_bin_xor_5():
36
+ args = (False, False)
37
+ expected = False
38
+ result = boolean.bin_xor(*args)
39
+ assert result == expected
40
+
41
+ def test_status_flags_6():
42
+ args = (True, False, True)
43
+ expected = 'admin-unverified'
44
+ result = boolean.status_flags(*args)
45
+ assert result == expected
46
+
47
+ def test_status_flags_7():
48
+ args = (False, False, False)
49
+ expected = 'inactive'
50
+ result = boolean.status_flags(*args)
51
+ assert result == expected
52
+
53
+ def test_status_flags_8():
54
+ args = (True, False, False)
55
+ expected = 'user-unverified'
56
+ result = boolean.status_flags(*args)
57
+ assert result == expected
58
+
59
+ def test_status_flags_9():
60
+ args = (False, True, True)
61
+ expected = 'admin-verified'
62
+ result = boolean.status_flags(*args)
63
+ assert result == expected
64
+
65
+ def test_status_flags_10():
66
+ args = (True, True, False)
67
+ expected = 'user-verified'
68
+ result = boolean.status_flags(*args)
69
+ assert result == expected
@@ -109,8 +109,23 @@ def load_and_parse_file_for_tree(file) -> Module:
109
109
  tree = ast.parse(code)
110
110
  return tree
111
111
 
112
- def adjust_file_path_for_docker(file_path) -> str:
113
- """Adjust file path for Docker environment to handle subdirectories and relative paths."""
112
+ def adjust_file_path_for_docker(file_path: str) -> str:
113
+ """Adjust the file path to be valid inside the Docker container."""
114
+ print(f"Docker - adjusting path: {file_path}")
115
+
116
+ # If already absolute to /controller, return as-is
117
+ if file_path.startswith("/controller/"):
118
+ print(f"Docker - already adjusted: {file_path}")
119
+ return file_path
120
+
121
+ # If relative, make absolute
122
+ adjusted_path = f"/controller/{file_path.lstrip('/')}"
123
+ print(f"Docker - adjusted to: {adjusted_path}")
124
+ return adjusted_path
125
+
126
+
127
+ """def adjust_file_path_for_docker(file_path) -> str:
128
+ #Adjust file path for Docker environment to handle subdirectories and relative paths.
114
129
  print(f"Docker - adjusting path: {file_path}")
115
130
 
116
131
  # Try direct path first (maybe it's correct already)
@@ -144,13 +159,28 @@ def adjust_file_path_for_docker(file_path) -> str:
144
159
 
145
160
  # Return original path if we couldn't find a better match
146
161
  print(f"Docker - couldn't find file, returning original: {file_path}")
147
- return file_path
162
+ return file_path"""
163
+
164
+
148
165
 
149
166
  def get_project_root_in_docker(script_path) -> str:
150
- script_path = os.path.abspath(sys.argv[0])
151
- print(f"Script path: {script_path}")
152
- script_dir = os.path.dirname(script_path)
153
- print(f"Script directory: {script_dir}")
154
- project_root = os.path.dirname(script_dir)
155
- print(f"Project root directory: {project_root}")
156
- return project_root
167
+ # Don't use sys.argv[0] as it points to the virtualenv
168
+ # Instead, find the actual project root
169
+ if os.path.exists('/mnt/c/Users/cjsei/thesis/dev/testgen'):
170
+ # Hard-coded path for now
171
+ project_root = '/mnt/c/Users/cjsei/thesis/dev/testgen'
172
+ else:
173
+ # Try to find project root by looking for pyproject.toml or similar
174
+ current_dir = os.path.dirname(os.path.abspath(script_path))
175
+ while current_dir != '/':
176
+ if os.path.exists(os.path.join(current_dir, 'pyproject.toml')) or \
177
+ os.path.exists(os.path.join(current_dir, 'setup.py')):
178
+ project_root = current_dir
179
+ break
180
+ current_dir = os.path.dirname(current_dir)
181
+ else:
182
+ # Fallback - use parent of script dir
183
+ project_root = os.path.dirname(os.path.dirname(os.path.abspath(script_path)))
184
+
185
+ print(f"Project root directory: {project_root}")
186
+ return project_root
@@ -1,22 +0,0 @@
1
- FROM python:3.10
2
-
3
- RUN apt-get update && apt-get install -y curl build-essential
4
-
5
- RUN curl -sSL https://install.python-poetry.org | python3 - \
6
- && ln -s /root/.local/bin/poetry /usr/local/bin/poetry
7
-
8
- ENV POETRY_VIRTUALENVS_CREATE=false \
9
- PYTHONUNBUFFERED=1 \
10
- RUNNING_IN_DOCKER=true
11
-
12
- WORKDIR /controller
13
-
14
- # Copy poetry files
15
- COPY . .
16
-
17
- ENV PYTHONPATH=/controller:/controller/testgen
18
-
19
- RUN poetry install --no-root
20
-
21
- # Entrypoint (Can be overridden by Docker SDK in Python)
22
- CMD ["poetry", "run", "python", "-m", "testgen.main"]