Skip to content

Commit 6074381

Browse files
authored
Cross-platform CI matrix, Windows path tests, and PyInstaller smoke test (closes #44) (#62)
* feat: initial implementation for cross platform ci matrix * fix: test_percent_encoded_drive_on_win32 duplicates the win32 branch
1 parent a085b33 commit 6074381

3 files changed

Lines changed: 56 additions & 10 deletions

File tree

.github/workflows/tests.yml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ jobs:
7272
<(grep -E '^[A-Za-z0-9_.-]+==' /tmp/requirements-lock.txt | sort)
7373
7474
# ── Unit tests: matrix across OS and Python version ───────────────────────
75-
# Closes #13. The unittest suite is the merge gate. Multi-OS catches the
76-
# rare path / line-ending issue that a single-OS run hides; multi-Python
77-
# catches API drift across LTS / current / latest interpreters.
75+
# Closes #13 and #44. Multi-OS catches path-normalisation drift and
76+
# line-ending issues that a single-OS run hides; multi-Python catches API
77+
# drift across LTS / current / latest interpreters. Matrix parallelism
78+
# keeps wall-clock under ~15 min (slowest runner wins, not the sum).
7879
unittest:
7980
name: Unit tests (${{ matrix.os }} / Python ${{ matrix.python-version }})
8081
runs-on: ${{ matrix.os }}
8182
strategy:
8283
fail-fast: false
8384
matrix:
84-
os: [ubuntu-latest]
85+
os: [ubuntu-latest, windows-latest, macos-latest]
8586
python-version: ["3.10", "3.11", "3.12", "3.13"]
8687
steps:
8788
# Pinned to immutable commit SHAs (not @v4 / @v5) so a compromised tag
@@ -117,6 +118,21 @@ jobs:
117118
# ~2× the CI minutes for zero extra signal.
118119
run: python -m pytest tests/test_api_endpoints.py -v --tb=short
119120

121+
# ── PyInstaller desktop build (Windows only, once per workflow) ────────
122+
# Closes #44. Builds the onedir bundle and smoke-tests --help so the
123+
# desktop entry point is verified without launching the GUI window.
124+
- name: Install PyInstaller
125+
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
126+
run: python -m pip install 'pyinstaller>=6,<7'
127+
128+
- name: Build PyInstaller bundle
129+
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
130+
run: pyinstaller cursor-browser.spec --noconfirm
131+
132+
- name: Smoke-test PyInstaller exe (--help)
133+
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
134+
run: dist\CursorChatBrowser\CursorChatBrowser.exe --help
135+
120136
# ── Typecheck: mypy ───────────────────────────────────────────────────────
121137
# Codebase already has type hints across most of the surface (~70+ typed
122138
# functions). Mypy runs in lenient mode (--ignore-missing-imports for

launcher.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@
55
directly in-process.
66
"""
77

8+
from __future__ import annotations
9+
10+
import argparse
11+
import sys
12+
813
from app import create_app
914

1015

11-
def main():
16+
def main(argv: list[str] | None = None) -> None:
17+
parser = argparse.ArgumentParser(
18+
prog="cursor-chat-browser",
19+
description=(
20+
"Cursor Chat Browser - opens the Flask app in a native OS window "
21+
"via pywebview (no HTTP server or port)."
22+
),
23+
)
24+
parser.parse_args(argv)
25+
1226
try:
1327
import webview
1428
except ImportError:
@@ -28,4 +42,4 @@ def main():
2842

2943

3044
if __name__ == "__main__":
31-
main()
45+
main(sys.argv[1:])

tests/test_normalize_file_path.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
"""Tests for utils.path_helpers path/timestamp helpers (closes #46).
1+
"""Tests for utils.path_helpers path/timestamp helpers (closes #44, #46).
22
33
Covers ``normalize_file_path`` and ``to_epoch_ms``, both previously duplicated
44
in scripts/export.py. All call-sites in the web app and CLI export script now
55
use the shared implementations in utils.path_helpers.
66
7-
Test inventory (this module only): 21 cases — 12 ``normalize_file_path``,
7+
Test inventory (this module only): 23 cases — 14 ``normalize_file_path``,
88
9 ``to_epoch_ms``. On win32, 2 cases skip (POSIX passthrough in
9-
``TestNormalizeFilePathPosixPassthrough`` only). A full-suite run may report
10-
more skips (e.g. ``skipped=4``) from other test modules, not this file.
9+
``TestNormalizeFilePathPosixPassthrough`` only). On non-win32, 2 cases skip
10+
(``TestNormalizeFilePathWindowsNative`` — exercised on windows-latest CI).
11+
A full-suite run may report more skips (e.g. ``skipped=4``) from other test
12+
modules, not this file.
1113
"""
1214

1315
import sys
@@ -91,6 +93,20 @@ def test_mixed_case_drive_lowercased(self) -> None:
9193
self.assertEqual(out, r"e:\mixed\case\path")
9294

9395

96+
class TestNormalizeFilePathWindowsNative(unittest.TestCase):
97+
"""Win32-only edge cases — run on actual Windows runners in CI (#44)."""
98+
99+
@unittest.skipUnless(sys.platform == "win32", "native win32 path semantics")
100+
def test_leading_backslash_before_drive_stripped(self) -> None:
101+
out = normalize_file_path(r"\C:\Users\Dev\project")
102+
self.assertEqual(out, r"c:\users\dev\project")
103+
104+
@unittest.skipUnless(sys.platform == "win32", "native win32 path semantics")
105+
def test_file_uri_backslashes_normalised(self) -> None:
106+
out = normalize_file_path(r"file:///C:\Users\Dev\project")
107+
self.assertEqual(out, r"c:\users\dev\project")
108+
109+
94110
class TestNormalizeFilePathPosixPassthrough(unittest.TestCase):
95111
def test_plain_posix_path_unchanged_on_non_windows(self) -> None:
96112
if sys.platform == "win32":

0 commit comments

Comments
 (0)