diff --git a/bin/notfair-content-calendar b/bin/notfair-content-calendar index ce33bd23..45eaad25 100755 --- a/bin/notfair-content-calendar +++ b/bin/notfair-content-calendar @@ -359,6 +359,13 @@ def _port_in_use(port: int, host: str = "127.0.0.1") -> bool: return False +def _should_auto_open(no_open: bool, platform: str, display: str) -> bool: + """Whether to auto-open the browser. Honors --no-open on every platform.""" + if no_open: + return False + return bool(display) or platform == "darwin" or platform == "win32" + + def main(argv=None) -> int: parser = argparse.ArgumentParser(prog="notfair-content-calendar") parser.add_argument("--port", type=int, default=DEFAULT_PORT) @@ -396,7 +403,7 @@ def main(argv=None) -> int: print(f"Reading: {calendar_path}") print("Ctrl+C to stop.") - if not args.no_open and os.environ.get("DISPLAY", "") or sys.platform == "darwin" or sys.platform == "win32": + if _should_auto_open(args.no_open, sys.platform, os.environ.get("DISPLAY", "")): # Open in a thread so we don't block startup if the browser command stalls. threading.Thread(target=lambda: (time.sleep(0.2), webbrowser.open(url)), daemon=True).start() diff --git a/test/unit/test_content_calendar_auto_open.py b/test/unit/test_content_calendar_auto_open.py new file mode 100644 index 00000000..7240dd2c --- /dev/null +++ b/test/unit/test_content_calendar_auto_open.py @@ -0,0 +1,38 @@ +import unittest +import importlib.util +from importlib.machinery import SourceFileLoader +import sys +from pathlib import Path + +# bin script has no .py extension, so give spec an explicit source loader. +script_path = Path(__file__).parent.parent.parent / 'bin' / 'notfair-content-calendar' +loader = SourceFileLoader("notfair_content_calendar", str(script_path)) +spec = importlib.util.spec_from_file_location("notfair_content_calendar", str(script_path), loader=loader) +mod = importlib.util.module_from_spec(spec) +sys.modules["notfair_content_calendar"] = mod +spec.loader.exec_module(mod) + +should_auto_open = mod._should_auto_open + + +class TestShouldAutoOpen(unittest.TestCase): + def test_no_open_suppresses_on_every_platform(self): + # --no-open must win on macOS and Windows too, not just headless Linux. + for platform in ("darwin", "win32", "linux"): + self.assertFalse( + should_auto_open(no_open=True, platform=platform, display=""), + f"--no-open should suppress auto-open on {platform}", + ) + self.assertFalse(should_auto_open(no_open=True, platform="linux", display=":0")) + + def test_default_opens_where_a_gui_exists(self): + self.assertTrue(should_auto_open(False, "darwin", "")) + self.assertTrue(should_auto_open(False, "win32", "")) + self.assertTrue(should_auto_open(False, "linux", ":0")) + + def test_headless_linux_does_not_open(self): + self.assertFalse(should_auto_open(False, "linux", "")) + + +if __name__ == "__main__": + unittest.main()