[core] Rework core implementation

Experimental re-implementation of core functionality with the aim:
- Depend only on the Python Standard Library for core
- If modules are missing elsewhere, *never* throw
- Unit test *everything*
- Cleaner and more minimal implementation
- Better integration points for existing implementations (charts,
  braille, etc.)
- Full backwards-compatibility with existing module system (except where
  modules can be vastly simplified)
This commit is contained in:
Tobias Witek 2020-01-19 13:29:34 +01:00
parent 72f88b3409
commit e931bb93c6
214 changed files with 45 additions and 13040 deletions

View file

View file

@ -1,141 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import json
import shlex
import random
import subprocess
from bumblebee.input import I3BarInput
from bumblebee.output import Widget
from bumblebee.config import Config
def rand(cnt):
return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for i in range(cnt))
def setup_test(test, Module):
test._stdin, test._select, test.stdin, test.select = poll_mock("bumblebee.input")
test.popen = MockPopen()
test.config = Config()
test.input = I3BarInput()
test.engine = mock.Mock()
test.engine.input = test.input
test.input.need_event = True
test.module = Module(engine=test.engine, config={ "config": test.config })
for widget in test.module.widgets():
widget.link_module(test.module)
test.anyWidget = widget
def teardown_test(test):
test._stdin.stop()
test._select.stop()
test.popen.cleanup()
def poll_mock(module=""):
if len(module) > 0: module = "{}.".format(module)
stdin = mock.patch("{}sys.stdin".format(module))
select = mock.patch("{}select".format(module))
poll = mock.Mock()
stdin_mock = stdin.start()
select_mock = select.start()
stdin_mock.fileno.return_value = 1
select_mock.poll.return_value = poll
poll.poll.return_value = [(stdin_mock.fileno.return_value, 100)]
return stdin, select, stdin_mock, select_mock
def mouseEvent(stdin, button, inp, module=None, instance=None):
stdin.readline.return_value = json.dumps({
"name": module.id if module else rand(10),
"button": button,
"instance": instance
})
inp.start()
inp.stop()
stdin.readline.assert_any_call()
class MockPopen(object):
def __init__(self, module=""):
if len(module) > 0: module = "{}.".format(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_any_call(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def cleanup(self):
self._patch.stop()
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 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 MockEngine(object):
def __init__(self):
self.input = MockInput()
class MockWidget(Widget):
def __init__(self, text):
super(MockWidget, self).__init__(text)
self.module = None
self.attr_state = ["state-default"]
self.id = rand(10)
self.full_text(text)
# def state(self):
# return self.attr_state
def update(self, widgets):
pass
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,109 +0,0 @@
# pylint: disable=C0103,C0111
import sys
import mock
import unittest
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import tests.mocks as mocks
from bumblebee.modules.battery import Module
from bumblebee.config import Config
class TestBatteryModule(unittest.TestCase):
def setUp(self):
self._stdout = mock.patch("sys.stdout", new_callable=StringIO)
self._exists = mock.patch("bumblebee.modules.battery.os.path.exists")
self._open = mock.patch("bumblebee.modules.battery.open", create=True)
self.stdout = self._stdout.start()
self.exists = self._exists.start()
self.open = self._open.start()
self.file = mock.Mock()
self.file.__enter__ = lambda x: self.file
self.file.__exit__ = lambda x, a, b, c: ""
self.file.read.return_value = "120"
self.open.return_value = self.file
self.exists.return_value = True
self.engine = mock.Mock()
self.config = Config()
self.config.set("battery.showremaining", "false")
self.module = Module(engine=self.engine, config={"config":self.config})
self.config.set("battery.critical", "20")
self.config.set("battery.warning", "25")
self.criticalValue = "19"
self.warningValue = "21"
self.normalValue = "26"
self.chargedValue = "96"
self.module.widgets()[0]
def tearDown(self):
self._stdout.stop()
self._exists.stop()
self._open.stop()
def test_format(self):
for widget in self.module.widgets():
self.assertEquals(len(widget.full_text()), len("100%"))
def test_critical(self):
self.file.read.return_value = self.criticalValue
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.module.widgets()[0]))
def test_warning(self):
self.file.read.return_value = self.warningValue
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.module.widgets()[0]))
def test_normal(self):
self.file.read.return_value = self.normalValue
self.module.update_all()
self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0]))
self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0]))
def test_overload(self):
self.file.read.return_value = "120"
self.module.update_all()
self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0]))
self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0]))
self.assertEquals(self.module.capacity(self.module.widgets()[0]), "100%")
def test_ac(self):
self.exists.return_value = False
self.file.read.return_value = "120"
self.module.update_all()
self.assertEquals(self.module.capacity(self.module.widgets()[0]), "ac")
self.assertTrue("AC" in self.module.state(self.module.widgets()[0]))
def test_error(self):
self.file.read.side_effect = IOError("failed to read")
self.module.update_all()
self.assertEquals(self.module.capacity(self.module.widgets()[0]), "n/a")
self.assertTrue("critical" in self.module.state(self.module.widgets()[0]))
self.assertTrue("unknown" in self.module.state(self.module.widgets()[0]))
def test_charging(self):
self.file.read.return_value = self.chargedValue
self.module.update_all()
self.assertTrue("charged" in self.module.state(self.module.widgets()[0]))
self.file.read.return_value = self.normalValue
self.module.update_all()
self.assertTrue("charging" in self.module.state(self.module.widgets()[0]))
def test_discharging(self):
for limit in [ 10, 25, 50, 80, 100 ]:
value = limit - 1
self.file.read.return_value = str(value)
self.module.update_all()
self.file.read.return_value = "Discharging"
self.assertTrue("discharging-{}".format(limit) in self.module.state(self.module.widgets()[0]))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,69 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
try:
FileNotFoundError
except NameError:
FileNotFoundError = IOError
import tests.mocks as mocks
import bumblebee.util
from bumblebee.config import Config
from bumblebee.input import WHEEL_UP, WHEEL_DOWN
from bumblebee.modules.brightness import Module
class TestBrightnessModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self.tool = ""
self.up = ""
self.down = ""
if bumblebee.util.which("light"):
self.tool = "light"
self.up = "-A {}%"
self.down = "-U {}%"
elif bumblebee.util.which("brightnessctl"):
self.tool = "brightnessctl"
self.up = "s {}%+"
self.down = "s {}%-"
else:
self.tool = "xbacklight"
self.up = "+{}%"
self.down = "-{}%"
def tearDown(self):
mocks.teardown_test(self)
# def test_format(self):
# for widget in self.module.widgets():
# self.assertEquals(len(widget.full_text()), len("100%"))
def test_wheel_up(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_UP, inp=self.input, module=self.module)
self.popen.assert_call("{} {}".format(self.tool, self.up.format(2)))
def test_wheel_down(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=self.module)
self.popen.assert_call("{} {}".format(self.tool, self.down.format(2)))
def test_custom_step(self):
self.config.set("brightness.step", "10")
module = Module(engine=self.engine, config={"config": self.config})
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=module)
self.popen.assert_call("{} {}".format(self.tool, self.down.format(10)))
@mock.patch('bumblebee.modules.brightness.open', create=True)
def test_error(self,mock_open):
mock_open.side_effect = FileNotFoundError
self.module.update_all()
self.assertEquals(self.module.brightness(self.anyWidget), "n/a")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,50 +0,0 @@
# pylint: disable=C0103,C0111
import unittest
from mock import patch
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.caffeine import Module
class TestCaffeineModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
def tearDown(self):
mocks.teardown_test(self)
def test_check_requirements(self):
with patch('bumblebee.util.which', side_effect=['', 'xprop', 'xdg-screensaver']):
self.assertTrue(['xdotool'] == self.module._check_requirements())
def test_get_i3bar_xid_returns_digit(self):
self.popen.mock.communicate.return_value = ("8388614", None)
self.assertTrue(self.module._get_i3bar_xid().isdigit())
def test_get_i3bar_xid_returns_error_string(self):
self.popen.mock.communicate.return_value = ("Some error message", None)
self.assertTrue(self.module._get_i3bar_xid() is None)
def test_get_i3bar_xid_returns_empty_string(self):
self.popen.mock.communicate.return_value = ("", None)
self.assertTrue(self.module._get_i3bar_xid() is None)
def test_suspend_screensaver_success(self):
with patch.object(self.module, '_get_i3bar_xid', return_value=8388614):
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._suspend_screensaver() is True)
def test_suspend_screensaver_fail(self):
with patch.object(self.module, '_get_i3bar_xid', return_value=None):
self.module._active = False
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._suspend_screensaver() is False)
def test_resume_screensaver(self):
with patch.object(self.module, '_check_requirements', return_value=[]):
self.module._active = True
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._resume_screensaver() is True)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,114 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.cmus import Module
class TestCmusModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self.songTemplate = """
status {status}
file /path/to/file
duration {duration}
position {position}
tag title {title}
tag artist {artist}
tag album {album}
tag tracknumber 1
tag date 1984
tag comment comment
"""
def tearDown(self):
mocks.teardown_test(self)
def test_read_song(self):
self.popen.mock.communicate.return_value = ("song", None)
self.module.update_all()
self.popen.assert_call("cmus-remote -Q")
def test_handle_runtimeerror(self):
self.popen.mock.communicate.side_effect = RuntimeError("error loading song")
self.module.update_all()
self.assertEquals(self.module.description(self.anyWidget), " - /")
def test_format(self):
self.popen.mock.communicate.return_value = (self.songTemplate.format(
artist="an artist", title="a title", duration="100", position="20",
album="an album", status="irrelevant"
), None)
self.module.update_all()
self.anyWidget.set("theme.width", 1000)
self.assertEquals(self.module.description(self.anyWidget),
"an artist - a title 00:20/01:40"
)
def test_scrollable_format(self):
self.popen.mock.communicate.return_value = (self.songTemplate.format(
artist="an artist", title="a title", duration="100", position="20",
album="an album", status="irrelevant"
), None)
self.module.update_all()
self.anyWidget.set("theme.width", 10)
self.assertEquals(self.module.description(self.anyWidget),
"an artist - a title 00:20/01:40"[:10]
)
def test_repeat(self):
self.popen.mock.communicate.return_value = ("set repeat false", None)
self.module.update_all()
self.assertTrue("repeat-off" in self.module.state(self.module.widget("cmus.repeat")))
self.popen.mock.communicate.return_value = ("set repeat true", None)
self.module.update_all()
self.assertTrue("repeat-on" in self.module.state(self.module.widget("cmus.repeat")))
def test_shuffle(self):
self.popen.mock.communicate.return_value = ("set shuffle false", None)
self.module.update_all()
self.assertTrue("shuffle-off" in self.module.state(self.module.widget("cmus.shuffle")))
self.popen.mock.communicate.return_value = ("set shuffle true", None)
self.module.update_all()
self.assertTrue("shuffle-on" in self.module.state(self.module.widget("cmus.shuffle")))
def test_prevnext(self):
self.assertTrue("prev" in self.module.state(self.module.widget("cmus.prev")))
self.assertTrue("next" in self.module.state(self.module.widget("cmus.next")))
def test_main(self):
self.popen.mock.communicate.return_value = ("status paused", None)
self.module.update_all()
self.assertTrue("paused" in self.module.state(self.module.widget("cmus.main")))
self.popen.mock.communicate.return_value = ("status playing", None)
self.module.update_all()
self.assertTrue("playing" in self.module.state(self.module.widget("cmus.main")))
self.popen.mock.communicate.return_value = ("status stopped", None)
self.module.update_all()
self.assertTrue("stopped" in self.module.state(self.module.widget("cmus.main")))
def test_widget(self):
self.assertEquals(len(self.module.widgets()), 5)
for idx, val in enumerate(["prev", "main", "next", "shuffle", "repeat"]):
self.assertEquals(self.module.widgets()[idx].name, "cmus.{}".format(val))
def test_interaction(self):
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"},
]
for event in events:
mocks.mouseEvent(stdin=self.stdin, inp=self.input, module=self.module, instance=self.module.widget(event["widget"]).id, button=LEFT_MOUSE)
self.popen.assert_call(event["action"])
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,45 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.cpu import Module
class TestCPUModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self._psutil = mock.patch("bumblebee.modules.cpu.psutil")
self.psutil = self._psutil.start()
def tearDown(self):
self._psutil.stop()
mocks.teardown_test(self)
def test_format(self):
self.psutil.cpu_percent.return_value = 21.0
self.module.update_all()
for widget in self.module.widgets():
self.assertEquals(len(widget.full_text()), len("99.0%"))
def test_leftclick(self):
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("gnome-system-monitor")
def test_warning(self):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "18")
self.psutil.cpu_percent.return_value = 19.0
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
def test_critical(self):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "19")
self.psutil.cpu_percent.return_value = 21.0
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.anyWidget))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,48 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.disk import Module
class MockVFS(object):
def __init__(self, perc):
self.f_blocks = 1024*1024
self.f_frsize = 1
self.f_bfree = self.f_blocks*(1.0 - perc/100.0)
class TestDiskModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self._os = mock.patch("bumblebee.modules.disk.os")
self.os = self._os.start()
self.config.set("disk.path", "somepath")
self.config.set("disk.open", "nautilus")
def tearDown(self):
self._os.stop()
mocks.teardown_test(self)
def test_leftclick(self):
module = Module(engine=self.engine, config={"config":self.config})
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=module)
self.popen.assert_call("nautilus {}".format(self.module.parameter("path")))
def test_warning(self):
self.config.set("disk.critical", "80")
self.config.set("disk.warning", "70")
self.os.statvfs.return_value = MockVFS(75.0)
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
def test_critical(self):
self.config.set("disk.critical", "80")
self.config.set("disk.warning", "70")
self.os.statvfs.return_value = MockVFS(85.0)
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.anyWidget))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
import mock
import unittest
from bumblebee.config import Config
import bumblebee.modules.hddtemp
class TestHddtempModule(unittest.TestCase):
def setUp(self):
config = Config()
self.module = bumblebee.modules.hddtemp.Module(
engine=mock.Mock(), config={"config": config})
self.data_line = "|/dev/sda|TOSHIBA DT01ACA100 <20>|35|C||/dev/sdb|TOSHIBA DT01ACA100 <20>|37|C|"
self.expected_parts = [
"/dev/sda",
"TOSHIBA DT01ACA100 <20>",
"35",
"C",
"",
"/dev/sdb",
"TOSHIBA DT01ACA100 <20>",
"37",
"C",
""]
self.expected_per_disk = [
["/dev/sda",
"TOSHIBA DT01ACA100 <20>",
"35",
"C",
""],
["/dev/sdb",
"TOSHIBA DT01ACA100 <20>",
"37",
"C",
""]]
self.device_record = self.expected_per_disk[0]
self.expected_name_and_temp = ("sda", "35")
self.expected_hddtemp = "sda+35°C"
def test_get_parts(self):
self.assertEqual(
self.expected_parts, self.module._get_parts(self.data_line))
def test_partition_parts(self):
self.assertEqual(
self.expected_per_disk,
self.module._partition_parts(self.expected_parts))
def test_get_name_and_temp(self):
self.assertEqual(
self.expected_name_and_temp,
self.module._get_name_and_temp(self.device_record))
def test_get_hddtemp(self):
self.assertEqual(
self.expected_hddtemp,
self.module._get_hddtemp(self.expected_name_and_temp))

View file

@ -1,49 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
from bumblebee.modules.http_status import Module
from bumblebee.config import Config
class TestHttpStatusModule(unittest.TestCase):
def test_status_success(self):
config = Config()
config.set("http_status.target", "http://example.org")
self.module = Module(engine=mock.Mock(), config={"config":config})
self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0]))
self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0]))
self.assertEqual(self.module.getStatus(), "200")
self.assertEqual(self.module.getOutput(), "200")
def test_status_error(self):
config = Config()
config.set("http_status.expect", "not a 200")
config.set("http_status.target", "http://example.org")
self.module = Module(engine=mock.Mock(), config={"config":config})
self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0]))
self.assertTrue("critical" in self.module.state(self.module.widgets()[0]))
self.assertEqual(self.module.getStatus(), "200")
self.assertEqual(self.module.getOutput(), "200 != not a 200")
def test_label(self):
config = Config()
config.set("http_status.label", "example")
config.set("http_status.target", "http://example.org")
self.module = Module(engine=mock.Mock(), config={"config":config})
self.assertEqual(self.module.getOutput(), "example: 200")
def test_unknow(self):
config = Config()
config.set("http_status.target", "invalid target")
self.module = Module(engine=mock.Mock(), config={"config":config})
self.assertTrue("warning" in self.module.state(self.module.widgets()[0]))
self.assertEqual(self.module.getStatus(), "UNK")
self.assertEqual(self.module.getOutput(), "UNK != 200")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,57 +0,0 @@
# pylint: disable=C0103,C0111
import json
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.load import Module
class TestLoadModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self._mp = mock.patch("bumblebee.modules.load.multiprocessing")
self._os = mock.patch("bumblebee.modules.load.os")
self.mp = self._mp.start()
self.os = self._os.start()
self.mp.cpu_count.return_value = 1
def tearDown(self):
self._mp.stop()
self._os.stop()
mocks.teardown_test(self)
def test_leftclick(self):
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("gnome-system-monitor")
def test_load_format(self):
self.os.getloadavg.return_value = [ 5.9, 1.2, 0.8 ]
self.module.update_all()
self.assertEquals(self.module.load(self.anyWidget), "5.90/1.20/0.80")
def test_warning(self):
self.config.set("load.critical", "1")
self.config.set("load.warning", "0.8")
self.os.getloadavg.return_value = [ 0.9, 0, 0 ]
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
def test_critical(self):
self.config.set("load.critical", "1")
self.config.set("load.warning", "0.8")
self.os.getloadavg.return_value = [ 1.1, 0, 0 ]
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.anyWidget))
def test_assume_single_core(self):
self.mp.cpu_count.side_effect = NotImplementedError
module = Module(engine=self.engine, config={"config": mock.Mock() })
self.assertEquals(1, module._cpus)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,34 +0,0 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE, RIGHT_MOUSE, WHEEL_UP, WHEEL_DOWN
from bumblebee.modules.pulseaudio import Module
class TestPulseAudioModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
def tearDown(self):
mocks.teardown_test(self)
def test_leftclick(self):
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("pactl set-source-mute @DEFAULT_SOURCE@ toggle")
def test_rightclick(self):
mocks.mouseEvent(stdin=self.stdin, button=RIGHT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("pavucontrol")
def test_wheelup(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_UP, inp=self.input, module=self.module)
self.popen.assert_call("pactl set-source-volume @DEFAULT_SOURCE@ +2%")
def test_wheeldown(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=self.module)
self.popen.assert_call("pactl set-source-volume @DEFAULT_SOURCE@ -2%")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,70 +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._stdout = mock.patch("bumblebee.config.sys.stdout", new_callable=StringIO)
self._stderr = mock.patch("bumblebee.config.sys.stderr", new_callable=StringIO)
self.stdout = self._stdout.start()
self.stderr = self._stderr.start()
self.defaultConfig = Config()
self.someSimpleModules = ["foo", "bar", "baz"]
self.someAliasModules = ["foo:a", "bar:b", "baz:c"]
self.someTheme = "some-theme"
def tearDown(self):
self._stdout.stop()
self._stderr.stop()
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])
def test_parameters(self):
cfg = Config(["-m", "module", "-p", "module.key=value"])
self.assertEquals(cfg.get("module.key"), "value")
def test_theme(self):
cfg = Config(["-t", self.someTheme])
self.assertEquals(cfg.theme(), self.someTheme)
def test_notheme(self):
self.assertEquals(self.defaultConfig.theme(), "default")
def test_list_themes(self):
with self.assertRaises(SystemExit):
cfg = Config(["-l", "themes"])
result = self.stdout.getvalue()
for theme in themes():
self.assertTrue(theme in result)
def test_invalid_list(self):
with self.assertRaises(SystemExit):
cfg = Config(["-l", "invalid"])
self.assertTrue("invalid choice" in "".join(self.stderr.getvalue()))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,90 +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.mocks import MockOutput, MockInput
class TestEngine(unittest.TestCase):
def setUp(self):
self.engine = Engine(config=Config(), output=MockOutput(), inp=MockInput())
self.testModule = "test"
self.testAlias = "test-alias"
self.singleWidgetModule = [{"module": self.testModule, "name": "a"}]
self.singleWidgetAlias = [{"module": self.testAlias, "name": "a" }]
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_aliases(self):
modules = self.engine.load_modules(self.singleWidgetAlias)
self.assertEquals(len(modules), 1)
self.assertEquals(modules[0].__module__, self.testModuleSpec)
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

View file

@ -1,110 +0,0 @@
# pylint: disable=C0103,C0111
import json
import mock
import unittest
import tests.mocks as mocks
from bumblebee.input import I3BarInput, LEFT_MOUSE, RIGHT_MOUSE
class TestI3BarInput(unittest.TestCase):
def setUp(self):
self.input = I3BarInput()
self.input.need_event = True
self._stdin = mock.patch("bumblebee.input.sys.stdin")
self.stdin = self._stdin.start()
self._select = mock.patch("bumblebee.input.select")
self.select = self._select.start()
self.popen = mocks.MockPopen()
self.stdin.fileno.return_value = 1
poll = mock.Mock()
self.select.poll.return_value = poll
poll.poll.return_value = [(self.stdin.fileno.return_value, 2)]
self.anyModule = mock.Mock()
self.anyModule.id = mocks.rand(10)
self.anotherModule = mock.Mock()
self.anotherModule.id = mocks.rand(10)
self.anyWidget = mocks.MockWidget("some-widget")
self.anotherWidget = mocks.MockWidget("another-widget")
self.anyData = self.invalidData = "any data"
self.invalidEvent = json.dumps({"name": None, "instance": None, "button": 1})
self.incompleteEvent = json.dumps({"button": 1})
self.anyCommand = "this is a command with arguments"
self._called = 0
def tearDown(self):
self._stdin.stop()
self._select.stop()
self.popen.cleanup()
def callback(self, event):
self._called += 1
def calls(self):
rv = self._called
self._called = 0
return rv
def test_read_event(self):
self.stdin.readline.return_value = self.anyData
self.input.start()
self.input.stop()
self.stdin.readline.assert_any_call()
def test_ignore_invalid_input(self):
for data in [ self.invalidData, self.incompleteEvent, self.invalidEvent ]:
self.stdin.readline.return_value = data
self.input.start()
self.assertEquals(self.input.alive(), True)
self.assertEquals(self.input.stop(), True)
self.stdin.readline.assert_any_call()
def test_global_callback(self):
self.input.register_callback(None, button=LEFT_MOUSE, cmd=self.callback)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin)
self.assertTrue(self.calls() > 0)
def test_remove_global_callback(self):
self.test_global_callback()
self.input.deregister_callbacks(None)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin)
self.assertTrue(self.calls() == 0)
def test_global_callback_wrong_button(self):
self.input.register_callback(None, button=LEFT_MOUSE, cmd=self.callback)
mocks.mouseEvent(button=RIGHT_MOUSE, inp=self.input, stdin=self.stdin)
self.assertTrue(self.calls() == 0)
def test_module_callback(self):
self.input.register_callback(self.anyModule, button=LEFT_MOUSE, cmd=self.callback)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyModule)
self.assertTrue(self.calls() > 0)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anotherModule)
self.assertTrue(self.calls() == 0)
def test_remove_module_callback(self):
self.test_module_callback()
self.input.deregister_callbacks(self.anyModule)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyModule)
self.assertTrue(self.calls() == 0)
def test_widget_callback(self):
self.input.register_callback(self.anyWidget, button=LEFT_MOUSE, cmd=self.callback)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyWidget)
self.assertTrue(self.calls() > 0)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anotherWidget)
self.assertTrue(self.calls() == 0)
def test_widget_cmd_callback(self):
self.input.register_callback(self.anyWidget, button=LEFT_MOUSE, cmd=self.anyCommand)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyWidget)
self.popen.assert_call(self.anyCommand)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,138 +0,0 @@
# pylint: disable=C0103,C0111
import json
import mock
import unittest
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import tests.mocks as mocks
from bumblebee.output import I3BarOutput
class TestI3BarOutput(unittest.TestCase):
def setUp(self):
self.theme = mock.Mock()
self.theme.separator_fg.return_value = "#123456"
self.theme.separator_bg.return_value = "#000000"
self.theme.separator.return_value = ""
self.theme.prefix.return_value = ""
self.theme.suffix.return_value = ""
self.theme.separator_block_width.return_value = 1
self.theme.fg.return_value = "#ababab"
self.theme.bg.return_value = "#ababab"
self.theme.align.return_value = None
self.theme.minwidth.return_value = ""
self.config = mock.Mock()
self.config.markup.return_value = ""
self.config.unused_keys.return_value = []
self.output = I3BarOutput(self.theme, self.config)
self._stdout = mock.patch("bumblebee.output.sys.stdout", new_callable=StringIO)
self.stdout = self._stdout.start()
self.anyWidget = mocks.MockWidget("some text")
self.anyModule = mock.Mock()
self.anyModule.id = mocks.rand(10)
self.anyModule.name = mocks.rand(10)
self.expectedStart = json.dumps({"version": 1, "click_events": True}) + "\n[\n"
self.expectedStop = "]\n"
self.anyColor = "#ffffff"
self.anotherColor = "#cdcdcd"
def tearDown(self):
self._stdout.stop()
def test_start(self):
self.output.start()
self.assertEquals(self.expectedStart, self.stdout.getvalue())
def test_stop(self):
self.output.stop()
self.assertEquals(self.expectedStop, self.stdout.getvalue())
def test_draw_single_widget(self):
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], self.anyWidget.full_text())
def test_draw_multiple_widgets(self):
for i in range(4):
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())
for res in result:
self.assertEquals(res["full_text"], self.anyWidget.full_text())
def test_begin(self):
self.output.begin()
self.assertEquals("", self.stdout.getvalue())
def test_end(self):
self.output.end()
self.assertEquals(",\n", self.stdout.getvalue())
def test_prefix(self):
self.theme.prefix.return_value = " - "
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], " - {}".format(self.anyWidget.full_text()))
def test_suffix(self):
self.theme.suffix.return_value = " - "
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], "{} - ".format(self.anyWidget.full_text()))
def test_bothfix(self):
self.theme.prefix.return_value = "*"
self.theme.suffix.return_value = " - "
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], "*{} - ".format(self.anyWidget.full_text()))
def test_colors(self):
self.theme.fg.return_value = self.anyColor
self.theme.bg.return_value = self.anotherColor
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["color"], self.anyColor)
self.assertEquals(result["background"], self.anotherColor)
def test_widget_link(self):
self.anyWidget.link_module(self.anyModule)
self.assertEquals(self.anyWidget._module, self.anyModule)
self.assertEquals(self.anyWidget.module, self.anyModule.name)
def test_unlinked_widget_state(self):
state = self.anyWidget.state()
self.assertTrue(type(state) == list)
def test_linked_widget_state(self):
self.anyWidget.link_module(self.anyModule)
for lst in [ "samplestate", ["a", "b", "c"], [] ]:
self.anyModule.state.return_value = lst
state = self.anyWidget.state()
self.assertEquals(type(state), list)
if type(lst) is not list: lst = [lst]
self.assertEquals(state, lst)
def test_widget_fulltext(self):
self.anyWidget.full_text("some text")
self.assertEquals(self.anyWidget.full_text(), "some text")
self.anyWidget.full_text(lambda x: "callable fulltext")
self.assertEquals(self.anyWidget.full_text(), "callable fulltext")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,89 +0,0 @@
# pylint: disable=C0103,C0111,W0703
import unittest
from bumblebee.engine import Module
from bumblebee.config import Config
from tests.mocks import MockWidget
class TestModule(unittest.TestCase):
def setUp(self):
self.widgetName = "foo"
self.widget = MockWidget(self.widgetName)
self.config = Config()
self.anyWidgetName = "random-widget-name"
self.noSuchModule = "this-module-does-not-exist"
self.moduleWithoutWidgets = Module(engine=None, widgets=None)
self.moduleWithOneWidget = Module(engine=None, widgets=self.widget, config={"config": self.config})
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_retrieve_widget_by_name(self):
widget = MockWidget(self.anyWidgetName)
widget.name = self.anyWidgetName
module = Module(engine=None, widgets=[self.widget, widget, self.widget])
retrievedWidget = module.widget(self.anyWidgetName)
self.assertEquals(retrievedWidget, widget)
def test_retrieve_widget_by_id(self):
widget = MockWidget(self.anyWidgetName)
widget.id = self.anyWidgetName
module = Module(engine=None, widgets=[self.widget, widget, self.widget])
retrievedWidget = module.widget_by_id(self.anyWidgetName)
self.assertEquals(retrievedWidget, widget)
def test_retrieve_missing_widget(self):
module = self.moduleWithMultipleWidgets
widget = module.widget(self.noSuchModule)
self.assertEquals(widget, None)
widget = module.widget_by_id(self.noSuchModule)
self.assertEquals(widget, None)
def test_threshold(self):
module = self.moduleWithOneWidget
module.name = self.widgetName
self.config.set("{}.critical".format(self.widgetName), 10.0)
self.config.set("{}.warning".format(self.widgetName), 8.0)
self.assertEquals("critical", module.threshold_state(10.1, 0, 0))
self.assertEquals("warning", module.threshold_state(10.0, 0, 0))
self.assertEquals(None, module.threshold_state(8.0, 0, 0))
self.assertEquals(None, module.threshold_state(7.9, 0, 0))
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)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,62 +1,27 @@
import unittest
import json
import bumblebee.output
import core.output
class TestHBar(unittest.TestCase):
"""tests for bumblebee.output.HBar"""
class i3(unittest.TestCase):
def setUp(self):
self.value = 1
self.values = [10, 20, 30, 40, 55, 65, 80, 90]
self.hbar = bumblebee.output.HBar(self.value)
self.i3 = core.output.i3()
def test___init__(self):
"""bumblebee.output.HBar.__init__()"""
self.assertEqual(
self.hbar.step, bumblebee.output.MAX_PERCENTS / bumblebee.output.CHARS)
def tearDown(self):
pass
def test_get_char(self):
"""bumblebee.output.HBar.get_char()"""
for i in range(bumblebee.output.CHARS):
hbar = bumblebee.output.HBar(self.values[i])
self.assertEqual(hbar.get_char(), bumblebee.output.HBARS[i])
# edge case for 100%
hbar = bumblebee.output.HBar(100)
self.assertEqual(hbar.get_char(), bumblebee.output.HBARS[-1])
def test_start(self):
data = json.loads(self.i3.start())
self.assertEquals(1, data['version'], 'i3bar protocol version 1 expected')
self.assertTrue(data['click_events'], 'click events should be enabled')
def test_begin_status_line(self):
self.assertEquals('[', self.i3.begin_status_line(), 'each line must be a JSON array')
class TestVBar(unittest.TestCase):
"""tests for bumblebee.output.VBar"""
def setUp(self):
self.value = 1
self.values = [10, 20, 30, 40, 55, 65, 80, 90]
self.vbar = bumblebee.output.VBar(self.value)
def test_end_status_line(self):
self.assertEquals('],\n', self.i3.end_status_line(), 'each line must terminate properly')
def test___init__(self):
"""bumblebee.output.VBar.__init__()"""
self.assertEqual(
self.vbar.step, bumblebee.output.MAX_PERCENTS / bumblebee.output.CHARS)
def test_stop(self):
self.assertEquals(']\n', self.i3.stop())
def test_get_chars(self):
"""bumblebee.output.VBar.get_char()"""
for i in range(bumblebee.output.CHARS):
vbar = bumblebee.output.VBar(self.values[i])
self.assertEqual(vbar.get_chars(), bumblebee.output.VBARS[i])
# edge case for 100%
vbar = bumblebee.output.VBar(100)
self.assertEqual(vbar.get_chars(), bumblebee.output.VBARS[-1])
# 0.x chars filled
value = 0.1
vbar = bumblebee.output.VBar(value, 3)
expected_chars = vbar.bars[0] + " "
self.assertEqual(vbar.get_chars(), expected_chars)
# 1.x chars filled
value = 35
vbar = bumblebee.output.VBar(value, 3)
expected_chars = vbar.bars[-1] + vbar.bars[0] + " "
self.assertEqual(vbar.get_chars(), expected_chars)
# 2.x chars filled
value = 67
vbar = bumblebee.output.VBar(value, 3)
expected_chars = vbar.bars[-1] * 2 + vbar.bars[0]
self.assertEqual(vbar.get_chars(), expected_chars)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,26 +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)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,142 +0,0 @@
# pylint: disable=C0103,C0111,W0703
import mock
import unittest
from bumblebee.theme import Theme
from bumblebee.error import ThemeLoadError
from tests.mocks import MockWidget
class TestTheme(unittest.TestCase):
def setUp(self):
self.nonexistentThemeName = "no-such-theme"
self.invalidThemeName = "test_invalid"
self.validThemeName = "test"
self.validThemeSeparator = " * "
self.themedWidget = MockWidget("bla")
self.theme = Theme(self.validThemeName)
self.cycleTheme = Theme("test_cycle")
self.anyModule = mock.Mock()
self.anyWidget = MockWidget("bla")
self.anotherWidget = MockWidget("blub")
self.anyModule.state.return_value = "state-default"
self.anyWidget.link_module(self.anyModule)
self.themedWidget.link_module(self.anyModule)
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.anyModule.state.return_value = "critical"
self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["critical"]["fg"])
self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["critical"]["bg"])
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"])
def test_empty_state(self):
theme = self.theme
data = theme.data()
self.anyModule.state.return_value = ""
self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["fg"])
self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["bg"])
def test_separator(self):
self.assertEquals(self.validThemeSeparator, self.theme.separator(self.anyWidget))
def test_list(self):
theme = self.theme
data = theme.data()[self.widgetTheme]["cycle-test"]["fg"]
self.anyModule.state.return_value = "cycle-test"
self.assertTrue(len(data) > 1)
for idx in range(0, len(data)):
self.assertEquals(theme.fg(self.themedWidget), data[idx])
self.assertEquals(theme.fg(self.themedWidget), data[0])
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,90 +0,0 @@
# pylint: disable=C0103,C0111
import unittest
import re
import tests.mocks as mocks
import bumblebee.util as bu
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):
self.assertEquals(bu.bytefmt(10), "10.00B")
self.assertEquals(bu.bytefmt(15 * 1024), "15.00KiB")
self.assertEquals(bu.bytefmt(20 * 1024 * 1024), "20.00MiB")
self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024), "22.00GiB")
self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024), "35840.00GiB")
fmt = "{:.0f}"
self.assertEquals(bu.bytefmt(10, fmt), "10B")
self.assertEquals(bu.bytefmt(15 * 1024, fmt), "15KiB")
self.assertEquals(bu.bytefmt(20 * 1024 * 1024, fmt), "20MiB")
self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024, fmt), "22GiB")
self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024, fmt), "35840GiB")
def test_durationfmt(self):
self.assertEquals(bu.durationfmt(00), "00:00")
self.assertEquals(bu.durationfmt(25), "00:25")
self.assertEquals(bu.durationfmt(60), "01:00")
self.assertEquals(bu.durationfmt(119), "01:59")
self.assertEquals(bu.durationfmt(3600), "01:00:00")
self.assertEquals(bu.durationfmt(7265), "02:01:05")
def test_execute(self):
bu.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_nowait(self):
bu.execute(self.some_command_with_args, False)
self.assertTrue(self.popen.mock.popen.called)
self.popen.mock.popen.assert_call(self.some_command_with_args)
self.assertFalse(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):
bu.execute(self.some_command_with_args)
def test_which(self):
# test for a binary that has to be somewhere
print(bu.which("ls"))
self.assertTrue(re.search('/(ls)$', bu.which("ls")))
# test for a binary that is not necessarily there
program = "iwgetid"
self.assertTrue(
bu.which(program) is None or
re.search('/(' + program + ')$', bu.which(program))
)
# test if which also works with garbage input
self.assertTrue(bu.which("qwertygarbage") is None)
def test_asbool(self):
for val in ("t", "true", "y", "yes", "on", "1", 1, True):
self.assertTrue(bu.asbool(val))
if isinstance(val, str):
self.assertTrue(bu.asbool(val.upper()))
for val in ("f", "false", "n", "no", "off", "0", 0, False):
self.assertFalse(bu.asbool(val))
if isinstance(val, str):
self.assertFalse(bu.asbool(val.upper()))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4