Dotfiles_ArchAP/tests/test_wallpaper_analysis.py

92 lines
3.9 KiB
Python

"""Propriétés de l'analyse locale, sur des images synthétiques temporaires."""
import sys
from pathlib import Path
import tempfile
import unittest
from unittest import mock
from PIL import Image
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'bin/.local/bin'))
import wallpaper_analysis as analysis
import importlib.util
source = Path(__file__).resolve().parents[1] / 'bin/.local/bin/wallpaper-manager.py'
spec = importlib.util.spec_from_file_location('wallpaper_manager_analysis_tests', source)
manager = importlib.util.module_from_spec(spec)
spec.loader.exec_module(manager)
class WallpaperAnalysisTest(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.root = Path(self.temp.name)
self.cache_patch = mock.patch.object(analysis, 'CACHE', self.root / 'cache')
self.cache_patch.start()
def tearDown(self):
self.cache_patch.stop()
self.temp.cleanup()
def result(self, name, image):
path = self.root / name
image.save(path)
return analysis.analyze(manager.validate_image(path))
def test_linear_luminance_and_four_flavors(self):
self.assertAlmostEqual(analysis.linear_channel(0), 0)
self.assertAlmostEqual(analysis.linear_channel(1), 1)
self.assertAlmostEqual(analysis.linear_channel(128 / 255), 0.21586, places=4)
colors = [(0, 'mocha'), (40, 'mocha'), (80, 'mocha'),
(128, 'macchiato'), (192, 'frappe'),
(224, 'latte'), (255, 'latte')]
for value, flavor in colors:
with self.subTest(value=value):
result = self.result(f'gris {value} été.png', Image.new('RGB', (100, 80), (value, value, value)))
self.assertEqual(result['flavor'], flavor)
self.assertAlmostEqual(result['mean'], result['median'], places=6)
self.assertLessEqual(result['p10'], result['p90'])
def test_bimodal_weight_and_gradient(self):
split = Image.new('RGB', (100, 40), 'black')
split.paste('white', (50, 0, 100, 40))
result = self.result('moitié noir blanc.png', split)
self.assertEqual(result['flavor'], 'frappe')
self.assertGreater(result['p90'], 0.9)
self.assertLess(result['p10'], 0.1)
dark = Image.new('RGB', (100, 40), 'black')
dark.paste('white', (80, 0, 100, 40))
self.assertEqual(self.result('majorité sombre.png', dark)['flavor'], 'mocha')
bright = Image.new('RGB', (100, 40), 'white')
bright.paste('black', (0, 0, 20, 40))
self.assertEqual(self.result('majorité claire.png', bright)['flavor'], 'latte')
gradient = Image.new('RGB', (256, 8))
gradient.putdata([(x, x, x) for _ in range(8) for x in range(256)])
graded = self.result('gradient.png', gradient)
self.assertEqual(graded['flavor'], 'macchiato')
self.assertLess(graded['p10'], graded['median'])
self.assertLess(graded['median'], graded['p90'])
def test_cache_invalidated_by_content_and_version(self):
path = self.root / 'image.png'
Image.new('RGB', (20, 20), 'black').save(path)
first = manager.validate_image(path)
self.assertEqual(analysis.analyze(first)['flavor'], 'mocha')
key = analysis.cache_key(first)
Image.new('RGB', (25, 25), 'white').save(path)
second = manager.validate_image(path)
self.assertNotEqual(key, analysis.cache_key(second))
self.assertEqual(analysis.analyze(second)['flavor'], 'latte')
second_key = analysis.cache_key(second)
with mock.patch.object(analysis, 'ALGORITHM_VERSION', analysis.ALGORITHM_VERSION + 1):
self.assertNotEqual(analysis.cache_key(second), second_key)
def test_invalid_image_rejected(self):
path = self.root / 'faux.png'
path.write_text('pas une image')
with self.assertRaises(Exception):
manager.validate_image(path)
if __name__ == '__main__':
unittest.main()