Skip to content

Commit 5f7fbd7

Browse files
committed
Update CMake Example Tests
1 parent b27046d commit 5f7fbd7

File tree

11 files changed

+166
-77
lines changed

11 files changed

+166
-77
lines changed

cppython/plugins/cmake/builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def write_root_presets(preset_file: Path, cppython_preset_file: Path) -> None:
109109
else:
110110
# If the file doesn't exist, we need to default it for the user
111111

112-
# Forward the tool's build directory
112+
# TODO: Forward the tool's build directory
113113
default_configure_preset = ConfigurePreset(name='default', inherits='cppython', binaryDir='build')
114114
root_preset = CMakePresets(configurePresets=[default_configure_preset])
115115

cppython/plugins/cmake/resolution.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ def resolve_cmake_data(data: dict[str, Any], core_data: CorePluginData) -> CMake
2020

2121
root_directory = core_data.project_data.project_root.absolute()
2222

23-
modified_preset_dir = parsed_data.preset_file
24-
if not modified_preset_dir.is_absolute():
25-
modified_preset_dir = root_directory / modified_preset_dir
23+
modified_preset_file = parsed_data.preset_file
24+
if not modified_preset_file.is_absolute():
25+
modified_preset_file = root_directory / modified_preset_file
2626

27-
return CMakeData(preset_file=modified_preset_dir, configuration_name=parsed_data.configuration_name)
27+
28+
29+
return CMakeData(preset_file=modified_preset_file, configuration_name=parsed_data.configuration_name)

cppython/plugins/conan/builder.py

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ def __init__(self, dependencies: list[ConanDependency]) -> None:
2020
def _create_requires_assignment(self) -> cst.Assign:
2121
"""Create a `requires` assignment statement."""
2222
return cst.Assign(
23-
targets=[cst.AssignTarget(cst.Name('requires'))],
24-
value=cst.List([
25-
cst.Element(cst.SimpleString(f'"{dependency.requires()}"')) for dependency in self.dependencies
26-
]),
23+
targets=[cst.AssignTarget(cst.Name(value='requires'))],
24+
value=cst.List(
25+
[cst.Element(cst.SimpleString(f'"{dependency.requires()}"')) for dependency in self.dependencies]
26+
),
2727
)
2828

2929
def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.BaseStatement:
@@ -56,24 +56,23 @@ def _update_requires(self, updated_node: cst.ClassDef) -> cst.ClassDef:
5656
for body_statement_line in updated_node.body.body:
5757
if not isinstance(body_statement_line, cst.SimpleStatementLine):
5858
continue
59-
60-
assignment_statement = body_statement_line.body[0]
61-
if not isinstance(assignment_statement, cst.Assign):
62-
continue
63-
64-
for target in assignment_statement.targets:
65-
if not isinstance(target.target, cst.Name) or target.target.value != 'requires':
59+
for assignment_statement in body_statement_line.body:
60+
if not isinstance(assignment_statement, cst.Assign):
6661
continue
67-
68-
return self._replace_requires(updated_node, body_statement_line, assignment_statement)
62+
for target in assignment_statement.targets:
63+
if not isinstance(target.target, cst.Name) or target.target.value != 'requires':
64+
continue
65+
# Replace only the assignment within the SimpleStatementLine
66+
return self._replace_requires(updated_node, body_statement_line, assignment_statement)
6967

7068
# Find the last attribute assignment before methods
7169
last_attribute = None
7270
for body_statement_line in updated_node.body.body:
7371
if not isinstance(body_statement_line, cst.SimpleStatementLine):
7472
break
75-
assignment_statement = body_statement_line.body[0]
76-
if not isinstance(assignment_statement, cst.Assign):
73+
if not body_statement_line.body:
74+
break
75+
if not isinstance(body_statement_line.body[0], cst.Assign):
7776
break
7877
last_attribute = body_statement_line
7978

@@ -89,29 +88,27 @@ def _update_requires(self, updated_node: cst.ClassDef) -> cst.ClassDef:
8988
new_body.insert(index + 1, new_statement)
9089
else:
9190
new_body = [new_statement] + list(updated_node.body.body)
92-
9391
return updated_node.with_changes(body=updated_node.body.with_changes(body=new_body))
9492

9593
def _replace_requires(
9694
self, updated_node: cst.ClassDef, body_statement_line: cst.SimpleStatementLine, assignment_statement: cst.Assign
9795
) -> cst.ClassDef:
98-
"""Replace the existing 'requires' assignment with a new one.
96+
"""Replace the existing 'requires' assignment with a new one, preserving other statements on the same line."""
97+
new_value = cst.List(
98+
[cst.Element(cst.SimpleString(f'"{dependency.requires()}"')) for dependency in self.dependencies]
99+
)
100+
new_assignment = assignment_statement.with_changes(value=new_value)
99101

100-
Args:
101-
updated_node (cst.ClassDef): The class definition to update.
102-
body_statement_line (cst.SimpleStatementLine): The body item containing the assignment.
103-
assignment_statement (cst.Assign): The existing assignment statement.
102+
# Replace only the relevant assignment in the SimpleStatementLine
103+
new_body = [
104+
new_assignment if statement is assignment_statement else statement for statement in body_statement_line.body
105+
]
106+
new_statement_line = body_statement_line.with_changes(body=new_body)
104107

105-
Returns:
106-
cst.ClassDef: The updated class definition.
107-
"""
108-
new_value = cst.List([
109-
cst.Element(cst.SimpleString(f'"{dependency.requires()}"')) for dependency in self.dependencies
110-
])
111-
new_assignment = assignment_statement.with_changes(value=new_value)
108+
# Replace the statement line in the class body
112109
return updated_node.with_changes(
113110
body=updated_node.body.with_changes(
114-
body=[new_assignment if item is body_statement_line else item for item in updated_node.body.body]
111+
body=[new_statement_line if item is body_statement_line else item for item in updated_node.body.body]
115112
)
116113
)
117114

examples/conan_cmake/inject/pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ description = "A simple project showing how to use conan with CPPython"
33
name = "cppython-conan-cmake-simple"
44
version = "1.0.0"
55

6-
license = {text = "MIT"}
6+
license = { text = "MIT" }
77

8-
authors = [{name = "Synodic Software", email = "contact@synodic.software"}]
8+
authors = [{ name = "Synodic Software", email = "contact@synodic.software" }]
99

1010
requires-python = ">=3.13"
1111

12-
dependencies = ["cppython[conan, cmake]>=0.1.0"]
12+
dependencies = ["cppython[conan, cmake, git]>=0.9.0"]
1313

1414
[tool.cppython]
1515
generator-name = "cmake"

examples/conan_cmake/simple/pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ description = "A simple project showing how to use conan with CPPython"
33
name = "cppython-conan-cmake-simple"
44
version = "1.0.0"
55

6-
license = {text = "MIT"}
6+
license = { text = "MIT" }
77

8-
authors = [{name = "Synodic Software", email = "contact@synodic.software"}]
8+
authors = [{ name = "Synodic Software", email = "contact@synodic.software" }]
99

1010
requires-python = ">=3.13"
1111

12-
dependencies = ["cppython[conan, cmake]>=0.1.0"]
12+
dependencies = ["cppython[conan, cmake, git]>=0.9.0"]
13+
1314

1415
[tool.cppython]
1516
generator-name = "cmake"

examples/vcpkg_cmake/simple/pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ description = "A simple project showing how to use vcpkg with CPPython"
33
name = "cppython-vcpkg-cmake-simple"
44
version = "1.0.0"
55

6-
license = {text = "MIT"}
6+
license = { text = "MIT" }
77

8-
authors = [{name = "Synodic Software", email = "contact@synodic.software"}]
8+
authors = [{ name = "Synodic Software", email = "contact@synodic.software" }]
99

1010
requires-python = ">=3.13"
1111

12-
dependencies = ["cppython[vcpkg, cmake]>=0.1.0"]
12+
dependencies = ["cppython[vcpkg, cmake, git]>=0.9.0"]
13+
1314

1415
[tool.cppython]
1516
generator-name = "cmake"

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ skip_empty = true
100100
plugins = ["-e file:///${PROJECT_ROOT}"]
101101

102102
[tool.pdm.options]
103-
update = ["--update-all", "--unconstrained"]
103+
install = ["-G:all"]
104+
update = ["--update-all"]
104105

105106
[tool.pdm.version]
106107
source = "scm"

tests/fixtures/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""Fixtures for interfacing with the CLI."""
22

3+
import os
4+
import platform
5+
36
import pytest
47
from typer.testing import CliRunner
58

@@ -13,3 +16,25 @@ def fixture_typer_runner() -> CliRunner:
1316
runner = CliRunner()
1417

1518
return runner
19+
20+
21+
@pytest.fixture(
22+
name='fresh_environment',
23+
scope='session',
24+
)
25+
def fixture_fresh_environment(request: pytest.FixtureRequest) -> dict[str, str]:
26+
"""Create a fresh environment for subprocess calls."""
27+
# Start with a minimal environment
28+
new_env = {}
29+
30+
# Copy only variables you need
31+
if platform.system() == 'Windows':
32+
new_env['SystemRoot'] = os.environ['SystemRoot'] # noqa: SIM112
33+
34+
# Provide a PATH that doesn't contain venv references
35+
new_env['PATH'] = os.environ['PATH']
36+
37+
# Set the Cppython root directory
38+
new_env['CPPYTHON_ROOT'] = str(request.config.rootpath.resolve())
39+
40+
return new_env

tests/integration/examples/test_conan_cmake.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
from typer.testing import CliRunner
1111

12-
from cppython.console.entry import app
13-
1412
pytest_plugins = ['tests.fixtures.example']
1513

1614

@@ -20,39 +18,31 @@ class TestConanCMake:
2018
@staticmethod
2119
def test_simple(example_runner: CliRunner) -> None:
2220
"""Simple project"""
23-
result = example_runner.invoke(
24-
app,
25-
[
26-
'install',
27-
],
28-
)
21+
# By nature of running the test, we require PDM to develop the project and so it will be installed
22+
result = subprocess.run(['pdm', 'install'], capture_output=True, text=True, check=False)
2923

30-
assert result.exit_code == 0, result.output
24+
assert result.returncode == 0, f'PDM install failed: {result.stderr}'
3125

3226
# Run the CMake configuration command
33-
cmake_result = subprocess.run(['cmake', '--preset=default'], capture_output=True, text=True, check=False)
27+
result = subprocess.run(['cmake', '--preset=default'], capture_output=True, text=True, check=False)
3428

35-
assert cmake_result.returncode == 0, f'CMake configuration failed: {cmake_result.stderr}'
29+
assert result.returncode == 0, f'Cmake failed: {result.stderr}'
3630

3731
# Verify that the build directory contains the expected files
3832
assert (Path('build') / 'CMakeCache.txt').exists(), 'build/CMakeCache.txt not found'
3933

4034
@staticmethod
4135
def test_inject(example_runner: CliRunner) -> None:
4236
"""Inject"""
43-
result = example_runner.invoke(
44-
app,
45-
[
46-
'install',
47-
],
48-
)
37+
# By nature of running the test, we require PDM to develop the project and so it will be installed
38+
result = subprocess.run(['pdm', 'install'], capture_output=True, text=True, check=False)
4939

50-
assert result.exit_code == 0, result.output
40+
assert result.returncode == 0, f'PDM install failed: {result.stderr}'
5141

5242
# Run the CMake configuration command
53-
cmake_result = subprocess.run(['cmake', '--preset=default'], capture_output=True, text=True, check=False)
43+
result = subprocess.run(['cmake', '--preset=default'], capture_output=True, text=True, check=False)
5444

55-
assert cmake_result.returncode == 0, f'CMake configuration failed: {cmake_result.stderr}'
45+
assert result.returncode == 0, f'Cmake failed: {result.stderr}'
5646

5747
# Verify that the build directory contains the expected files
5848
assert (Path('build') / 'CMakeCache.txt').exists(), 'build/CMakeCache.txt not found'

tests/integration/examples/test_vcpkg_cmake.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import pytest
1111
from typer.testing import CliRunner
1212

13-
from cppython.console.entry import app
14-
1513
pytest_plugins = ['tests.fixtures.example']
1614

1715

@@ -22,21 +20,15 @@ class TestVcpkgCMake:
2220
@pytest.mark.skip(reason='TODO')
2321
def test_simple(example_runner: CliRunner) -> None:
2422
"""Simple project"""
25-
result = example_runner.invoke(
26-
app,
27-
[
28-
'install',
29-
],
30-
)
23+
# By nature of running the test, we require PDM to develop the project and so it will be installed
24+
result = subprocess.run(['pdm', 'install'], capture_output=True, text=True, check=False)
3125

32-
assert result.exit_code == 0, result.output
26+
assert result.returncode == 0, f'PDM install failed: {result.stderr}'
3327

3428
# Run the CMake configuration command
35-
cmake_result = subprocess.run(
36-
['cmake', '--preset=default', '-B', 'build'], capture_output=True, text=True, check=False
37-
)
29+
result = subprocess.run(['cmake', '--preset=default'], capture_output=True, text=True, check=False)
3830

39-
assert cmake_result.returncode == 0, f'CMake configuration failed: {cmake_result.stderr}'
31+
assert result.returncode == 0, f'Cmake failed: {result.stderr}'
4032

4133
# Verify that the build directory contains the expected files
4234
assert (Path('build') / 'CMakeCache.txt').exists(), 'build/CMakeCache.txt not found'

0 commit comments

Comments
 (0)