#!/usr/bin/env python3 """Exercise the real GUI's default ~/.xtc.conf lifecycle in an isolated child HOME.""" import configparser import os from pathlib import Path import subprocess import sys import tempfile import time binary = str(Path(sys.argv[1]).resolve()) with tempfile.TemporaryDirectory(prefix="xtc-config-startup-") as directory: configuration = Path(directory) / ".xtc.conf" environment = dict(os.environ) environment["HOME"] = directory # Child only; never reads/writes the user's config. def run_window(expected_width): process = subprocess.Popen([binary], env=environment, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) try: window = None deadline = time.monotonic() + 15 while time.monotonic() < deadline: if process.poll() is not None: raise AssertionError(f"GUI exited early: {process.communicate()}") found = subprocess.run(["xdotool", "search", "--onlyvisible", "--pid", str(process.pid), "--name", "xtc"], capture_output=True, text=True) if found.returncode == 0: window = found.stdout.splitlines()[0] geometry = subprocess.check_output( ["xdotool", "getwindowgeometry", "--shell", window], text=True) if f"WIDTH={expected_width}\n" in geometry: break time.sleep(.05) else: raise AssertionError(f"Expected startup width {expected_width}; window={window}") subprocess.run(["xdotool", "windowfocus", window], check=True) subprocess.run(["xdotool", "key", "--window", window, "ctrl+q"], check=True) output, error = process.communicate(timeout=15) assert process.returncode == 0, (output, error) finally: if process.poll() is None: process.kill() process.communicate() run_window(1280) assert configuration.exists() and configuration.stat().st_mode & 0o777 == 0o600 saved = configparser.ConfigParser() saved.read(configuration) assert saved["midi"]["midi_input_channel"] == "-1" assert saved["editing"]["note_velocity"] == "100" configuration.write_text("[interface]\nwidth=1360\nheight=860\n" "[midi]\nmidi_input_channel=5\nmidi_output_channel=7\n" "[project_defaults]\ntempo=137000\n") run_window(1360) saved.read(configuration) assert saved["midi"]["midi_input_channel"] == "5" assert saved["midi"]["midi_output_channel"] == "7" assert saved["project_defaults"]["tempo"] == "137000" invalid = "[unknown]\nkeep_this_file=1\n" configuration.write_text(invalid) run_window(1280) assert configuration.read_text() == invalid print("Real startup ~/.xtc.conf creation, defaults, reload and malformed-file preservation passed.")