Skip to content

Commit 1220be5

Browse files
ctruedenclaude
andcommitted
Improve integration tests for validate subcommand
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 93bdbf6 commit 1220be5

2 files changed

Lines changed: 151 additions & 7 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[filter]
2+
includes = ["org.scijava:*"]
3+
excludes = ["org.scijava:legacy-*"]
4+
5+
[build]
6+
min-java-version = 11
7+
8+
[skip-tests]
9+
components = ["org.example:legacy-lib"]

tests/integration/test_validate.py

Lines changed: 142 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515

1616
MINIBOM = Path(__file__).parent.parent / "fixtures" / "minibom"
1717

18-
# scijava-common depends on parsington, making it the right component to test
19-
# the BOM's dependency version pinning.
20-
_SCJ_COMMON = "org.scijava:scijava-common"
18+
# Components from the minibom (4 total), in same order as the BOM.
19+
_APP_LAUNCHER = "org.scijava:app-launcher:2.3.1"
20+
_PARSINGTON = "org.scijava:parsington:3.1.0"
21+
_SJ_COMMON = "org.scijava:scijava-common:2.99.2"
22+
_SJ_DESKTOP = "org.scijava:scijava-desktop:1.0.0"
2123

22-
# parsington 1.0.0 predates the 3.x API that scijava-common 2.99.2 requires,
24+
_ALL_COMPONENTS = [_APP_LAUNCHER, _PARSINGTON, _SJ_COMMON, _SJ_DESKTOP]
25+
26+
# parsington 1.0.0 predates the 3.x API that scijava-common 2.99.2 uses,
2327
# so injecting it should cause a compilation failure.
2428
_PARSINGTON_INCOMPATIBLE = "org.scijava:parsington:1.0.0"
2529

@@ -36,13 +40,37 @@ def _make_pipeline(tmp_path: Path, **kwargs) -> Pipeline:
3640
return Pipeline(config)
3741

3842

43+
def _make_pipeline_with_config(tmp_path: Path, config_path: Path, **kwargs) -> Pipeline:
44+
"""Create a pipeline with a config file."""
45+
from pombast.config._settings import PombastConfig
46+
47+
pombast_config = PombastConfig.load(config_path)
48+
49+
pipeline_config = PipelineConfig(
50+
bom=str(MINIBOM),
51+
output_dir=tmp_path / "output",
52+
success_cache_dir=tmp_path / ".success-cache",
53+
test_binary=False,
54+
force=True,
55+
config=pombast_config,
56+
**kwargs,
57+
)
58+
return Pipeline(pipeline_config)
59+
60+
61+
def _assert_components(report, expected: list[str]) -> None:
62+
"""Assert the report contains exactly the given component coordinates, in order."""
63+
actual = [r.component.coordinate for r in report.results]
64+
assert actual == expected, f"expected {expected}, but found: {actual}"
65+
66+
3967
class TestValidate:
4068
def test_passing_bom(self, tmp_path):
4169
"""scijava-common should build successfully against the minibom."""
42-
pipeline = _make_pipeline(tmp_path, includes=[_SCJ_COMMON])
70+
pipeline = _make_pipeline(tmp_path, includes=["org.scijava:scijava-common"])
4371
report = pipeline.run()
4472

45-
assert report.results, "expected at least one result"
73+
_assert_components(report, [_SJ_COMMON])
4674
failures = [r for r in report.results if r.status != BuildStatus.SUCCESS]
4775
assert not failures, (
4876
f"unexpected failures: {[r.component.coordinate for r in failures]}"
@@ -52,11 +80,12 @@ def test_incompatible_parsington(self, tmp_path):
5280
"""Injecting parsington 1.0.0 via -c should cause scijava-common to fail."""
5381
pipeline = _make_pipeline(
5482
tmp_path,
55-
includes=[_SCJ_COMMON],
83+
includes=["org.scijava:scijava-common"],
5684
changes=[_PARSINGTON_INCOMPATIBLE],
5785
)
5886
report = pipeline.run()
5987

88+
_assert_components(report, [_SJ_COMMON])
6089
failures = [
6190
r
6291
for r in report.results
@@ -85,3 +114,109 @@ def test_incompatible_parsington(self, tmp_path):
85114
f"expected compilation failure matching signature {expected_incompatibility_regex}, "
86115
f"but found unexpected build log content."
87116
)
117+
118+
def test_exclude_component(self, tmp_path):
119+
"""Excluding a component via -e should skip it entirely."""
120+
pipeline = _make_pipeline(tmp_path, excludes=["org.scijava:scijava-common"])
121+
report = pipeline.run()
122+
123+
_assert_components(report, [_APP_LAUNCHER, _PARSINGTON, _SJ_DESKTOP])
124+
125+
def test_exclude_nonexistent(self, tmp_path):
126+
"""Excluding a non-existent component should not affect results."""
127+
pipeline = _make_pipeline(tmp_path, excludes=["org.nonexistent:nonexistent"])
128+
report = pipeline.run()
129+
130+
_assert_components(report, _ALL_COMPONENTS)
131+
132+
def test_prune_with_change(self, tmp_path):
133+
"""With prune, only components that depend on the change should be built."""
134+
pipeline = _make_pipeline(
135+
tmp_path,
136+
changes=[_PARSINGTON_INCOMPATIBLE],
137+
prune=True,
138+
)
139+
report = pipeline.run()
140+
141+
_assert_components(report, _ALL_COMPONENTS)
142+
built = [r for r in report.results if r.status != BuildStatus.SKIPPED]
143+
skipped = [r for r in report.results if r.status == BuildStatus.SKIPPED]
144+
assert [r.component.coordinate for r in built] == [_SJ_COMMON], (
145+
f"expected only scijava-common to be built with prune, "
146+
f"but built: {[r.component.coordinate for r in built]}"
147+
)
148+
assert [r.component.coordinate for r in skipped] == [
149+
_APP_LAUNCHER,
150+
_PARSINGTON,
151+
_SJ_DESKTOP,
152+
], (
153+
f"expected app-launcher, parsington, scijava-desktop to be skipped with prune, "
154+
f"but skipped: {[r.component.coordinate for r in skipped]}"
155+
)
156+
157+
def test_exclude_and_include_interaction(self, tmp_path):
158+
"""When both -i and -e are used, exclude takes precedence for matching components."""
159+
pipeline = _make_pipeline(
160+
tmp_path,
161+
includes=["org.scijava:scijava-*"],
162+
excludes=["org.scijava:scijava-common"],
163+
)
164+
report = pipeline.run()
165+
166+
# "org.scijava:scijava-*" matches scijava-common and scijava-desktop;
167+
# scijava-common is then excluded, leaving only scijava-desktop.
168+
_assert_components(report, [_SJ_DESKTOP])
169+
170+
def test_repository_option(self, tmp_path):
171+
"""Adding a repository via -r should be accepted without error."""
172+
pipeline = _make_pipeline(
173+
tmp_path,
174+
includes=["org.scijava:scijava-common"],
175+
repositories=["https://repo1.maven.org/maven2"],
176+
)
177+
report = pipeline.run()
178+
179+
_assert_components(report, [_SJ_COMMON])
180+
181+
def test_multiple_repositories(self, tmp_path):
182+
"""Multiple -r options should all be added to the repository map."""
183+
pipeline = _make_pipeline(
184+
tmp_path,
185+
includes=["org.scijava:scijava-common"],
186+
repositories=[
187+
"https://repo1.maven.org/maven2",
188+
"https://repo.jfrog.org/artifactory",
189+
],
190+
)
191+
report = pipeline.run()
192+
193+
_assert_components(report, [_SJ_COMMON])
194+
195+
def test_skip_build_option(self, tmp_path):
196+
"""Using -s should skip actual builds; no results are produced."""
197+
pipeline = _make_pipeline(
198+
tmp_path,
199+
includes=["org.scijava:scijava-common"],
200+
skip_build=True,
201+
)
202+
report = pipeline.run()
203+
204+
_assert_components(report, [])
205+
206+
def test_config_file_loading(self, tmp_path):
207+
"""Loading configuration from a pombast.toml file should work."""
208+
config_path = MINIBOM / "pombast.toml"
209+
210+
pipeline = _make_pipeline_with_config(tmp_path, config_path)
211+
report = pipeline.run()
212+
213+
_assert_components(report, _ALL_COMPONENTS)
214+
215+
def test_config_min_java_version(self, tmp_path):
216+
"""Config file min-java-version should be used if not specified on CLI."""
217+
config_path = MINIBOM / "pombast.toml"
218+
219+
pipeline = _make_pipeline_with_config(tmp_path, config_path)
220+
report = pipeline.run()
221+
222+
_assert_components(report, _ALL_COMPONENTS)

0 commit comments

Comments
 (0)