Files
aego/tools/ci/test_protocol_install.py

120 lines
5.4 KiB
Python

import os
from pathlib import Path
import json
import subprocess
import sys
import tempfile
import unittest
class ProtocolInstallTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
self.home = self.root / 'home'
self.data = self.root / 'data'
self.home.mkdir()
self.data.mkdir()
self.bin = self.root / 'bin'
self.bin.mkdir()
self.state = self.root / 'handler'
xdg = self.bin / 'xdg-mime'
xdg.write_text('''#!/bin/sh
case "$1:$2:$3" in
query:default:x-scheme-handler/aego) [ ! -f "$HANDLER_STATE" ] || cat "$HANDLER_STATE" ;;
default:*:x-scheme-handler/aego) printf '%s\\n' "$2" > "$HANDLER_STATE" ;;
esac
''')
xdg.chmod(0o755)
for name in ('update-mime-database', 'update-desktop-database'):
helper = self.bin / name
helper.write_text('#!/bin/sh\nexit 0\n')
helper.chmod(0o755)
script = (Path(__file__).resolve().parents[2] / 'tools/release/install.sh').read_text()
start = script.index('install_desktop() {')
end = script.index('\n}\n', start) + 2
self.function = script[start:end]
def install(self, prefix):
env = dict(os.environ, HOME=str(self.home), XDG_DATA_HOME=str(self.data),
PATH=str(self.bin) + os.pathsep + os.defpath, HANDLER_STATE=str(self.state),
TEST_PREFIX=str(prefix))
subprocess.run(['sh', '-c', 'set -eu\nprefix="$TEST_PREFIX"\nroot="$prefix/share/aego"\n' + self.function + '\ninstall_desktop\n'],
env=env, cwd=self.root, check=True, capture_output=True)
@property
def desktop(self):
return self.data / 'applications/aego-example.desktop'
def test_existing_default_and_modified_file_are_preserved(self):
prefix = self.root / 'install with spaces'
self.state.write_text('other.desktop\n')
self.install(prefix)
self.assertEqual(self.state.read_text(), 'other.desktop\n')
self.assertIn('edit --example-link %u', self.desktop.read_text())
modified = b'[Desktop Entry]\nName=User work\n'
self.desktop.write_bytes(modified)
self.install(prefix)
self.assertEqual(self.desktop.read_bytes(), modified)
self.assertEqual(self.state.read_text(), 'other.desktop\n')
self.assertEqual(list(self.desktop.parent.glob('.aego-example.*')), [])
def test_new_and_identical_owned_file_register_without_replacement(self):
prefix = self.root / 'install with spaces'
self.install(prefix)
before = self.desktop.stat()
self.assertEqual(self.state.read_text(), 'aego-example.desktop\n')
self.install(prefix)
self.assertEqual(self.desktop.stat().st_ino, before.st_ino)
def test_symlink_and_target_are_untouched(self):
self.desktop.parent.mkdir(parents=True)
target = self.root / 'user-data'
target.write_bytes(b'preserve')
self.desktop.symlink_to(target)
self.install(self.root / 'install')
self.assertTrue(self.desktop.is_symlink())
self.assertEqual(target.read_bytes(), b'preserve')
self.assertFalse(self.state.exists())
def test_unsafe_exec_prefix_does_not_register_protocol(self):
for name in ('literal%U', 'quote"path', 'line\nbreak', 'tab\tpath', 'dollar$path'):
with self.subTest(prefix=name):
self.install(self.root / name)
self.assertFalse(self.desktop.exists())
self.assertFalse((self.data / 'applications/aego.desktop').exists())
self.assertFalse(self.state.exists())
class AppImageArgumentTests(unittest.TestCase):
def test_wrapper_preserves_url_as_one_restricted_argument(self):
# Exercise the shipped AppRun script without creating an AppImage,
# invoking appimagetool or touching an installed user application.
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
script = (Path(__file__).resolve().parents[2] / 'tools/release/appimage.sh').read_text()
begin = script.index('cat > "$app/AppRun" <<\'RUN\'\n') + len('cat > "$app/AppRun" <<\'RUN\'\n')
end = script.index('\nRUN\n', begin)
wrapper = root / 'AppRun'
wrapper.write_text(script[begin:end] + '\n')
wrapper.chmod(0o755)
binary = root / 'usr/bin/aego'
binary.parent.mkdir(parents=True)
binary.write_text(f'#!{sys.executable}\nimport json,sys\nprint(json.dumps(sys.argv[1:]))\n')
binary.chmod(0o755)
for incoming, expected in [
([], ['edit']),
(['/tmp/project.aego'], ['edit', '/tmp/project.aego']),
(['file:///tmp/My%20Game/project.aego'], ['edit', '--file-link', 'file:///tmp/My%20Game/project.aego']),
(['aego://example?manifest=https%3A%2F%2Fexample.invalid%2Fx'],
['edit', '--example-link', 'aego://example?manifest=https%3A%2F%2Fexample.invalid%2Fx']),
(['aego://example?x=y', '--tool'], ['edit', '--example-link', 'aego://example?x=y', '--tool']),
]:
result = subprocess.run([str(wrapper), *incoming], capture_output=True, text=True, check=True)
self.assertEqual(json.loads(result.stdout), expected)
if __name__ == '__main__':
unittest.main()