diff --git a/bumblebee/util.py b/bumblebee/util.py index 730ed87..07f8091 100644 --- a/bumblebee/util.py +++ b/bumblebee/util.py @@ -15,6 +15,8 @@ def execute(cmd, wait=True): out, _ = proc.communicate() if proc.returncode != 0: raise RuntimeError("{} exited with {}".format(cmd, proc.returncode)) + if type(out) == str: + return out return out.decode("utf-8") return None diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/mocks.py b/tests/mocks.py new file mode 100644 index 0000000..f60a9ee --- /dev/null +++ b/tests/mocks.py @@ -0,0 +1,27 @@ +# pylint: disable=C0103,C0111 + +import mock +import shlex +import subprocess + +class MockPopen(object): + def __init__(self, module): + self._patch = mock.patch("{}.subprocess.Popen".format(module)) + self._popen = self._patch.start() + self.mock = mock.Mock() + # for a nicer, more uniform interface + self.mock.popen = self._popen + # for easier command execution checks + self.mock.popen.assert_call = self.assert_call + self._popen.return_value = self.mock + + self.mock.communicate.return_value = [ "", None ] + self.mock.returncode = 0 + + def assert_call(self, cmd): + self.mock.popen.assert_called_with(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + def cleanup(self): + self._patch.stop() + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/__init__.py b/tests/modules/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/test_battery.py b/tests/modules/test_battery.py deleted file mode 100644 index 499a0fa..0000000 --- a/tests/modules/test_battery.py +++ /dev/null @@ -1,68 +0,0 @@ -# pylint: disable=C0103,C0111 - -import sys -import json -import unittest -import mock - -from contextlib import contextmanager - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.battery import Module -from tests.util import MockEngine, MockConfig, assertPopen - -class MockOpen(object): - def __init__(self): - self._value = "" - - def returns(self, value): - self._value = value - - def __enter__(self): - return self - - def __exit__(self, a, b, c): - pass - - def read(self): - return self._value - -class TestBatteryModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - for widget in self.module.widgets(): - widget.link_module(self.module) - - @mock.patch("sys.stdout") - def test_format(self, mock_output): - for widget in self.module.widgets(): - self.assertEquals(len(widget.full_text()), len("100%")) - - @mock.patch("os.path.exists") - @mock.patch("{}.open".format("__builtin__" if sys.version_info[0] < 3 else "builtins")) - @mock.patch("subprocess.Popen") - def test_critical(self, mock_output, mock_open, mock_exists): - mock_open.return_value = MockOpen() - mock_open.return_value.returns("19") - mock_exists.return_value = True - self.config.set("battery.critical", "20") - self.config.set("battery.warning", "25") - self.module.update(self.module.widgets()) - self.assertTrue("critical" in self.module.widgets()[0].state()) - - @mock.patch("os.path.exists") - @mock.patch("{}.open".format("__builtin__" if sys.version_info[0] < 3 else "builtins")) - @mock.patch("subprocess.Popen") - def test_warning(self, mock_output, mock_open, mock_exists): - mock_open.return_value = MockOpen() - mock_exists.return_value = True - mock_open.return_value.returns("22") - self.config.set("battery.critical", "20") - self.config.set("battery.warning", "25") - self.module.update(self.module.widgets()) - self.assertTrue("warning" in self.module.widgets()[0].state()) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_brightness.py b/tests/modules/test_brightness.py deleted file mode 100644 index b14af4b..0000000 --- a/tests/modules/test_brightness.py +++ /dev/null @@ -1,56 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.brightness import Module -from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent - -class TestBrightnessModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - for widget in self.module.widgets(): - widget.link_module(self.module) - - @mock.patch("sys.stdout") - def test_format(self, mock_output): - for widget in self.module.widgets(): - self.assertEquals(len(widget.full_text()), len("100%")) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_wheel_up(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.WHEEL_UP, - "xbacklight +2%" - ) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_wheel_down(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.WHEEL_DOWN, - "xbacklight -2%" - ) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_custom_step(self, mock_input, mock_output, mock_select): - self.config.set("brightness.step", "10") - module = Module(engine=self.engine, config={ "config": self.config }) - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - module, bumblebee.input.WHEEL_DOWN, - "xbacklight -10%" - ) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_caffeine.py b/tests/modules/test_caffeine.py deleted file mode 100644 index 995eece..0000000 --- a/tests/modules/test_caffeine.py +++ /dev/null @@ -1,21 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.caffeine import Module -from tests.util import MockEngine, MockConfig, assertPopen - -class TestCaffeineModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.engine.input.need_valid_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - for widget in self.module.widgets(): - widget.link_module(self.module) diff --git a/tests/modules/test_cmus.py b/tests/modules/test_cmus.py deleted file mode 100644 index 58be4bc..0000000 --- a/tests/modules/test_cmus.py +++ /dev/null @@ -1,58 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.cmus import Module -from tests.util import MockEngine, MockConfig, assertPopen, MockEpoll - -class TestCmusModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.module = Module(engine=self.engine, config={"config": MockConfig()}) - - @mock.patch("subprocess.Popen") - def test_read_song(self, mock_output): - rv = mock.Mock() - rv.configure_mock(**{ - "communicate.return_value": ("out", None) - }) - mock_output.return_value = rv - self.module.update(self.module.widgets()) - assertPopen(mock_output, "cmus-remote -Q") - - def test_widgets(self): - self.assertTrue(len(self.module.widgets()), 5) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_interaction(self, mock_input, mock_output, mock_select): - events = [ - {"widget": "cmus.shuffle", "action": "cmus-remote -S"}, - {"widget": "cmus.repeat", "action": "cmus-remote -R"}, - {"widget": "cmus.next", "action": "cmus-remote -n"}, - {"widget": "cmus.prev", "action": "cmus-remote -r"}, - {"widget": "cmus.main", "action": "cmus-remote -u"}, - ] - - mock_input.fileno.return_value = 1 - mock_select.return_value = MockEpoll() - - for event in events: - mock_input.readline.return_value = json.dumps({ - "name": self.module.id, - "button": bumblebee.input.LEFT_MOUSE, - "instance": self.module.widget(event["widget"]).id - }) - self.engine.input.start() - self.engine.input.stop() - mock_input.readline.assert_any_call() - assertPopen(mock_output, event["action"]) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_cpu.py b/tests/modules/test_cpu.py deleted file mode 100644 index fea056e..0000000 --- a/tests/modules/test_cpu.py +++ /dev/null @@ -1,48 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.cpu import Module -from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains - -class TestCPUModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - - @mock.patch("sys.stdout") - def test_format(self, mock_output): - for widget in self.module.widgets(): - self.assertEquals(len(widget.full_text()), len("100.00%")) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_leftclick(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.LEFT_MOUSE, - "gnome-system-monitor" - ) - - @mock.patch("psutil.cpu_percent") - def test_warning(self, mock_psutil): - self.config.set("cpu.critical", "20") - self.config.set("cpu.warning", "18") - mock_psutil.return_value = 19.0 - assertStateContains(self, self.module, "warning") - - @mock.patch("psutil.cpu_percent") - def test_critical(self, mock_psutil): - self.config.set("cpu.critical", "20") - self.config.set("cpu.warning", "19") - mock_psutil.return_value = 21.0 - assertStateContains(self, self.module, "critical") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_disk.py b/tests/modules/test_disk.py deleted file mode 100644 index 423612e..0000000 --- a/tests/modules/test_disk.py +++ /dev/null @@ -1,56 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.disk import Module -from tests.util import MockEngine, MockConfig, assertPopen, assertStateContains, MockEpoll - -class MockVFS(object): - def __init__(self, perc): - self.f_blocks = 1024*1024 - self.f_frsize = 1 - self.f_bavail = self.f_blocks - self.f_blocks*(perc/100.0) - -class TestDiskModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.config.set("disk.path", "somepath") - self.module = Module(engine=self.engine, config={"config": self.config}) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_leftclick(self, mock_input, mock_output, mock_select): - mock_input.readline.return_value = json.dumps({ - "name": self.module.id, - "button": bumblebee.input.LEFT_MOUSE, - "instance": None - }) - mock_select.return_value = MockEpoll() - self.engine.input.start() - self.engine.input.stop() - mock_input.readline.assert_any_call() - assertPopen(mock_output, "nautilus {}".format(self.module.parameter("path"))) - - @mock.patch("os.statvfs") - def test_warning(self, mock_stat): - self.config.set("disk.critical", "80") - self.config.set("disk.warning", "70") - mock_stat.return_value = MockVFS(75.0) - assertStateContains(self, self.module, "warning") - - @mock.patch("os.statvfs") - def test_critical(self, mock_stat): - self.config.set("disk.critical", "80") - self.config.set("disk.warning", "70") - mock_stat.return_value = MockVFS(85.0) - assertStateContains(self, self.module, "critical") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_load.py b/tests/modules/test_load.py deleted file mode 100644 index e4ed353..0000000 --- a/tests/modules/test_load.py +++ /dev/null @@ -1,47 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.load import Module -from tests.util import MockEngine, MockConfig, assertStateContains, assertMouseEvent - -class TestLoadModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_leftclick(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.LEFT_MOUSE, - "gnome-system-monitor" - ) - - @mock.patch("multiprocessing.cpu_count") - @mock.patch("os.getloadavg") - def test_warning(self, mock_loadavg, mock_cpucount): - self.config.set("load.critical", "1") - self.config.set("load.warning", "0.8") - mock_cpucount.return_value = 1 - mock_loadavg.return_value = [ 0.9, 0, 0 ] - assertStateContains(self, self.module, "warning") - - @mock.patch("multiprocessing.cpu_count") - @mock.patch("os.getloadavg") - def test_critical(self, mock_loadavg, mock_cpucount): - self.config.set("load.critical", "1") - self.config.set("load.warning", "0.8") - mock_cpucount.return_value = 1 - mock_loadavg.return_value = [ 1.1, 0, 0 ] - assertStateContains(self, self.module, "critical") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_memory.py b/tests/modules/test_memory.py deleted file mode 100644 index b32205d..0000000 --- a/tests/modules/test_memory.py +++ /dev/null @@ -1,47 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.memory import Module -from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains - -class VirtualMemory(object): - def __init__(self, percent): - self.percent = percent - -class TestMemoryModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_leftclick(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.LEFT_MOUSE, - "gnome-system-monitor" - ) - - @mock.patch("psutil.virtual_memory") - def test_warning(self, mock_vmem): - self.config.set("memory.critical", "80") - self.config.set("memory.warning", "70") - mock_vmem.return_value = VirtualMemory(75) - assertStateContains(self, self.module, "warning") - - @mock.patch("psutil.virtual_memory") - def test_critical(self, mock_vmem): - self.config.set("memory.critical", "80") - self.config.set("memory.warning", "70") - mock_vmem.return_value = VirtualMemory(85) - assertStateContains(self, self.module, "critical") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_modules.py b/tests/modules/test_modules.py deleted file mode 100644 index 59db4fa..0000000 --- a/tests/modules/test_modules.py +++ /dev/null @@ -1,57 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -import importlib -import mock - -from bumblebee.engine import all_modules -from bumblebee.config import Config -from tests.util import assertWidgetAttributes, MockEngine - -class MockCommunicate(object): - def __init__(self): - self.returncode = 0 - - def communicate(self): - return (str.encode("1"), "error") - -class TestGenericModules(unittest.TestCase): - @mock.patch("subprocess.Popen") - def setUp(self, mock_output): - mock_output.return_value = MockCommunicate() - engine = MockEngine() - config = Config() - self.objects = {} - for mod in all_modules(): - cls = importlib.import_module("bumblebee.modules.{}".format(mod["name"])) - self.objects[mod["name"]] = getattr(cls, "Module")(engine, {"config": config}) - for widget in self.objects[mod["name"]].widgets(): - self.assertEquals(widget.get("variable", None), None) - - @mock.patch("subprocess.Popen") - def test_widgets(self, mock_output): - mock_output.return_value = MockCommunicate() - for mod in self.objects: - widgets = self.objects[mod].widgets() - for widget in widgets: - widget.link_module(self.objects[mod]) - self.assertEquals(widget.module, mod) - assertWidgetAttributes(self, widget) - widget.set("variable", "value") - self.assertEquals(widget.get("variable", None), "value") - self.assertTrue(isinstance(widget.full_text(), str) or isinstance(widget.full_text(), unicode)) - - @mock.patch("subprocess.Popen") - def test_update(self, mock_output): - mock_output.return_value = MockCommunicate() - rv = mock.Mock() - rv.configure_mock(**{ - "communicate.return_value": ("out", None) - }) - for mod in self.objects: - widgets = self.objects[mod].widgets() - self.objects[mod].update(widgets) - self.test_widgets() - self.assertEquals(widgets, self.objects[mod].widgets()) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_pulseaudio.py b/tests/modules/test_pulseaudio.py deleted file mode 100644 index 5aae761..0000000 --- a/tests/modules/test_pulseaudio.py +++ /dev/null @@ -1,56 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from bumblebee.modules.pulseaudio import Module -from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains - -class TestPulseAudioModule(unittest.TestCase): - def setUp(self): - self.engine = MockEngine() - self.engine.input = I3BarInput() - self.engine.input.need_event = True - self.config = MockConfig() - self.module = Module(engine=self.engine, config={ "config": self.config }) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_leftclick(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.LEFT_MOUSE, - "pactl set-source-mute @DEFAULT_SOURCE@ toggle" - ) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_rightclick(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.RIGHT_MOUSE, - "pavucontrol" - ) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_wheelup(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.WHEEL_UP, - "pactl set-source-volume @DEFAULT_SOURCE@ +2%" - ) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_wheeldown(self, mock_input, mock_output, mock_select): - assertMouseEvent(mock_input, mock_output, mock_select, self.engine, - self.module, bumblebee.input.WHEEL_DOWN, - "pactl set-source-volume @DEFAULT_SOURCE@ -2%" - ) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_config.py b/tests/test_config.py deleted file mode 100644 index e7a05f9..0000000 --- a/tests/test_config.py +++ /dev/null @@ -1,52 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -import mock -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -from bumblebee.config import Config -from bumblebee.theme import themes -from bumblebee.engine import all_modules - -class TestConfig(unittest.TestCase): - def setUp(self): - self.defaultConfig = Config() - self.someSimpleModules = ["foo", "bar", "baz"] - self.someAliasModules = ["foo:a", "bar:b", "baz:c"] - - def test_no_modules_by_default(self): - self.assertEquals(self.defaultConfig.modules(), []) - - def test_simple_modules(self): - cfg = Config(["-m"] + self.someSimpleModules) - self.assertEquals(cfg.modules(), [{ - "name": x, "module": x - } for x in self.someSimpleModules]) - - def test_alias_modules(self): - cfg = Config(["-m"] + self.someAliasModules) - self.assertEquals(cfg.modules(), [{ - "module": x.split(":")[0], - "name": x.split(":")[1], - } for x in self.someAliasModules]) - - @mock.patch("sys.stdout", new_callable=StringIO) - @mock.patch("sys.exit") - def test_list_themes(self, exit, stdout): - cfg = Config(["-l", "themes"]) - result = stdout.getvalue() - for theme in themes(): - self.assertTrue(theme in result) - - @mock.patch("sys.stdout", new_callable=StringIO) - @mock.patch("sys.exit") - def test_list_modules(self, exit, stdout): - cfg = Config(["-l", "modules"]) - result = stdout.getvalue() - for module in all_modules(): - self.assertTrue(module["name"] in result) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_engine.py b/tests/test_engine.py deleted file mode 100644 index 0b71fd4..0000000 --- a/tests/test_engine.py +++ /dev/null @@ -1,83 +0,0 @@ -# pylint: disable=C0103,C0111,W0703,W0212 - -import shlex -import unittest - -from bumblebee.error import ModuleLoadError -from bumblebee.engine import Engine -from bumblebee.config import Config -import bumblebee.input - -from tests.util import MockOutput, MockInput - -class TestEngine(unittest.TestCase): - def setUp(self): - self.engine = Engine(config=Config(), output=MockOutput(), inp=MockInput()) - self.singleWidgetModule = [{"module": "test", "name": "a"}] - self.testModule = "test" - self.invalidModule = "no-such-module" - self.testModuleSpec = "bumblebee.modules.{}".format(self.testModule) - self.testModules = [ - {"module": "test", "name": "a"}, - {"module": "test", "name": "b"}, - ] - - def test_stop(self): - self.assertTrue(self.engine.running()) - self.engine.stop() - self.assertFalse(self.engine.running()) - - def test_load_module(self): - module = self.engine._load_module(self.testModule) - self.assertEquals(module.__module__, self.testModuleSpec) - - def test_load_invalid_module(self): - with self.assertRaises(ModuleLoadError): - self.engine._load_module(self.invalidModule) - - def test_load_none(self): - with self.assertRaises(ModuleLoadError): - self.engine._load_module(None) - - def test_load_modules(self): - modules = self.engine.load_modules(self.testModules) - self.assertEquals(len(modules), len(self.testModules)) - self.assertEquals( - [module.__module__ for module in modules], - [self.testModuleSpec for module in modules] - ) - - def test_run(self): - self.engine.load_modules(self.singleWidgetModule) - try: - self.engine.run() - except Exception as e: - self.fail(e) - - def test_custom_cmd(self): - testmodules = [ - { "name": "test", "button": "test.left-click", "action": "echo" }, - { "name": "test:alias", "button": "alias.right-click", "action": "echo2" }, - ] - cmd = "-m" - for test in testmodules: - cmd += " " + test["name"] - cmd += " -p" - for test in testmodules: - cmd += " " + test["button"] + "=" + test["action"] - cfg = Config(shlex.split(cmd)) - inp = MockInput() - engine = Engine(config=cfg, output=MockOutput(), inp=inp) - - i = 0 - for module in engine.modules(): - callback = inp.get_callback(module.id) - self.assertTrue(callback is not None) - self.assertEquals(callback["command"], testmodules[i]["action"]) - if "left" in testmodules[i]["button"]: - self.assertTrue(callback["button"], bumblebee.input.LEFT_MOUSE) - if "right" in testmodules[i]["button"]: - self.assertTrue(callback["button"], bumblebee.input.RIGHT_MOUSE) - i += 1 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_i3barinput.py b/tests/test_i3barinput.py deleted file mode 100644 index ca9892f..0000000 --- a/tests/test_i3barinput.py +++ /dev/null @@ -1,129 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -import json -import subprocess -import mock - -import bumblebee.input -from bumblebee.input import I3BarInput -from tests.util import MockWidget, MockModule, assertPopen, assertMouseEvent, MockEpoll - -class TestI3BarInput(unittest.TestCase): - def setUp(self): - self.input = I3BarInput() - self.input.need_event = True - self.anyModule = MockModule() - self.anyWidget = MockWidget("test") - self.anyModule.id = "test-module" - self._called = 0 - - def callback(self, event): - self._called += 1 - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_basic_read_event(self, mock_input, mock_select): - mock_input.readline.return_value = "somedata" - mock_input.fileno.return_value = 1 - mock_select.return_value = MockEpoll() - self.input.start() - self.input.stop() - mock_input.readline.assert_any_call() - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_ignore_invalid_data(self, mock_input, mock_select): - mock_select.return_value = MockEpoll() - mock_input.readline.return_value = "garbage" - self.input.start() - self.assertEquals(self.input.alive(), True) - self.assertEquals(self.input.stop(), True) - mock_input.readline.assert_any_call() - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_ignore_invalid_event(self, mock_input, mock_select): - mock_select.return_value = MockEpoll() - mock_input.readline.return_value = json.dumps({ - "name": None, - "instance": None, - "button": 1, - }) - self.input.start() - self.assertEquals(self.input.alive(), True) - self.assertEquals(self.input.stop(), True) - mock_input.readline.assert_any_call() - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_ignore_partial_event(self, mock_input, mock_select): - mock_select.return_value = MockEpoll() - self.input.register_callback(None, button=1, cmd=self.callback) - mock_input.readline.return_value = json.dumps({ - "button": 1, - }) - self.input.start() - self.assertEquals(self.input.alive(), True) - self.assertEquals(self.input.stop(), True) - mock_input.readline.assert_any_call() - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_global_callback(self, mock_input, mock_select): - self.input.register_callback(None, button=1, cmd=self.callback) - assertMouseEvent(mock_input, None, mock_select, self, None, - bumblebee.input.LEFT_MOUSE, None, "someinstance") - self.assertTrue(self._called > 0) - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_remove_global_callback(self, mock_input, mock_select): - self.input.register_callback(None, button=1, cmd=self.callback) - self.input.deregister_callbacks(None) - assertMouseEvent(mock_input, None, mock_select, self, None, - bumblebee.input.LEFT_MOUSE, None, "someinstance") - self.assertTrue(self._called == 0) - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_global_callback_button_missmatch(self, mock_input, mock_select): - self.input.register_callback(self.anyModule, button=1, cmd=self.callback) - assertMouseEvent(mock_input, None, mock_select, self, None, - bumblebee.input.RIGHT_MOUSE, None, "someinstance") - self.assertTrue(self._called == 0) - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_module_callback(self, mock_input, mock_select): - self.input.register_callback(self.anyModule, button=1, cmd=self.callback) - assertMouseEvent(mock_input, None, mock_select, self, self.anyModule, - bumblebee.input.LEFT_MOUSE, None) - self.assertTrue(self._called > 0) - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_remove_module_callback(self, mock_input, mock_select): - self.input.register_callback(self.anyModule, button=1, cmd=self.callback) - self.input.deregister_callbacks(self.anyModule) - assertMouseEvent(mock_input, None, mock_select, self, None, - bumblebee.input.LEFT_MOUSE, None, self.anyWidget.id) - self.assertTrue(self._called == 0) - - @mock.patch("select.epoll") - @mock.patch("sys.stdin") - def test_widget_callback(self, mock_input, mock_select): - self.input.register_callback(self.anyWidget, button=1, cmd=self.callback) - assertMouseEvent(mock_input, None, mock_select, self, None, - bumblebee.input.LEFT_MOUSE, None, self.anyWidget.id) - self.assertTrue(self._called > 0) - - @mock.patch("select.epoll") - @mock.patch("subprocess.Popen") - @mock.patch("sys.stdin") - def test_widget_cmd_callback(self, mock_input, mock_output, mock_select): - self.input.register_callback(self.anyWidget, button=1, cmd="echo") - assertMouseEvent(mock_input, mock_output, mock_select, self, None, - bumblebee.input.LEFT_MOUSE, "echo", self.anyWidget.id) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_i3baroutput.py b/tests/test_i3baroutput.py deleted file mode 100644 index f4c4cca..0000000 --- a/tests/test_i3baroutput.py +++ /dev/null @@ -1,104 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import unittest -import mock -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -from bumblebee.output import I3BarOutput -from tests.util import MockWidget, MockTheme, MockModule - -class TestI3BarOutput(unittest.TestCase): - def setUp(self): - self.theme = MockTheme() - self.output = I3BarOutput(self.theme) - self.expectedStart = json.dumps({"version": 1, "click_events": True}) + "[\n" - self.expectedStop = "]\n" - self.someWidget = MockWidget("foo bar baz") - self.anyModule = MockModule(None, None) - self.anyColor = "#ababab" - self.anotherColor = "#cccccc" - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_start(self, stdout): - self.output.start() - self.assertEquals(self.expectedStart, stdout.getvalue()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_stop(self, stdout): - self.output.stop() - self.assertEquals(self.expectedStop, stdout.getvalue()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_draw_single_widget(self, stdout): - self.output.draw(self.someWidget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["full_text"], self.someWidget.full_text()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_draw_multiple_widgets(self, stdout): - for widget in [self.someWidget, self.someWidget]: - self.output.draw(widget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue()) - for res in result: - self.assertEquals(res["full_text"], self.someWidget.full_text()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_begin(self, stdout): - self.output.begin() - self.assertEquals("", stdout.getvalue()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_end(self, stdout): - self.output.end() - self.assertEquals(",\n", stdout.getvalue()) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_prefix(self, stdout): - self.theme.attr_prefix = " - " - self.output.draw(self.someWidget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["full_text"], "{}{}".format( - self.theme.prefix(self.someWidget), self.someWidget.full_text()) - ) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_suffix(self, stdout): - self.theme.attr_suffix = " - " - self.output.draw(self.someWidget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["full_text"], "{}{}".format( - self.someWidget.full_text(), self.theme.suffix(self.someWidget)) - ) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_bothfix(self, stdout): - self.theme.attr_suffix = " - " - self.theme.attr_prefix = " * " - self.output.draw(self.someWidget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["full_text"], "{}{}{}".format( - self.theme.prefix(self.someWidget), - self.someWidget.full_text(), - self.theme.suffix(self.someWidget) - )) - - @mock.patch("sys.stdout", new_callable=StringIO) - def test_colors(self, stdout): - self.theme.attr_fg = self.anyColor - self.theme.attr_bg = self.anotherColor - self.output.draw(self.someWidget, self.anyModule) - self.output.flush() - result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["color"], self.anyColor) - self.assertEquals(result["background"], self.anotherColor) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_module.py b/tests/test_module.py deleted file mode 100644 index 0cc95ad..0000000 --- a/tests/test_module.py +++ /dev/null @@ -1,50 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import unittest - -from bumblebee.engine import Module -from bumblebee.config import Config -from tests.util import MockWidget - -class TestModule(unittest.TestCase): - def setUp(self): - self.widget = MockWidget("foo") - self.config = Config() - self.moduleWithoutWidgets = Module(engine=None, widgets=None) - self.moduleWithOneWidget = Module(engine=None, widgets=self.widget) - self.moduleWithMultipleWidgets = Module(engine=None, - widgets=[self.widget, self.widget, self.widget] - ) - - self.anyConfigName = "cfg" - self.anotherConfigName = "cfg2" - self.anyModule = Module(engine=None, widgets=self.widget, config={ - "name": self.anyConfigName, "config": self.config - }) - self.anotherModule = Module(engine=None, widgets=self.widget, config={ - "name": self.anotherConfigName, "config": self.config - }) - self.anyKey = "some-parameter" - self.anyValue = "value" - self.anotherValue = "another-value" - self.emptyKey = "i-do-not-exist" - self.config.set("{}.{}".format(self.anyConfigName, self.anyKey), self.anyValue) - self.config.set("{}.{}".format(self.anotherConfigName, self.anyKey), self.anotherValue) - - def test_empty_widgets(self): - self.assertEquals(self.moduleWithoutWidgets.widgets(), []) - - def test_single_widget(self): - self.assertEquals(self.moduleWithOneWidget.widgets(), [self.widget]) - - def test_multiple_widgets(self): - for widget in self.moduleWithMultipleWidgets.widgets(): - self.assertEquals(widget, self.widget) - - def test_parameters(self): - self.assertEquals(self.anyModule.parameter(self.anyKey), self.anyValue) - self.assertEquals(self.anotherModule.parameter(self.anyKey), self.anotherValue) - - def test_default_parameters(self): - self.assertEquals(self.anyModule.parameter(self.emptyKey), None) - self.assertEquals(self.anyModule.parameter(self.emptyKey, self.anyValue), self.anyValue) diff --git a/tests/test_store.py b/tests/test_store.py deleted file mode 100644 index 0b712f0..0000000 --- a/tests/test_store.py +++ /dev/null @@ -1,24 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import unittest - -from bumblebee.store import Store - -class TestStore(unittest.TestCase): - def setUp(self): - self.store = Store() - self.anyKey = "some-key" - self.anyValue = "some-value" - self.unsetKey = "invalid-key" - - def test_set_value(self): - self.store.set(self.anyKey, self.anyValue) - self.assertEquals(self.store.get(self.anyKey), self.anyValue) - - def test_get_invalid_value(self): - result = self.store.get(self.unsetKey) - self.assertEquals(result, None) - - def test_get_invalid_with_default_value(self): - result = self.store.get(self.unsetKey, self.anyValue) - self.assertEquals(result, self.anyValue) diff --git a/tests/test_theme.py b/tests/test_theme.py deleted file mode 100644 index ef356ca..0000000 --- a/tests/test_theme.py +++ /dev/null @@ -1,115 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import unittest -from bumblebee.theme import Theme -from bumblebee.error import ThemeLoadError -from tests.util import MockWidget - -class TestTheme(unittest.TestCase): - def setUp(self): - self.nonexistentThemeName = "no-such-theme" - self.invalidThemeName = "test_invalid" - self.validThemeName = "test" - self.themedWidget = MockWidget("bla") - self.theme = Theme(self.validThemeName) - self.cycleTheme = Theme("test_cycle") - self.anyWidget = MockWidget("bla") - self.anotherWidget = MockWidget("blub") - - data = self.theme.data() - self.widgetTheme = "test-widget" - self.themedWidget.module = self.widgetTheme - self.defaultColor = data["defaults"]["fg"] - self.defaultBgColor = data["defaults"]["bg"] - self.widgetColor = data[self.widgetTheme]["fg"] - self.widgetBgColor = data[self.widgetTheme]["bg"] - self.defaultPrefix = data["defaults"]["prefix"] - self.defaultSuffix = data["defaults"]["suffix"] - self.widgetPrefix = data[self.widgetTheme]["prefix"] - self.widgetSuffix = data[self.widgetTheme]["suffix"] - - def test_load_valid_theme(self): - try: - Theme(self.validThemeName) - except Exception as e: - self.fail(e) - - def test_load_nonexistent_theme(self): - with self.assertRaises(ThemeLoadError): - Theme(self.nonexistentThemeName) - - def test_load_invalid_theme(self): - with self.assertRaises(ThemeLoadError): - Theme(self.invalidThemeName) - - def test_default_prefix(self): - self.assertEquals(self.theme.prefix(self.anyWidget), self.defaultPrefix) - - def test_default_suffix(self): - self.assertEquals(self.theme.suffix(self.anyWidget), self.defaultSuffix) - - def test_widget_prefix(self): - self.assertEquals(self.theme.prefix(self.themedWidget), self.widgetPrefix) - - def test_widget_fg(self): - self.assertEquals(self.theme.fg(self.anyWidget), self.defaultColor) - self.anyWidget.module = self.widgetTheme - self.assertEquals(self.theme.fg(self.anyWidget), self.widgetColor) - - def test_widget_bg(self): - self.assertEquals(self.theme.bg(self.anyWidget), self.defaultBgColor) - self.anyWidget.module = self.widgetTheme - self.assertEquals(self.theme.bg(self.anyWidget), self.widgetBgColor) - - def test_absent_cycle(self): - theme = self.theme - try: - theme.fg(self.anyWidget) - theme.fg(self.anotherWidget) - except Exception as e: - self.fail(e) - - def test_reset(self): - theme = self.cycleTheme - data = theme.data() - theme.reset() - self.assertEquals(theme.fg(self.anyWidget), data["cycle"][0]["fg"]) - self.assertEquals(theme.fg(self.anotherWidget), data["cycle"][1]["fg"]) - theme.reset() - self.assertEquals(theme.fg(self.anyWidget), data["cycle"][0]["fg"]) - - def test_separator_block_width(self): - theme = self.theme - data = theme.data() - - self.assertEquals(theme.separator_block_width(self.anyWidget), - data["defaults"]["separator-block-width"] - ) - - def test_separator(self): - for theme in [self.theme, self.cycleTheme]: - theme.reset() - prev_bg = theme.bg(self.anyWidget) - theme.bg(self.anotherWidget) - - self.assertEquals(theme.separator_fg(self.anotherWidget), theme.bg(self.anotherWidget)) - self.assertEquals(theme.separator_bg(self.anotherWidget), prev_bg) - - def test_state(self): - theme = self.theme - data = theme.data() - - self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["fg"]) - self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["bg"]) - - self.anyWidget.attr_state = ["critical"] - self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["critical"]["fg"]) - self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["critical"]["bg"]) - - self.themedWidget.attr_state = ["critical"] - self.assertEquals(theme.fg(self.themedWidget), data[self.widgetTheme]["critical"]["fg"]) - # if elements are missing in the state theme, they are taken from the - # widget theme instead (i.e. no fallback to a more general state theme) - self.assertEquals(theme.bg(self.themedWidget), data[self.widgetTheme]["bg"]) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_util.py b/tests/test_util.py index b9b04c4..0720e34 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,18 +1,27 @@ # pylint: disable=C0103,C0111 +import mock import unittest +import mocks + from bumblebee.util import * class TestUtil(unittest.TestCase): + def setUp(self): + self.popen = mocks.MockPopen("bumblebee.util") + self.some_command_with_args = "sample-command -a -b -c" + self.some_utf8 = "some string".encode("utf-8") + + def tearDown(self): + self.popen.cleanup() + def test_bytefmt(self): - value = 10 - display = 10 - units = [ "B", "KiB", "MiB", "GiB" ] - for unit in units: - self.assertEquals(bytefmt(value), "{:.2f}{}".format(display, unit)) - value *= 1024 - self.assertEquals(bytefmt(value), "{:.2f}GiB".format(display*1024)) + self.assertEquals(bytefmt(10), "10.00B") + self.assertEquals(bytefmt(15*1024), "15.00KiB") + self.assertEquals(bytefmt(20*1024*1024), "20.00MiB") + self.assertEquals(bytefmt(22*1024*1024*1024), "22.00GiB") + self.assertEquals(bytefmt(35*1024*1024*1024*1024), "35840.00GiB") def test_durationfmt(self): self.assertEquals(durationfmt(00), "00:00") @@ -22,4 +31,20 @@ class TestUtil(unittest.TestCase): self.assertEquals(durationfmt(3600), "01:00:00") self.assertEquals(durationfmt(7265), "02:01:05") + def test_execute(self): + execute(self.some_command_with_args) + self.assertTrue(self.popen.mock.popen.called) + self.popen.mock.popen.assert_call(self.some_command_with_args) + self.assertTrue(self.popen.mock.communicate.called) + + def test_execute_utf8(self): + self.popen.mock.communicate.return_value = [ self.some_utf8, None ] + self.test_execute() + + def test_execute_error(self): + self.popen.mock.returncode = 1 + + with self.assertRaises(RuntimeError): + execute(self.some_command_with_args) + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/util.py b/tests/util.py deleted file mode 100644 index c0f244d..0000000 --- a/tests/util.py +++ /dev/null @@ -1,162 +0,0 @@ -# pylint: disable=C0103,C0111,W0613 - -import json -import shlex -import subprocess - -from bumblebee.output import Widget - -def assertWidgetAttributes(test, widget): - test.assertTrue(isinstance(widget, Widget)) - test.assertTrue(hasattr(widget, "full_text")) - -def assertPopen(output, cmd): - res = shlex.split(cmd) - output.assert_any_call(res, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) - -def assertStateContains(test, module, state): - for widget in module.widgets(): - widget.link_module(module) - module.update(module.widgets()) - test.assertTrue(state in module.widgets()[0].state()) - -class MockEpoll(object): - def register(self, fileno, event): - pass - - def poll(self, timeout): - return [(1,2)] - - def unregister(self, fileno): - pass - - def close(self): - pass - -def assertMouseEvent(mock_input, mock_output, mock_select, engine, module, button, cmd, instance_id=None): - mock_input.readline.return_value = json.dumps({ - "name": module.id if module else "test", - "button": button, - "instance": instance_id - }) - mock_input.fileno.return_value = 1 - mock_select.return_value = MockEpoll() - engine.input.start() - engine.input.stop() - mock_input.readline.assert_any_call() - if cmd: - assertPopen(mock_output, cmd) - -class MockInput(object): - def __init__(self): - self._callbacks = {} - def start(self): - pass - - def stop(self): - pass - - def get_callback(self, uid): - return self._callbacks.get(uid, None) - - def register_callback(self, obj, button, cmd): - if not obj: - return - self._callbacks[obj.id] = { - "button": button, - "command": cmd, - } - -class MockEngine(object): - def __init__(self): - self.input = MockInput() - -class MockConfig(object): - def __init__(self): - self._data = {} - - def get(self, name, default): - if name in self._data: - return self._data[name] - return default - - def set(self, name, value): - self._data[name] = value - -class MockOutput(object): - def start(self): - pass - - def stop(self): - pass - - def draw(self, widget, engine, module): - engine.stop() - - def begin(self): - pass - - def flush(self): - pass - - def end(self): - pass - -class MockModule(object): - def __init__(self, engine=None, config=None): - self.id = None - -class MockWidget(Widget): - def __init__(self, text): - super(MockWidget, self).__init__(text) - self._text = text - self.module = None - self.attr_state = ["state-default"] - self.id = "none" - - def state(self): - return self.attr_state - - def update(self, widgets): - pass - - def full_text(self): - return self._text - -class MockTheme(object): - def __init__(self): - self.attr_prefix = None - self.attr_suffix = None - self.attr_fg = None - self.attr_bg = None - self.attr_separator = None - self.attr_separator_block_width = 0 - - def padding(self, widget): - return "" - - def reset(self): - pass - - def separator_block_width(self, widget): - return self.attr_separator_block_width - - def separator(self, widget): - return self.attr_separator - - def prefix(self, widget, default=None): - return self.attr_prefix - - def suffix(self, widget, default=None): - return self.attr_suffix - - def fg(self, widget): - return self.attr_fg - - def bg(self, widget): - return self.attr_bg - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4