#!/usr/bin/env python import unittest from unittest.mock import MagicMock import string import random import types import pytest from i3pystatus.core.exceptions import ConfigAmbigiousClassesError, ConfigInvalidModuleError from i3pystatus.core import util, ClassFinder def test_lchop_prefixed(): assert util.lchop("12345", "12") == "345" def test_lchop_no_prefix(): assert util.lchop("345", "") == "345" def test_lchop_unmatched(): assert util.lchop("12345", "345") == "12345" @pytest.mark.parametrize("iterable, limit, assrt", [ ([1, 2, 3, 4], 3, [[1, 2], [3], [4]]), ([2, 1, 3, 4], 3, [[1, 2], [3], [4]]), ([0.33, 0.45, 0.89], 1, [[0.33, 0.45, 0.89]]), ([], 10, []), ]) def test_partition(iterable, limit, assrt): partitions = util.partition(iterable, limit) partitions = [sorted(partition) for partition in partitions] for item in assrt: assert sorted(item) in partitions @pytest.mark.parametrize("iterable, predicate, assrt", [ ([1, 2, 3, 4], lambda x: x < 2, []), ([1, 2, 3, 4], lambda x: x < 5 and x > 2, [4, 3]), ([1, 2, 3, 4], lambda x: x == 4, [4]), ([1, 2, 3, 4], lambda x: True, [4, 3, 2, 1]), ([1, 2], lambda x: False, []), ]) def test_popwhile(iterable, predicate, assrt): assert list(util.popwhile(predicate, iterable)) == assrt @pytest.mark.parametrize("valid, required, feed, missing", [ # ( valid, required, feed, missing ) (("foo", "bar", "baz"), ("foo",), ("bar",), ("foo",)), (("foo", "bar", "baz"), ("foo",), tuple(), ("foo",)), (("foo", "bar", "baz"), ("bar", "baz"), ("bar", "baz"), tuple()), (("foo", "bar", "baz"), ("bar", "baz"), ("bar", "foo", "baz"), tuple()), ]) def test_keyconstraintdict_missing(valid, required, feed, missing): kcd = util.KeyConstraintDict(valid_keys=valid, required_keys=required) kcd.update(dict.fromkeys(feed)) assert kcd.missing() == set(missing) class ModuleListTests(unittest.TestCase): class ModuleBase: pass def setUp(self): self.status_handler = MagicMock() self.ml = util.ModuleList(self.status_handler, ClassFinder(self.ModuleBase)) def test_append_simple(self): module = self.ModuleBase() module.registered = MagicMock() self.ml.append(module) module.registered.assert_called_with(self.status_handler) def _create_module_class(self, name, bases=None): if not bases: bases = (self.ModuleBase,) return type(name, bases, { "registered": MagicMock(), "__init__": MagicMock(return_value=None), }) def test_append_class_instanciation(self): module_class = self._create_module_class("module_class") self.ml.append(module_class) module_class.__init__.assert_called_with() module_class.registered.assert_called_with(self.status_handler) def test_append_module(self): pymod = types.ModuleType("test_mod") pymod.some_class = self._create_module_class("some_class") pymod.some_class.__module__ = "test_mod" self.ml.append(pymod) pymod.some_class.__init__.assert_called_with() pymod.some_class.registered.assert_called_with(self.status_handler) def test_append_module2(self): # Here we test if imported classes are ignored as they should pymod = types.ModuleType("test_mod") pymod.some_class = self._create_module_class("some_class") pymod.some_class.__module__ = "other_module" with self.assertRaises(ConfigInvalidModuleError): self.ml.append(pymod) assert not pymod.some_class.__init__.called assert not pymod.some_class.registered.called def test_ambigious_classdef(self): pymod = types.ModuleType("test_mod") pymod.some_class = self._create_module_class("some_class") pymod.some_class.__module__ = "test_mod" pymod.some_other_class = self._create_module_class("some_other_class") pymod.some_other_class.__module__ = "test_mod" with self.assertRaises(ConfigAmbigiousClassesError): self.ml.append(pymod) def test_invalid_module(self): pymod = types.ModuleType("test_mod") with self.assertRaises(ConfigInvalidModuleError): self.ml.append(pymod) def test_append_class_inheritance(self): in_between = self._create_module_class("in_between") cls = self._create_module_class("cls", (in_between,)) self.ml.append(cls) cls.__init__.assert_called_with() cls.registered.assert_called_with(self.status_handler) class KeyConstraintDictAdvancedTests(unittest.TestCase): def test_invalid_1(self): kcd = util.KeyConstraintDict(valid_keys=tuple(), required_keys=tuple()) with self.assertRaises(KeyError): kcd["invalid"] = True def test_invalid_2(self): kcd = util.KeyConstraintDict( valid_keys=("foo", "bar"), required_keys=tuple()) with self.assertRaises(KeyError): kcd["invalid"] = True def test_incomplete_iteration(self): kcd = util.KeyConstraintDict( valid_keys=("foo", "bar"), required_keys=("foo",)) with self.assertRaises(util.KeyConstraintDict.MissingKeys): for x in kcd: pass def test_completeness(self): kcd = util.KeyConstraintDict( valid_keys=("foo", "bar"), required_keys=("foo",)) kcd["foo"] = False for x in kcd: pass assert kcd.missing() == set() def test_remove_required(self): kcd = util.KeyConstraintDict( valid_keys=("foo", "bar"), required_keys=("foo",)) kcd["foo"] = None assert kcd.missing() == set() del kcd["foo"] assert kcd.missing() == {"foo"} def test_set_twice(self): kcd = util.KeyConstraintDict( valid_keys=("foo", "bar"), required_keys=("foo",)) kcd["foo"] = 1 kcd["foo"] = 2 assert kcd.missing() == set() del kcd["foo"] assert kcd.missing() == {"foo"} class FormatPTests(unittest.TestCase): def test_escaping(self): assert util.formatp(r"[razamba \[ mabe \]]") == "razamba [ mabe ]" def test_numerical(self): assert util.formatp("[{t} - [schmuh {x}]]", t=1, x=2) == "1 - schmuh 2" assert util.formatp("[{t} - [schmuh {x}]]", t=1, x=0) == "1 - " assert util.formatp("[{t} - [schmuh {x}]]", t=0, x=0) == "" def test_nesting(self): s = "[[{artist} - ]{album} - ]{title}" assert util.formatp(s, title="Black rose") == "Black rose" assert util.formatp( s, artist="In Flames", title="Gyroscope") == "Gyroscope" assert util.formatp( s, artist="SOAD", album="Toxicity", title="Science") == "SOAD - Toxicity - Science" assert util.formatp( s, album="Toxicity", title="Science") == "Toxicity - Science" def test_bare(self): assert util.formatp("{foo} blar", foo="bar") == "bar blar" def test_presuffix(self): assert util.formatp( "ALINA[{title} schnacke]KOMMAHER", title="") == "ALINAKOMMAHER" assert util.formatp("grml[{title}]") == "grml" assert util.formatp("[{t}]grml") == "grml" def test_side_by_side(self): s = "{status} [{artist} / [{album} / ]]{title}[ {song_elapsed}/{song_length}]" assert util.formatp(s, status="▷", title="Only For The Weak", song_elapsed="1:41", song_length="4:55") == "▷ Only For The Weak 1:41/4:55" assert util.formatp( s, status="", album="Foo", title="Die, Die, Crucified", song_elapsed="2:52") == " Die, Die, Crucified" assert util.formatp("[[{a}][{b}]]", b=1) == "1" def test_complex_field(self): class NS: pass obj = NS() obj.attr = "bar" s = "[{a:.3f} m]{obj.attr}" assert util.formatp(s, a=3.14123456789, obj=obj) == "3.141 mbar" assert util.formatp(s, a=0.0, obj=obj) == "bar"