import unittest from _helpers import REPO_ROOT from app import version class PackagingTests(unittest.TestCase): def read_text(self, relative_path): return (REPO_ROOT / relative_path).read_text(encoding="utf-8") def test_frozen_entrypoint_keeps_program_and_data_paths_separate(self): main_py = self.read_text("main.py") gui_init = self.read_text("app/gui/__init__.py") self.assertIn('getattr(sys, "frozen", False)', main_py) self.assertIn("sys.executable", main_py) self.assertNotIn("os.chdir(PROJECT_ROOT)", main_py) self.assertIn("appconfig.prepare_data_dir()", gui_init) def test_pyinstaller_spec_uses_onedir_without_local_datas(self): spec = self.read_text("cmshopee.spec") normalized = "".join(spec.split()) self.assertIn("collect_data_files", spec) self.assertIn('"app.default_prompts"', spec) self.assertIn('includes=["**/*.txt"]', normalized) self.assertIn("datas=default_prompt_datas", normalized) self.assertIn("COLLECT(", spec) self.assertIn('name="cmshopee"', normalized) def test_build_script_blocks_user_data_in_release_output(self): script = self.read_text("scripts/build_exe.ps1") for token in ( "config.json", "config\\ai_models.json", "cmshopee.db", "cmshopee.db-wal", "cmshopee.db-shm", "db.sqlite", "chrome_user_data_dir", "images", "logs", "prompts", "title_prompt.txt", "data", ): self.assertIn(token, script) self.assertIn('$pythonExe = "py"', script) self.assertIn('$pythonArgs = @("-3.10")', script) self.assertIn("& $pythonExe @pythonArgs -m PyInstaller --noconfirm --clean", script) self.assertIn("cmshopee.spec", script) self.assertIn("Decode-Utf8Base64", script) def test_release_version_source_is_single_place(self): version_py = self.read_text("app/version.py") self.assertIn('APP_NAME = "蝦皮圈優化助手"', version_py) self.assertIn('APP_CODE_NAME = "cmshopee"', version_py) self.assertRegex(version.APP_VERSION, r"^\d+\.\d+\.\d+$") self.assertEqual( f"{version.APP_NAME} v{version.APP_VERSION}", version.display_name(), ) def test_build_script_assembles_versioned_release_package(self): script = self.read_text("scripts/build_exe.ps1") self.assertIn('Read-VersionValue -Path $versionFile -Name "APP_VERSION"', script) self.assertIn('$pythonExe = "py"', script) self.assertIn('$pythonArgs = @("-3.10")', script) self.assertIn( 'Decode-Utf8Base64 "5pyq5om+5YiwIFB5dGhvbiAzLjEw44CC6K+35YWI5a6J6KOFIFB5dGhvbiAzLjEw77yM5bm256Gu6K6kIFdpbmRvd3MgUHl0aG9uIExhdW5jaGVyIOWPr+mAmui/hyBweSAtMy4xMCDosIPnlKjjgII="', script, ) self.assertIn('$pythonVersion.StartsWith("3.10.")', script) self.assertNotIn('python -m PyInstaller --noconfirm --clean', script) self.assertNotIn("3.7.9", script) self.assertIn('$releaseRoot = Join-Path $repoRoot "release"', script) self.assertIn('$releaseName = "$appName$appVersion"', script) self.assertIn('$portableZip = Join-Path $releaseRoot "$releaseName.zip"', script) self.assertNotIn('$releaseName = "$appCodeName-$appVersion"', script) self.assertNotIn('$portableZip = Join-Path $releaseRoot "$releaseName-portable.zip"', script) self.assertIn('version.txt', script) self.assertIn('README.txt', script) self.assertIn('Compress-Archive', script) self.assertIn('Compress-ArchiveWithRetry', script) self.assertIn('Start-Sleep -Seconds $DelaySeconds', script) self.assertIn('Assert-NoExcludedData -Root $releaseDir', script) if __name__ == "__main__": unittest.main()