mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-27 19:03:22 +01:00
102 lines
4.9 KiB
Python
102 lines
4.9 KiB
Python
"""The author example stores settings as a normal Decky user plugin."""
|
|
import asyncio
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
|
|
EXAMPLE = Path(__file__).resolve().parents[1] / 'examples/framey-settings/main.py'
|
|
|
|
|
|
def backend(settings_dir):
|
|
decky = types.ModuleType('decky')
|
|
decky.DECKY_PLUGIN_SETTINGS_DIR = settings_dir
|
|
spec = importlib.util.spec_from_file_location('framey_sample', EXAMPLE)
|
|
module = importlib.util.module_from_spec(spec)
|
|
with patch.dict(sys.modules, {'decky': decky}):
|
|
spec.loader.exec_module(module)
|
|
return module.Plugin()
|
|
|
|
|
|
class SamplePlugin(unittest.TestCase):
|
|
def test_frontend_bundle_loads_in_framey_host(self):
|
|
result = subprocess.run(['node', str(Path(__file__).parent / 'page/framey_sample.mjs')],
|
|
capture_output=True, text=True, timeout=10)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
|
|
def test_setting_survives_backend_instance_restart(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
first = backend(folder)
|
|
self.assertFalse(asyncio.run(first.get_setting('enabled', False)))
|
|
self.assertTrue(asyncio.run(first.set_setting('enabled', True)))
|
|
second = backend(folder)
|
|
self.assertTrue(asyncio.run(second.get_setting('enabled', False)))
|
|
self.assertEqual(json.loads((Path(folder) / 'settings.json').read_text()),
|
|
{'schema': 1, 'enabled': True})
|
|
|
|
def test_backend_rejects_unknown_keys_and_non_boolean_values(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
plugin = backend(folder)
|
|
with self.assertRaises(ValueError): asyncio.run(plugin.get_setting('other'))
|
|
with self.assertRaises(ValueError): asyncio.run(plugin.set_setting('enabled', 'yes'))
|
|
self.assertFalse((Path(folder) / 'settings.json').exists())
|
|
|
|
def test_corrupt_or_old_setting_uses_default_and_can_be_replaced(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
plugin = backend(folder)
|
|
path = Path(folder) / 'settings.json'
|
|
for data in ('broken JSON', '[]', '{"enabled": "yes"}'):
|
|
with self.subTest(data=data):
|
|
path.write_text(data)
|
|
self.assertFalse(asyncio.run(plugin.get_setting('enabled', False)))
|
|
self.assertTrue(asyncio.run(plugin.get_setting('enabled', True)))
|
|
self.assertTrue(asyncio.run(plugin.set_setting('enabled', True)))
|
|
self.assertTrue(asyncio.run(backend(folder).get_setting('enabled', False)))
|
|
|
|
def test_legacy_boolean_survives_restart_and_migrates_on_save(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
path = Path(folder) / 'settings.json'
|
|
path.write_text('{"enabled": true}\n')
|
|
self.assertTrue(asyncio.run(backend(folder).get_setting('enabled', False)))
|
|
self.assertEqual(json.loads(path.read_text()), {'enabled': True},
|
|
'Reading must not rewrite a user setting')
|
|
self.assertTrue(asyncio.run(backend(folder).set_setting('enabled', False)))
|
|
self.assertEqual(json.loads(path.read_text()), {'schema': 1, 'enabled': False})
|
|
self.assertFalse(asyncio.run(backend(folder).get_setting('enabled', True)))
|
|
|
|
def test_newer_schema_is_preserved_on_read_and_save(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
path = Path(folder) / 'settings.json'
|
|
original = '{"schema": 2, "enabled": true, "future": "keep"}\n'
|
|
path.write_text(original)
|
|
plugin = backend(folder)
|
|
with self.assertRaisesRegex(ValueError, 'unsupported sample version'):
|
|
asyncio.run(plugin.get_setting('enabled', False))
|
|
with self.assertRaisesRegex(ValueError, 'unsupported sample version'):
|
|
asyncio.run(plugin.set_setting('enabled', False))
|
|
self.assertEqual(path.read_text(), original)
|
|
self.assertEqual(list(Path(folder).glob('.settings-*')), [])
|
|
|
|
def test_failed_atomic_replace_keeps_previous_setting(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
path = Path(folder) / 'settings.json'
|
|
plugin = backend(folder)
|
|
self.assertTrue(asyncio.run(plugin.set_setting('enabled', True)))
|
|
previous = path.read_bytes()
|
|
with patch('os.replace', side_effect=OSError('storage unavailable')):
|
|
with self.assertRaisesRegex(OSError, 'storage unavailable'):
|
|
asyncio.run(plugin.set_setting('enabled', False))
|
|
self.assertEqual(path.read_bytes(), previous)
|
|
self.assertEqual(list(Path(folder).glob('.settings-*')), [])
|
|
self.assertTrue(asyncio.run(backend(folder).get_setting('enabled', False)))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|