Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,17 @@ jobs:
<(grep -E '^[A-Za-z0-9_.-]+==' /tmp/requirements-lock.txt | sort)

# ── Unit tests: matrix across OS and Python version ───────────────────────
# Closes #13. The unittest suite is the merge gate. Multi-OS catches the
# rare path / line-ending issue that a single-OS run hides; multi-Python
# catches API drift across LTS / current / latest interpreters.
# Closes #13 and #44. Multi-OS catches path-normalisation drift and
# line-ending issues that a single-OS run hides; multi-Python catches API
# drift across LTS / current / latest interpreters. Matrix parallelism
# keeps wall-clock under ~15 min (slowest runner wins, not the sum).
unittest:
name: Unit tests (${{ matrix.os }} / Python ${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
# Pinned to immutable commit SHAs (not @v4 / @v5) so a compromised tag
Expand Down Expand Up @@ -117,6 +118,21 @@ jobs:
# ~2× the CI minutes for zero extra signal.
run: python -m pytest tests/test_api_endpoints.py -v --tb=short

# ── PyInstaller desktop build (Windows only, once per workflow) ────────
# Closes #44. Builds the onedir bundle and smoke-tests --help so the
# desktop entry point is verified without launching the GUI window.
- name: Install PyInstaller
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
run: python -m pip install 'pyinstaller>=6,<7'

- name: Build PyInstaller bundle
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
run: pyinstaller cursor-browser.spec --noconfirm

- name: Smoke-test PyInstaller exe (--help)
if: matrix.os == 'windows-latest' && matrix.python-version == '3.12'
run: dist\CursorChatBrowser\CursorChatBrowser.exe --help

# ── Typecheck: mypy ───────────────────────────────────────────────────────
# Codebase already has type hints across most of the surface (~70+ typed
# functions). Mypy runs in lenient mode (--ignore-missing-imports for
Expand Down
18 changes: 16 additions & 2 deletions launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,24 @@
directly in-process.
"""

from __future__ import annotations

import argparse
import sys

from app import create_app


def main():
def main(argv: list[str] | None = None) -> None:
parser = argparse.ArgumentParser(
prog="cursor-chat-browser",
description=(
"Cursor Chat Browser - opens the Flask app in a native OS window "
"via pywebview (no HTTP server or port)."
),
)
parser.parse_args(argv)

try:
import webview
except ImportError:
Expand All @@ -28,4 +42,4 @@ def main():


if __name__ == "__main__":
main()
main(sys.argv[1:])
24 changes: 20 additions & 4 deletions tests/test_normalize_file_path.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Tests for utils.path_helpers path/timestamp helpers (closes #46).
"""Tests for utils.path_helpers path/timestamp helpers (closes #44, #46).

Covers ``normalize_file_path`` and ``to_epoch_ms``, both previously duplicated
in scripts/export.py. All call-sites in the web app and CLI export script now
use the shared implementations in utils.path_helpers.

Test inventory (this module only): 21 cases — 12 ``normalize_file_path``,
Test inventory (this module only): 23 cases — 14 ``normalize_file_path``,
9 ``to_epoch_ms``. On win32, 2 cases skip (POSIX passthrough in
``TestNormalizeFilePathPosixPassthrough`` only). A full-suite run may report
more skips (e.g. ``skipped=4``) from other test modules, not this file.
``TestNormalizeFilePathPosixPassthrough`` only). On non-win32, 2 cases skip
(``TestNormalizeFilePathWindowsNative`` — exercised on windows-latest CI).
A full-suite run may report more skips (e.g. ``skipped=4``) from other test
modules, not this file.
"""

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


class TestNormalizeFilePathWindowsNative(unittest.TestCase):
"""Win32-only edge cases — run on actual Windows runners in CI (#44)."""

@unittest.skipUnless(sys.platform == "win32", "native win32 path semantics")
def test_leading_backslash_before_drive_stripped(self) -> None:
out = normalize_file_path(r"\C:\Users\Dev\project")
self.assertEqual(out, r"c:\users\dev\project")

@unittest.skipUnless(sys.platform == "win32", "native win32 path semantics")
def test_file_uri_backslashes_normalised(self) -> None:
out = normalize_file_path(r"file:///C:\Users\Dev\project")
self.assertEqual(out, r"c:\users\dev\project")


class TestNormalizeFilePathPosixPassthrough(unittest.TestCase):
def test_plain_posix_path_unchanged_on_non_windows(self) -> None:
if sys.platform == "win32":
Expand Down
Loading