Run in the background and open when MTGA starts
- Closing the window hides it to the system tray; tracking and history recording continue. Quit from the tray, the menu or Ctrl+Q. - Show the window when MTGA starts a new Player.log, detected with OS file notifications on the log folder (QFileSystemWatcher), not polling. - Single instance over a local socket: launching again shows the running window (or stays hidden with --background). - Menu options for background mode, show-on-launch and start at login (XDG autostart on Linux, HKCU Run key on Windows); --background flag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f3c7c13d0
commit
c4533d12c0
4 files changed
+404
-4
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from PySide6.QtCore import QCoreApplication
|
||||
|
||||
from mtga_assistant.background import (
|
||||
LaunchWatcher,
|
||||
SingleInstance,
|
||||
autostart_enabled,
|
||||
desktop_exec,
|
||||
launch_command,
|
||||
set_autostart,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def app():
|
||||
return QCoreApplication.instance() or QCoreApplication([])
|
||||
|
||||
|
||||
def wait_for(app, cond, timeout=3.0):
|
||||
end = time.monotonic() + timeout
|
||||
while time.monotonic() < end:
|
||||
app.processEvents()
|
||||
if cond():
|
||||
return True
|
||||
time.sleep(0.01)
|
||||
app.processEvents()
|
||||
return cond()
|
||||
|
||||
|
||||
def test_second_launch_messages_the_running_instance(app):
|
||||
name = f"mtga-assistant-test-{uuid.uuid4().hex[:8]}"
|
||||
first = SingleInstance(name)
|
||||
assert not first.send("show") # nobody running yet
|
||||
assert first.listen()
|
||||
got = []
|
||||
first.message.connect(got.append)
|
||||
|
||||
second = SingleInstance(name)
|
||||
try:
|
||||
assert second.send("show")
|
||||
assert wait_for(app, lambda: got == ["show"])
|
||||
finally:
|
||||
# Let queued socket events run before the objects go away.
|
||||
first.close()
|
||||
wait_for(app, lambda: False, timeout=0.2)
|
||||
|
||||
|
||||
def test_launch_watcher_reports_new_log_not_appends(app, tmp_path):
|
||||
log = tmp_path / "Player.log"
|
||||
log.write_text("old session\n")
|
||||
watcher = LaunchWatcher(log)
|
||||
assert watcher.active
|
||||
launches = []
|
||||
watcher.launched.connect(lambda: launches.append(1))
|
||||
|
||||
# Normal logging: no launch.
|
||||
with open(log, "a") as f:
|
||||
f.write("more\n")
|
||||
wait_for(app, lambda: False, timeout=0.3)
|
||||
assert launches == []
|
||||
|
||||
# MTGA starts: old log becomes Player-prev.log, a new Player.log appears.
|
||||
os.replace(log, tmp_path / "Player-prev.log")
|
||||
log.write_text("new session\n")
|
||||
assert wait_for(app, lambda: len(launches) >= 1)
|
||||
|
||||
# Still watching the new file: a truncate-in-place restart is reported too.
|
||||
count = len(launches)
|
||||
with open(log, "a") as f:
|
||||
f.write("lots of lines\n" * 50)
|
||||
wait_for(app, lambda: False, timeout=0.3)
|
||||
assert len(launches) == count
|
||||
log.write_text("")
|
||||
assert wait_for(app, lambda: len(launches) > count)
|
||||
|
||||
|
||||
def test_launch_watcher_without_folder_is_inactive(app, tmp_path):
|
||||
assert not LaunchWatcher(tmp_path / "missing" / "Player.log").active
|
||||
|
||||
|
||||
def test_linux_autostart_entry(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
||||
assert not autostart_enabled("linux")
|
||||
set_autostart(True, "linux")
|
||||
entry = tmp_path / "autostart" / "mtga-assistant.desktop"
|
||||
text = entry.read_text()
|
||||
assert autostart_enabled("linux")
|
||||
assert "--background" in text and "Exec=" in text
|
||||
set_autostart(False, "linux")
|
||||
assert not entry.exists() and not autostart_enabled("linux")
|
||||
|
||||
|
||||
def test_launch_command_starts_hidden():
|
||||
cmd = launch_command()
|
||||
assert cmd[-1] == "--background"
|
||||
|
||||
|
||||
def test_desktop_exec_quoting():
|
||||
assert desktop_exec(["/usr/bin/python", "-m", "x"]) == "/usr/bin/python -m x"
|
||||
assert desktop_exec(["/a b/c"]) == '"/a b/c"'
|
||||
assert desktop_exec(['/a"b']) == '"/a\\"b"'
|
||||
Reference in new issue
Block a user