109 lines
5.8 KiB
Python
109 lines
5.8 KiB
Python
"""Durable real backend operations and private toolkit icon resolution."""
|
|
import concurrent.futures
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
APP = ROOT/'quickshell/.config/quickshell/labfy-sway/applications'
|
|
sys.path.insert(0, str(APP))
|
|
import backend
|
|
import shared
|
|
from gi.repository import Gio
|
|
|
|
NINE = ['firefox.desktop','kitty.desktop','yazi.desktop','nvim.desktop',
|
|
'org.darktable.darktable.desktop','orca-slicer.desktop','org.freecad.FreeCAD.desktop',
|
|
'org.kde.digikam.desktop','AppFlowy.desktop']
|
|
|
|
|
|
class Persistence(unittest.TestCase):
|
|
def test_nine_move_missing_anchor_and_empty(self):
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
path=Path(temp)/'labfy-sway/applications-favorites.json'
|
|
path.parent.mkdir()
|
|
path.write_text(json.dumps(dict(version=1,ids=NINE)))
|
|
self.assertEqual(backend.read_favorites(path)[1],NINE)
|
|
expected=[NINE[1],NINE[0]]+NINE[2:]
|
|
self.assertEqual(backend.write_favorites(path,'move',[NINE[1],NINE[0]]),expected)
|
|
before=path.read_bytes()
|
|
for pair in ([NINE[0],'absent.desktop'], ['absent.desktop',NINE[0]], [NINE[0],'../bad']):
|
|
with self.assertRaises(ValueError): backend.write_favorites(path,'move',pair)
|
|
self.assertEqual(before,path.read_bytes())
|
|
for identifier in NINE: backend.write_favorites(path,'remove',[identifier])
|
|
self.assertEqual(backend.write_favorites(path,'seed',NINE[:4]),[])
|
|
self.assertEqual(backend.read_favorites(path),(True,[]))
|
|
|
|
def test_toggle_is_atomic_and_does_not_depend_on_a_stale_ui_list(self):
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
path=Path(temp)/'favorites.json'
|
|
backend.write_favorites(path,'toggle',['kitty.desktop'])
|
|
self.assertEqual(backend.write_favorites(path,'toggle',['kitty.desktop']),[])
|
|
|
|
def test_real_concurrent_processes_keep_all_additions_during_moves(self):
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
env=dict(os.environ,XDG_STATE_HOME=temp)
|
|
path=Path(temp)/'labfy-sway/applications-favorites.json'
|
|
backend.write_favorites(path,'seed',['a.desktop','b.desktop'])
|
|
def run(args):
|
|
result=subprocess.run([sys.executable,'-B',str(APP/'backend.py'),'favorites',*args],
|
|
env=env,capture_output=True,text=True,timeout=10)
|
|
self.assertEqual(result.returncode,0,result.stdout+result.stderr)
|
|
jobs=[['add',f'added{i}.desktop'] for i in range(24)]
|
|
jobs += [['move','b.desktop','a.desktop'] for _ in range(10)]
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor:
|
|
list(executor.map(run,jobs))
|
|
ids=backend.read_favorites(path)[1]
|
|
self.assertEqual(ids[:2],['b.desktop','a.desktop'])
|
|
self.assertEqual(len(ids),26)
|
|
self.assertEqual(set(ids[2:]),{f'added{i}.desktop' for i in range(24)})
|
|
|
|
|
|
class Icons(unittest.TestCase):
|
|
def test_tela_desktop_icon_and_absolute(self):
|
|
resolver=shared.IconResolver()
|
|
self.assertIn('/Tela-circle-purple-dark/',resolver.resolve(Gio.ThemedIcon.new('firefox')))
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
path=Path(temp)/'custom icon.svg'
|
|
path.write_text('<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"/>')
|
|
self.assertEqual(resolver.resolve(Gio.FileIcon.new(Gio.File.new_for_path(str(path)))),path.as_uri())
|
|
self.assertTrue(resolver.resolve(Gio.ThemedIcon.new('labfy-icon-does-not-exist')))
|
|
self.assertTrue(resolver.resolve(Gio.FileIcon.new(Gio.File.new_for_path('/missing/icon.svg'))))
|
|
|
|
def test_inheritance_from_a_private_test_theme(self):
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
root=Path(temp)
|
|
for name,parent in [('Child','Parent'),('Parent','hicolor')]:
|
|
directory=root/name; (directory/'48x48/apps').mkdir(parents=True)
|
|
(directory/'index.theme').write_text('[Icon Theme]\nName='+name+'\nInherits='+parent+
|
|
'\nDirectories=48x48/apps\n[48x48/apps]\nSize=48\nType=Fixed\nContext=Applications\n')
|
|
icon=root/'Parent/48x48/apps/inherited.svg'
|
|
icon.write_text('<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"/>')
|
|
resolver=shared.IconResolver('Child')
|
|
resolver.theme.set_search_path([temp])
|
|
self.assertEqual(resolver.resolve(Gio.ThemedIcon.new('inherited')),icon.as_uri())
|
|
|
|
|
|
class Sway(unittest.TestCase):
|
|
def test_wayland_xwayland_scratchpad_and_explicit_focus(self):
|
|
tree=dict(nodes=[dict(type='workspace',name='__i3_scratch',floating_nodes=[
|
|
dict(id=42,window=3,window_properties={'class':'Fixture','instance':'fixture'},name='Arbitrary'),
|
|
dict(id=43,app_id='kitty',name='Completely different title')])])
|
|
windows=shared.windows(tree)
|
|
self.assertEqual(windows[0]['wmClass'],'Fixture')
|
|
self.assertEqual(windows[1]['appId'],'kitty')
|
|
self.assertEqual(windows[0]['workspace'],'__i3_scratch')
|
|
with patch.object(shared,'sway_request',side_effect=[tree,[{'success':True}],[{'success':True}]]) as ipc:
|
|
shared.focus('42')
|
|
self.assertEqual([c.args for c in ipc.call_args_list],[(4,''),(0,'[con_id=42] scratchpad show'),
|
|
(0,'[con_id=42] focus')])
|
|
with patch.object(shared,'sway_request') as ipc:
|
|
with self.assertRaises(ValueError): shared.focus('42] focus; exec bad')
|
|
ipc.assert_not_called()
|
|
|
|
if __name__=='__main__': unittest.main()
|