@@ -61,15 +61,53 @@ def test_coerce_bool_rejects_invalid_values() -> None:
61
61
ensure ._coerce_bool (value = "not-a-boolean" , parameter = "check-tag" )
62
62
63
63
64
- def _write_manifest (path : Path , version : str ) -> None :
65
- """Write a simple manifest declaring ``version`` to ``path``."""
64
+ def _write_manifest (path : Path , version : str , * , name : str = "demo" ) -> None :
65
+ """Write a simple manifest declaring ``name`` and `` version`` to ``path``."""
66
66
path .parent .mkdir (parents = True , exist_ok = True )
67
67
path .write_text (
68
- f"""[package]\n name = \" demo \" \n version = \" { version } \" \n """ ,
68
+ f"""[package]\n name = \" { name } \" \n version = \" { version } \" \n """ ,
69
69
encoding = "utf-8" ,
70
70
)
71
71
72
72
73
+ def _write_raw_manifest (path : Path , contents : str ) -> None :
74
+ """Write a manifest with ``contents`` directly to ``path``."""
75
+ path .parent .mkdir (parents = True , exist_ok = True )
76
+ path .write_text (contents , encoding = "utf-8" )
77
+
78
+
79
+ @pytest .mark .parametrize (
80
+ "manifest_contents" ,
81
+ [
82
+ '[package]\n version = "1.2.3"\n ' ,
83
+ '[package]\n name = ""\n version = "1.2.3"\n ' ,
84
+ '[package]\n name = " "\n version = "1.2.3"\n ' ,
85
+ ],
86
+ )
87
+ def test_read_manifest_version_rejects_invalid_names (
88
+ tmp_path : Path , manifest_contents : str
89
+ ) -> None :
90
+ """A manifest must declare a non-empty ``package.name``."""
91
+ manifest_path = tmp_path / "Cargo.toml"
92
+ _write_raw_manifest (manifest_path , manifest_contents )
93
+
94
+ with pytest .raises (ensure .ManifestError , match = r"package\.name" ):
95
+ ensure ._read_manifest_version (manifest_path )
96
+
97
+
98
+ def test_read_manifest_version_trims_whitespace_from_name (tmp_path : Path ) -> None :
99
+ """Whitespace around the crate name should be ignored."""
100
+ manifest_path = tmp_path / "Cargo.toml"
101
+ _write_raw_manifest (
102
+ manifest_path ,
103
+ '[package]\n name = " demo-crate "\n version = "1.2.3"\n ' ,
104
+ )
105
+
106
+ manifest_version = ensure ._read_manifest_version (manifest_path )
107
+
108
+ assert manifest_version .name == "demo-crate"
109
+
110
+
73
111
def test_main_skips_tag_comparison_when_disabled (
74
112
monkeypatch : pytest .MonkeyPatch ,
75
113
tmp_path : Path ,
@@ -89,6 +127,7 @@ def test_main_skips_tag_comparison_when_disabled(
89
127
90
128
contents = output_file .read_text (encoding = "utf-8" ).splitlines ()
91
129
assert "crate-version=1.2.4" in contents
130
+ assert "crate-name=demo" in contents
92
131
assert "version=9.9.9" in contents
93
132
94
133
captured = capsys .readouterr ()
@@ -114,6 +153,7 @@ def test_main_with_disabled_tag_check_does_not_require_ref(
114
153
115
154
contents = output_file .read_text (encoding = "utf-8" ).splitlines ()
116
155
assert "crate-version=7.8.9" in contents
156
+ assert "crate-name=demo" in contents
117
157
assert not any (line .startswith ("version=" ) for line in contents )
118
158
119
159
captured = capsys .readouterr ()
@@ -160,8 +200,8 @@ def test_main_records_first_manifest_version_in_output(
160
200
first_manifest = workspace / "Cargo.toml"
161
201
second_manifest = workspace / "crates" / "other" / "Cargo.toml"
162
202
163
- _write_manifest (first_manifest , "3.4.5" )
164
- _write_manifest (second_manifest , "9.9.9" )
203
+ _write_manifest (first_manifest , "3.4.5" , name = "primary" )
204
+ _write_manifest (second_manifest , "9.9.9" , name = "secondary" )
165
205
166
206
output_file = workspace / "outputs"
167
207
monkeypatch .setenv ("GITHUB_OUTPUT" , str (output_file ))
@@ -175,6 +215,7 @@ def test_main_records_first_manifest_version_in_output(
175
215
176
216
contents = output_file .read_text (encoding = "utf-8" ).splitlines ()
177
217
assert "crate-version=3.4.5" in contents
218
+ assert "crate-name=primary" in contents
178
219
assert "version=3.4.5" in contents
179
220
180
221
captured = capsys .readouterr ()
@@ -200,7 +241,47 @@ def test_main_emits_crate_version_when_checking_tag(
200
241
201
242
contents = output_file .read_text (encoding = "utf-8" ).splitlines ()
202
243
assert "crate-version=4.5.6" in contents
244
+ assert "crate-name=demo" in contents
203
245
assert "version=4.5.6" in contents
204
246
205
247
captured = capsys .readouterr ()
206
248
assert "Release tag 4.5.6 matches" in captured .out
249
+
250
+
251
+ @pytest .mark .parametrize (
252
+ "manifest_contents" ,
253
+ [
254
+ '[package]\n version = "1.2.3"\n ' ,
255
+ '[package]\n name = ""\n version = "1.2.3"\n ' ,
256
+ '[package]\n name = " "\n version = "1.2.3"\n ' ,
257
+ ],
258
+ )
259
+ def test_main_aborts_when_crate_name_missing_or_blank (
260
+ monkeypatch : pytest .MonkeyPatch ,
261
+ tmp_path : Path ,
262
+ manifest_contents : str ,
263
+ ) -> None :
264
+ """Invalid crate names should terminate the run with an error."""
265
+ workspace = tmp_path
266
+ manifest_path = workspace / "Cargo.toml"
267
+ _write_raw_manifest (manifest_path , manifest_contents )
268
+
269
+ output_file = workspace / "outputs"
270
+ monkeypatch .setenv ("GITHUB_OUTPUT" , str (output_file ))
271
+ monkeypatch .setenv ("GITHUB_WORKSPACE" , str (workspace ))
272
+
273
+ recorded_errors : list [tuple [str , str , Path | None ]] = []
274
+
275
+ def record_error (title : str , message : str , * , path : Path | None = None ) -> None :
276
+ recorded_errors .append ((title , message , path ))
277
+
278
+ monkeypatch .setattr (ensure , "_emit_error" , record_error )
279
+
280
+ with pytest .raises (SystemExit ) as excinfo :
281
+ ensure .main (manifests = [Path ("Cargo.toml" )], check_tag = "false" )
282
+
283
+ assert excinfo .value .code == 1
284
+ assert recorded_errors
285
+ error_titles = {title for title , _ , _ in recorded_errors }
286
+ assert "Cargo.toml parse failure" in error_titles
287
+ assert any ("package.name" in message for _ , message , _ in recorded_errors )
0 commit comments