ProPresenter updates are safe: any installed copy counts as running, the newest version opens

- newest_of picks by CFBundleShortVersionString, not file name (ProPresenter.app sorted after ProPresenter 20.1.app)
- mac_start takes newest_of; auto-setup uses it for programs on the Companion Mac
- WS and SC switched over; NA's ProP restart re-rendered (same pick today)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 14:33:39 -04:00
co-authored by Claude Opus 5.5
parent 5db1d93732
commit 42b325e927
7 changed files with 82 additions and 24 deletions
+7 -2
View File
@@ -162,9 +162,14 @@ class TestBuild(unittest.TestCase):
cfg, _ = ac.build(BASE, inv, {"id": "ws", "name": "Woonsocket"}, "1234")
self.assertEqual(schema.validate(cfg)[0], [])
prop = next(t for t in cfg["tiles"] if t["label"] == "PROP")
self.assertEqual([(c["type"], c.get("match") or c.get("conn")) for c in prop["checks"]], [("conn", "ProP"), ("process", exe)])
import re
self.assertEqual([c["type"] for c in prop["checks"]], ["conn", "process"])
match = prop["checks"][1]["match"] # any installed copy counts (an update beside the old)
self.assertTrue(re.search(match, exe) and re.search(match, "/Applications/ProPresenter 21.4.app/Contents/MacOS/ProPresenter"))
fix = cfg["fixes"][prop["checks"][1]["fix"]]
self.assertEqual((fix["kind"], fix["run"]), ("local", "pgrep -xq ProPresenter || open /Applications/ProPresenter.app"))
self.assertEqual(fix["kind"], "local")
self.assertTrue(fix["run"].startswith("pgrep -xq ProPresenter || { APP=$(for a in /Applications/ProPresenter*.app"), fix["run"])
self.assertTrue(fix["run"].endswith('open "$APP"; }'), fix["run"]) # the newest version opens
self.assertIn(prop["checks"][1]["fix"], cfg["auto_fix"]["fixes"])
self.assertEqual([k["label"] for k in cfg["restart_page"]["keys"]], ["PROP"])
self.assertEqual(cfg["fixes"][cfg["restart_page"]["keys"][0]["fix"]]["kind"], "local")
+27
View File
@@ -376,3 +376,30 @@ class TestBindingAndProbes(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
class TestNewestCopy(unittest.TestCase):
"""An update installed beside the old copy: the newest version opens, whatever the file names."""
@unittest.skipUnless(sys.platform == "darwin", "reads app versions with macOS's defaults")
def test_the_newest_version_wins_not_the_last_name(self):
import subprocess
from settings import builders as b
for names in ((("Show 20.0.1.app", "20.0.1"), ("Show.app", "20.1.0")), (("Show 20.0.1.app", "20.0.1"), ("Show.app", "19.4"))):
root = tempfile.mkdtemp(prefix="sp-apps-")
for name, ver in names:
os.makedirs(os.path.join(root, name, "Contents"))
subprocess.run(["/usr/bin/defaults", "write", os.path.join(root, name, "Contents", "Info"),
"CFBundleShortVersionString", ver], check=True)
out = subprocess.run(["/bin/sh", "-c", b.newest_app(root + "/Show*.app") + 'echo "$APP"'],
capture_output=True, text=True).stdout.strip()
want = max(names, key=lambda n: tuple(int(x) for x in n[1].split(".")))[0]
self.assertEqual(os.path.basename(out), want)
def test_any_copy_counts_as_running_but_never_a_helper(self):
import re
from settings import builders as b
m = b.app_match("/Applications/ProPresenter*.app", "ProPresenter")
self.assertTrue(re.search(m, "/Applications/ProPresenter 20.0.1.app/Contents/MacOS/ProPresenter"))
self.assertTrue(re.search(m, "/Applications/ProPresenter.app/Contents/MacOS/ProPresenter"))
self.assertFalse(re.search(m, "/Applications/ProPresenter.app/Contents/MacOS/ProPresenter Helper (Network)"))