@@ -28,12 +28,23 @@ def test_installer_to_portable_name_accepts_canonical_nightly_windows_name(self)
2828 )
2929
3030 def test_installer_to_portable_name_normalizes_legacy_nightly_windows_name (self ):
31- self .assertEqual (
32- MODULE .installer_to_portable_name (
33- "AstrBot_4.29.0-nightly.20260401.deadbeef_aarch64-setup.exe"
34- ),
35- "AstrBot_4.29.0_windows_arm64_portable_nightly_deadbeef.zip" ,
36- )
31+ arch_cases = [
32+ ("x64" , "amd64" ),
33+ ("amd64" , "amd64" ),
34+ ("arm64" , "arm64" ),
35+ ("aarch64" , "arm64" ),
36+ ]
37+ separators = ["." , "_" , "-" ]
38+
39+ for arch_input , arch_output in arch_cases :
40+ for separator in separators :
41+ with self .subTest (arch = arch_input , separator = separator ):
42+ installer_name = f"AstrBot_4.29.0-nightly{ separator } 20260401{ separator } deadbeef_{ arch_input } -setup.exe"
43+ expected_name = f"AstrBot_4.29.0_windows_{ arch_output } _portable_nightly_deadbeef.zip"
44+ self .assertEqual (
45+ MODULE .installer_to_portable_name (installer_name ),
46+ expected_name ,
47+ )
3748
3849 def test_installer_to_portable_name_rejects_noncanonical_nightly_suffix_length (
3950 self ,
@@ -136,6 +147,51 @@ def test_load_project_config_from_returns_root_product_and_marker(self):
136147 self .assertEqual (project_config .binary_name , "astrbot-desktop-tauri" )
137148 self .assertEqual (project_config .portable_marker_name , "portable.flag" )
138149
150+ def test_load_project_config_from_rejects_product_name_with_invalid_windows_chars (
151+ self ,
152+ ):
153+ with tempfile .TemporaryDirectory () as tmpdir :
154+ project_root = Path (tmpdir )
155+ script_path = (
156+ project_root / "scripts" / "ci" / "package_windows_portable.py"
157+ )
158+ tauri_config_path = project_root / "src-tauri" / "tauri.conf.json"
159+ cargo_toml_path = project_root / "src-tauri" / "Cargo.toml"
160+ marker_path = project_root / MODULE .PORTABLE_RUNTIME_MARKER_RELATIVE_PATH
161+
162+ script_path .parent .mkdir (parents = True )
163+ script_path .write_text ("# placeholder" )
164+ tauri_config_path .parent .mkdir (parents = True )
165+ tauri_config_path .write_text ('{"productName":"AstrBot:Beta"}' )
166+ cargo_toml_path .write_text ('[package]\n name = "astrbot-desktop-tauri"\n ' )
167+ marker_path .parent .mkdir (parents = True , exist_ok = True )
168+ marker_path .write_text ("portable.flag\n " )
169+
170+ with self .assertRaisesRegex (ValueError , "invalid Windows filename" ):
171+ MODULE .load_project_config_from (script_path )
172+
173+ def test_load_project_config_from_strips_exe_suffix_from_product_name (self ):
174+ with tempfile .TemporaryDirectory () as tmpdir :
175+ project_root = Path (tmpdir )
176+ script_path = (
177+ project_root / "scripts" / "ci" / "package_windows_portable.py"
178+ )
179+ tauri_config_path = project_root / "src-tauri" / "tauri.conf.json"
180+ cargo_toml_path = project_root / "src-tauri" / "Cargo.toml"
181+ marker_path = project_root / MODULE .PORTABLE_RUNTIME_MARKER_RELATIVE_PATH
182+
183+ script_path .parent .mkdir (parents = True )
184+ script_path .write_text ("# placeholder" )
185+ tauri_config_path .parent .mkdir (parents = True )
186+ tauri_config_path .write_text ('{"productName":"AstrBot.exe"}' )
187+ cargo_toml_path .write_text ('[package]\n name = "astrbot-desktop-tauri"\n ' )
188+ marker_path .parent .mkdir (parents = True , exist_ok = True )
189+ marker_path .write_text ("portable.flag\n " )
190+
191+ project_config = MODULE .load_project_config_from (script_path )
192+
193+ self .assertEqual (project_config .product_name , "AstrBot" )
194+
139195 def test_load_cargo_package_name_supports_inline_comments (self ):
140196 with tempfile .TemporaryDirectory () as tmpdir :
141197 project_root = Path (tmpdir )
@@ -301,13 +357,17 @@ def test_populate_portable_root_copies_release_bundle_contents(self):
301357 "Write-Host cleanup"
302358 )
303359
360+ project_config = MODULE .load_project_config_from (script_path )
361+
304362 MODULE .populate_portable_root (
305363 bundle_dir = bundle_dir ,
306364 destination_root = destination_root ,
307- project_config = MODULE . load_project_config_from ( script_path ) ,
365+ project_config = project_config ,
308366 )
309367
310- self .assertTrue ((destination_root / "AstrBot.exe" ).is_file ())
368+ executable_name = f"{ project_config .product_name } .exe"
369+
370+ self .assertTrue ((destination_root / executable_name ).is_file ())
311371 self .assertFalse ((destination_root / "astrbot-desktop-tauri.exe" ).exists ())
312372 self .assertTrue ((destination_root / "WebView2Loader.dll" ).is_file ())
313373 self .assertTrue (
0 commit comments