Dotfiles_ArchAP/tests/test_location_time_manager.py

148 lines
7.1 KiB
Python

"""Tests du contrat voyage, avec coordonnées exclusivement synthétiques."""
import importlib.util
import json
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
SOURCE = Path(__file__).resolve().parents[1] / 'bin/.local/bin/location-time-manager.py'
SPEC = importlib.util.spec_from_file_location('location_time_manager', SOURCE)
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
class LocationTimeTests(unittest.TestCase):
def test_zone1970_and_search(self):
entries = MODULE.presets()
self.assertGreater(len(entries), 200)
self.assertTrue(MODULE.search(entries, 'Europe/Paris'))
self.assertTrue(MODULE.search(entries, 'London'))
self.assertTrue(MODULE.search(entries, 'madrid'))
self.assertEqual(MODULE.search(entries, 'lieu-introuvable'), [])
def test_zone1970_synthetic_fixture(self):
with tempfile.TemporaryDirectory() as directory:
fixture = Path(directory) / 'zone1970.tab'
fixture.write_text('# synthetic\nXX,YY\t+1230-04515\tEurope/Paris\tLieu synthétique\n', encoding='utf-8')
items = MODULE.presets(fixture)
self.assertEqual(len(items), 1)
self.assertEqual(items[0]['countries'], ['XX', 'YY'])
self.assertEqual(items[0]['comment'], 'Lieu synthétique')
self.assertEqual((items[0]['latitude'], items[0]['longitude']), (12.5, -45.25))
def test_invalid_timezone(self):
for value in ('', '../../etc/passwd', '/etc/passwd', 'Europe/Impossible',
'Europe/Paris\n', 'Europe/Paris\0', 'Europe/../Paris'):
with self.subTest(value=repr(value)):
self.assertFalse(MODULE.timezone_valid(value))
self.assertTrue(MODULE.timezone_valid('Europe/Paris'))
self.assertTrue(MODULE.timezone_valid('UTC'))
def test_invalid_coordinates(self):
for lat, lon in ((91, 0), (0, 181), ('nan', 0), ('', 0), ('texte', 0), (0, '')):
with self.subTest(lat=lat, lon=lon):
with self.assertRaises(ValueError):
MODULE.coordinates(lat, lon)
self.assertEqual(MODULE.coordinates('12.5', '-30'), (12.5, -30.0))
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
base = Path(self.temp.name)
self.config = base / 'preferences.json'
self.state = base / 'effective.json'
self.lock = base / 'wallpaper.lock'
self.config.write_text(json.dumps({'version': 4, 'nightLightMode': 'auto',
'nightTemperature': 3000, 'dayTemperature': 6500, 'scheduleType': 'solar',
'latitude': 10, 'longitude': 20}), encoding='utf-8')
self.state.write_text('{}', encoding='utf-8')
self.original = self.config.read_bytes()
for name, value in (('CONFIG', self.config), ('STATE', self.state), ('LOCK', self.lock)):
patcher = patch.object(MODULE, name, value)
patcher.start(); self.addCleanup(patcher.stop)
self.zone = ['Europe/Paris']
patcher = patch.object(MODULE, 'current_timezone', side_effect=lambda: self.zone[0])
patcher.start(); self.addCleanup(patcher.stop)
patcher = patch.object(MODULE, 'set_timezone', side_effect=lambda tz: self.zone.__setitem__(0, tz))
self.setter = patcher.start(); self.addCleanup(patcher.stop)
original_night = MODULE.night_module
def mocked_night():
night = original_night()
night.apply_service = self.service
night.verify = self.verify
return night
self.service_calls = []
self.service = lambda pref, suspended: self.service_calls.append((pref['nightLightMode'], suspended))
self.verify = lambda pref, suspended: None
patcher = patch.object(MODULE, 'night_module', side_effect=mocked_night)
patcher.start(); self.addCleanup(patcher.stop)
def test_timezone_only(self):
MODULE.apply('timezone', timezone='Europe/London')
self.assertEqual(self.zone[0], 'Europe/London')
self.assertEqual(self.config.read_bytes(), self.original)
self.assertEqual(self.service_calls, [])
def test_solar_only_auto(self):
MODULE.apply('solar', latitude=11, longitude=21)
self.assertEqual(self.zone[0], 'Europe/Paris')
self.assertEqual(self.service_calls, [('auto', False)])
pref = json.loads(self.config.read_text())
self.assertEqual((pref['latitude'], pref['longitude']), (11, 21))
def test_both_and_timezone_failure(self):
MODULE.apply('both', timezone='Europe/London', latitude=11, longitude=21)
self.assertEqual(self.zone[0], 'Europe/London')
self.assertEqual(len(self.service_calls), 1)
self.zone[0] = 'Europe/Paris'
self.config.write_bytes(self.original)
self.setter.side_effect = RuntimeError('authentification refusée')
with self.assertRaises(RuntimeError):
MODULE.apply('both', timezone='Europe/London', latitude=11, longitude=21)
self.assertEqual(self.config.read_bytes(), self.original)
def test_rollback_on_reconcile_failure(self):
def fail(pref, suspended):
if pref['latitude'] == 11:
raise RuntimeError('service indisponible')
self.service = fail
with self.assertRaises(RuntimeError):
MODULE.apply('both', timezone='Europe/London', latitude=11, longitude=21)
self.assertEqual(self.zone[0], 'Europe/Paris')
self.assertEqual(self.config.read_bytes(), self.original)
def test_timezone_rollback_even_if_service_rollback_fails(self):
self.service = lambda pref, suspended: (_ for _ in ()).throw(RuntimeError('service indisponible'))
with self.assertRaisesRegex(RuntimeError, 'rollback incomplet'):
MODULE.apply('both', timezone='Europe/London', latitude=11, longitude=21)
self.assertEqual(self.zone[0], 'Europe/Paris')
self.assertEqual(self.config.read_bytes(), self.original)
def test_off_on_and_sun_do_not_restart(self):
pref = json.loads(self.original)
pref['nightLightMode'] = 'off'
self.config.write_text(json.dumps(pref))
MODULE.apply('solar', latitude=11, longitude=21)
self.assertEqual(self.service_calls, [])
pref['nightLightMode'] = 'on'
self.config.write_text(json.dumps(pref))
MODULE.apply('solar', latitude=12, longitude=22)
self.assertEqual(self.service_calls, [])
pref['nightLightMode'] = 'auto'
self.config.write_text(json.dumps(pref))
self.state.write_text(json.dumps({'effectiveMode': 'sun-light'}))
MODULE.apply('solar', latitude=12, longitude=22)
self.assertEqual(self.service_calls, [])
def test_saved_location(self):
MODULE.save_location('Lieu synthétique', 'Europe/London', 11, 22)
result = json.loads(self.config.read_text())
self.assertEqual(len(result['savedLocations']), 1)
self.assertEqual(result['savedLocations'][0]['name'], 'Lieu synthétique')
with self.assertRaises(ValueError):
MODULE.save_location('', 'Europe/London', 11, 22)
if __name__ == '__main__':
unittest.main()