Merge branch 'unit-test-refactoring'

This commit is contained in:
Tobi-wan Kenobi 2017-03-05 14:20:39 +01:00
commit ca9712770a
30 changed files with 888 additions and 681 deletions

View file

@ -1,3 +1,10 @@
[run]
omit =
tests/*
*mock*
*funcsigs*
*pbr*
*six*
/usr/lib*
[report]

View file

@ -25,8 +25,6 @@ class print_usage(argparse.Action):
self.print_modules()
elif value == "themes":
self.print_themes()
else:
parser.print_help()
sys.exit(0)
def print_themes(self):

View file

@ -52,6 +52,9 @@ class Module(object):
"""By default, update() is a NOP"""
pass
def update_all(self):
self.update(self._widgets)
def parameter(self, name, default=None):
"""Return the config parameter 'name' for this module"""
name = "{}.{}".format(self.name, name)

View file

@ -53,9 +53,7 @@ class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
widget = bumblebee.output.Widget(full_text=self.updates)
super(Module, self).__init__(engine, config, widget)
self._next_check = 0
widget
def updates(self, widget):
result = []

View file

@ -22,7 +22,7 @@ class Module(bumblebee.engine.Module):
self._load = [0, 0, 0]
try:
self._cpus = multiprocessing.cpu_count()
except multiprocessing.NotImplementedError as e:
except NotImplementedError as e:
self._cpus = 1
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE,
cmd="gnome-system-monitor")

View file

@ -5,6 +5,8 @@
import bumblebee.engine
ALIASES = [ "test-alias" ]
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
super(Module, self).__init__(engine, config,

View file

@ -90,11 +90,6 @@ class Theme(object):
"""Return the SBW"""
return self._get(widget, "separator-block-width", None)
def loads(self, data):
"""Initialize the theme from a JSON string"""
theme = json.loads(data)
self._init(theme)
def _load_icons(self, name):
"""Load icons for a theme"""
path = "{}/icons/".format(theme_path())

View file

@ -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

View file

@ -1,11 +1,11 @@
#!/bin/sh
echo "testing with $(python2 -V 2>&1)"
python2 $(which nosetests) --rednose -v tests/
python2 $(which nosetests) --rednose -v --with-coverage --cover-erase tests/
if [ $? == 0 ]; then
echo
echo "testing with $(python3 -V 2>&1)"
python3 $(which nosetests-3) --rednose -v tests/
python3 $(which nosetests-3) --rednose -v --with-coverage --cover-erase tests/
fi

141
tests/mocks.py Normal file
View file

@ -0,0 +1,141 @@
# 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 = epoll_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 epoll_mock(module=""):
if len(module) > 0: module = "{}.".format(module)
stdin = mock.patch("{}sys.stdin".format(module))
select = mock.patch("{}select".format(module))
epoll = mock.Mock()
stdin_mock = stdin.start()
select_mock = select.start()
stdin_mock.fileno.return_value = 1
select_mock.epoll.return_value = epoll
epoll.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,68 +1,108 @@
# pylint: disable=C0103,C0111
import sys
import json
import unittest
import mock
import unittest
from contextlib import contextmanager
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import tests.mocks as mocks
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
from bumblebee.config import Config
class TestBatteryModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
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.open.return_value = self.file
self.exists.return_value = True
self.engine = mock.Mock()
self.config = Config()
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"
for widget in self.module.widgets():
widget.link_module(self.module)
self.anyWidget = widget
@mock.patch("sys.stdout")
def test_format(self, mock_output):
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%"))
@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())
def test_critical(self):
self.file.read.return_value = self.criticalValue
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.anyWidget))
@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())
def test_warning(self):
self.file.read.return_value = self.warningValue
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
def test_normal(self):
self.file.read.return_value = self.normalValue
self.module.update_all()
self.assertTrue(not "warning" in self.module.state(self.anyWidget))
self.assertTrue(not "critical" in self.module.state(self.anyWidget))
def test_overload(self):
self.file.read.return_value = "120"
self.module.update_all()
self.assertTrue(not "warning" in self.module.state(self.anyWidget))
self.assertTrue(not "critical" in self.module.state(self.anyWidget))
self.assertEquals(self.module.capacity(self.anyWidget), "100%")
def test_ac(self):
self.exists.return_value = False
self.module.update_all()
self.assertEquals(self.module.capacity(self.anyWidget), "ac")
self.assertTrue("AC" in self.module.state(self.anyWidget))
def test_error(self):
self.file.read.side_effect = IOError("failed to read")
self.module.update_all()
self.assertEquals(self.module.capacity(self.anyWidget), "n/a")
self.assertTrue("critical" in self.module.state(self.anyWidget))
self.assertTrue("unknown" in self.module.state(self.anyWidget))
def test_charging(self):
self.file.read.return_value = self.chargedValue
self.module.update_all()
self.assertTrue("charged" in self.module.state(self.anyWidget))
self.file.read.return_value = self.normalValue
self.module.update_all()
self.assertTrue("charging" in self.module.state(self.anyWidget))
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.anyWidget))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,56 +1,47 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import tests.mocks as mocks
from bumblebee.input import WHEEL_UP, WHEEL_DOWN
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)
mocks.setup_test(self, Module)
@mock.patch("sys.stdout")
def test_format(self, mock_output):
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%"))
@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%"
)
def test_wheel_up(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_UP, inp=self.input, module=self.module)
self.popen.assert_call("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%"
)
def test_wheel_down(self):
mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=self.module)
self.popen.assert_call("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):
def test_custom_step(self):
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%"
)
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("xbacklight -10%")
def test_update(self):
self.popen.mock.communicate.return_value = ("20.0", None)
self.module.update_all()
self.assertEquals(self.module.brightness(self.anyWidget), "020%")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -4,18 +4,50 @@ import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import tests.mocks as mocks
from bumblebee.config import Config
from bumblebee.input import LEFT_MOUSE
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)
mocks.setup_test(self, Module)
self.xset_active = " timeout: 0 cycle: 123"
self.xset_inactive = " timeout: 600 cycle: 123"
def tearDown(self):
mocks.teardown_test(self)
def test_text(self):
self.assertEquals(self.module.caffeine(self.anyWidget), "")
def test_active(self):
self.popen.mock.communicate.return_value = (self.xset_active, None)
self.assertTrue(not "deactivated" in self.module.state(self.anyWidget))
self.assertTrue("activated" in self.module.state(self.anyWidget))
def test_inactive(self):
self.popen.mock.communicate.return_value = (self.xset_inactive, None)
self.assertTrue("deactivated" in self.module.state(self.anyWidget))
self.popen.mock.communicate.return_value = ("no text", None)
self.assertTrue("deactivated" in self.module.state(self.anyWidget))
def test_toggle(self):
self.popen.mock.communicate.return_value = (self.xset_active, None)
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("xset s default")
self.popen.assert_call("notify-send \"Out of coffee\"")
self.popen.mock.communicate.return_value = (self.xset_inactive, None)
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("xset s off")
self.popen.assert_call("notify-send \"Consuming caffeine\"")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,38 +1,93 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
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()})
mocks.setup_test(self, Module)
@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")
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 test_widgets(self):
self.assertTrue(len(self.module.widgets()), 5)
def tearDown(self):
mocks.teardown_test(self)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_interaction(self, mock_input, mock_output, mock_select):
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.assertEquals(self.module.description(self.anyWidget),
"an artist - a title 00:20/01:40"
)
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"},
@ -40,19 +95,8 @@ class TestCmusModule(unittest.TestCase):
{"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"])
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,48 +1,45 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
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 })
mocks.setup_test(self, Module)
self._psutil = mock.patch("bumblebee.modules.cpu.psutil")
self.psutil = self._psutil.start()
@mock.patch("sys.stdout")
def test_format(self, mock_output):
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("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"
)
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")
@mock.patch("psutil.cpu_percent")
def test_warning(self, mock_psutil):
def test_warning(self):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "18")
mock_psutil.return_value = 19.0
assertStateContains(self, self.module, "warning")
self.psutil.cpu_percent.return_value = 19.0
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
@mock.patch("psutil.cpu_percent")
def test_critical(self, mock_psutil):
def test_critical(self):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "19")
mock_psutil.return_value = 21.0
assertStateContains(self, self.module, "critical")
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,13 +1,12 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.disk import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertStateContains, MockEpoll
class MockVFS(object):
def __init__(self, perc):
@ -17,40 +16,32 @@ class MockVFS(object):
class TestDiskModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
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.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")))
def tearDown(self):
self._os.stop()
mocks.teardown_test(self)
@mock.patch("os.statvfs")
def test_warning(self, mock_stat):
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")
mock_stat.return_value = MockVFS(75.0)
assertStateContains(self, self.module, "warning")
self.os.statvfs.return_value = MockVFS(75.0)
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
@mock.patch("os.statvfs")
def test_critical(self, mock_stat):
def test_critical(self):
self.config.set("disk.critical", "80")
self.config.set("disk.warning", "70")
mock_stat.return_value = MockVFS(85.0)
assertStateContains(self, self.module, "critical")
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,47 +1,57 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
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 })
mocks.setup_test(self, Module)
@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"
)
self._mp = mock.patch("bumblebee.modules.load.multiprocessing")
self._os = mock.patch("bumblebee.modules.load.os")
@mock.patch("multiprocessing.cpu_count")
@mock.patch("os.getloadavg")
def test_warning(self, mock_loadavg, mock_cpucount):
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")
mock_cpucount.return_value = 1
mock_loadavg.return_value = [ 0.9, 0, 0 ]
assertStateContains(self, self.module, "warning")
self.os.getloadavg.return_value = [ 0.9, 0, 0 ]
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
@mock.patch("multiprocessing.cpu_count")
@mock.patch("os.getloadavg")
def test_critical(self, mock_loadavg, mock_cpucount):
def test_critical(self):
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")
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,13 +1,12 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.memory import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains
class VirtualMemory(object):
def __init__(self, percent):
@ -15,33 +14,39 @@ class VirtualMemory(object):
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 })
mocks.setup_test(self, Module)
self._psutil = mock.patch("bumblebee.modules.memory.psutil")
self.psutil = self._psutil.start()
@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"
)
def tearDown(self):
self._psutil.stop()
mocks.teardown_test(self)
@mock.patch("psutil.virtual_memory")
def test_warning(self, mock_vmem):
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("memory.critical", "80")
self.config.set("memory.warning", "70")
mock_vmem.return_value = VirtualMemory(75)
assertStateContains(self, self.module, "warning")
self.psutil.virtual_memory.return_value = VirtualMemory(75)
self.module.update_all()
self.assertTrue("warning" in self.module.state(self.anyWidget))
@mock.patch("psutil.virtual_memory")
def test_critical(self, mock_vmem):
def test_critical(self):
self.config.set("memory.critical", "80")
self.config.set("memory.warning", "70")
mock_vmem.return_value = VirtualMemory(85)
assertStateContains(self, self.module, "critical")
self.psutil.virtual_memory.return_value = VirtualMemory(81)
self.module.update_all()
self.assertTrue("critical" in self.module.state(self.anyWidget))
def test_usage(self):
rv = VirtualMemory(50)
rv.total = 1000
rv.available = 500
self.psutil.virtual_memory.return_value = rv
self.module.update_all()
self.assertEquals("500.00B/1000.00B (50.00%)", self.module.memory_usage(self.anyWidget))
self.assertEquals(None, self.module.state(self.anyWidget))
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,56 +1,34 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
import tests.mocks as mocks
from bumblebee.input import LEFT_MOUSE, RIGHT_MOUSE, WHEEL_UP, WHEEL_DOWN
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 })
mocks.setup_test(self, Module)
@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"
)
def tearDown(self):
mocks.teardown_test(self)
@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"
)
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")
@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%"
)
def test_rightclick(self):
mocks.mouseEvent(stdin=self.stdin, button=RIGHT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("pavucontrol")
@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%"
)
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

@ -13,9 +13,20 @@ 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(), [])
@ -33,20 +44,34 @@ class TestConfig(unittest.TestCase):
"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):
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 = stdout.getvalue()
result = self.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):
def test_list_modules(self):
with self.assertRaises(SystemExit):
cfg = Config(["-l", "modules"])
result = stdout.getvalue()
result = self.stdout.getvalue()
for module in all_modules():
self.assertTrue(module["name"] 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

@ -8,13 +8,15 @@ from bumblebee.engine import Engine
from bumblebee.config import Config
import bumblebee.input
from tests.util import MockOutput, MockInput
from tests.mocks 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.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 = [
@ -54,6 +56,11 @@ class TestEngine(unittest.TestCase):
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" },

View file

@ -1,129 +1,110 @@
# pylint: disable=C0103,C0111
import unittest
import json
import subprocess
import mock
import unittest
import bumblebee.input
from bumblebee.input import I3BarInput
from tests.util import MockWidget, MockModule, assertPopen, assertMouseEvent, MockEpoll
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.anyModule = MockModule()
self.anyWidget = MockWidget("test")
self.anyModule.id = "test-module"
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
epoll = mock.Mock()
self.select.epoll.return_value = epoll
epoll.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
@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()
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()
mock_input.readline.assert_any_call()
self.stdin.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"
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)
mock_input.readline.assert_any_call()
self.stdin.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()
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)
@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)
def test_remove_global_callback(self):
self.test_global_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)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin)
self.assertTrue(self.calls() == 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)
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)
@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)
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)
@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)
def test_remove_module_callback(self):
self.test_module_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)
mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyModule)
self.assertTrue(self.calls() == 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)
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)
@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

View file

@ -1,104 +1,131 @@
# pylint: disable=C0103,C0111
import json
import unittest
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
from tests.util import MockWidget, MockTheme, MockModule
class TestI3BarOutput(unittest.TestCase):
def setUp(self):
self.theme = MockTheme()
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.output = I3BarOutput(self.theme)
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"
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.anyColor = "#ffffff"
self.anotherColor = "#cdcdcd"
def tearDown(self):
self._stdout.stop()
def test_start(self):
self.output.start()
self.assertEquals(self.expectedStart, stdout.getvalue())
self.assertEquals(self.expectedStart, self.stdout.getvalue())
@mock.patch("sys.stdout", new_callable=StringIO)
def test_stop(self, stdout):
def test_stop(self):
self.output.stop()
self.assertEquals(self.expectedStop, stdout.getvalue())
self.assertEquals(self.expectedStop, self.stdout.getvalue())
@mock.patch("sys.stdout", new_callable=StringIO)
def test_draw_single_widget(self, stdout):
self.output.draw(self.someWidget, self.anyModule)
def test_draw_single_widget(self):
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(stdout.getvalue())[0]
self.assertEquals(result["full_text"], self.someWidget.full_text())
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], self.anyWidget.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)
def test_draw_multiple_widgets(self):
for i in range(4):
self.output.draw(self.anyWidget, self.anyModule)
self.output.flush()
result = json.loads(stdout.getvalue())
result = json.loads(self.stdout.getvalue())
for res in result:
self.assertEquals(res["full_text"], self.someWidget.full_text())
self.assertEquals(res["full_text"], self.anyWidget.full_text())
@mock.patch("sys.stdout", new_callable=StringIO)
def test_begin(self, stdout):
def test_begin(self):
self.output.begin()
self.assertEquals("", stdout.getvalue())
self.assertEquals("", self.stdout.getvalue())
@mock.patch("sys.stdout", new_callable=StringIO)
def test_end(self, stdout):
def test_end(self):
self.output.end()
self.assertEquals(",\n", stdout.getvalue())
self.assertEquals(",\n", self.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)
def test_prefix(self):
self.theme.prefix.return_value = " - "
self.output.draw(self.anyWidget, 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())
)
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], " - {}".format(self.anyWidget.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)
def test_suffix(self):
self.theme.suffix.return_value = " - "
self.output.draw(self.anyWidget, 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))
)
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], "{} - ".format(self.anyWidget.full_text()))
@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)
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(stdout.getvalue())[0]
self.assertEquals(result["full_text"], "{}{}{}".format(
self.theme.prefix(self.someWidget),
self.someWidget.full_text(),
self.theme.suffix(self.someWidget)
))
result = json.loads(self.stdout.getvalue())[0]
self.assertEquals(result["full_text"], "*{} - ".format(self.anyWidget.full_text()))
@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)
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(stdout.getvalue())[0]
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

@ -4,14 +4,17 @@ import unittest
from bumblebee.engine import Module
from bumblebee.config import Config
from tests.util import MockWidget
from tests.mocks import MockWidget
class TestModule(unittest.TestCase):
def setUp(self):
self.widget = MockWidget("foo")
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)
self.moduleWithOneWidget = Module(engine=None, widgets=self.widget, config={"config": self.config})
self.moduleWithMultipleWidgets = Module(engine=None,
widgets=[self.widget, self.widget, self.widget]
)
@ -41,6 +44,40 @@ class TestModule(unittest.TestCase):
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)
@ -48,3 +85,5 @@ class TestModule(unittest.TestCase):
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,53 +1,54 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import importlib
import mock
import tests.mocks as mocks
from bumblebee.engine import all_modules
from bumblebee.output import Widget
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()
def setUp(self):
engine = mock.Mock()
engine.input = mock.Mock()
config = Config()
self.objects = {}
self.popen = mocks.MockPopen()
self.popen.mock.communicate.return_value = (str.encode("1"), "error")
self.popen.mock.returncode = 0
self._platform = mock.patch("bumblebee.modules.kernel.platform")
self.platform = self._platform.start()
self.platform.release.return_value = "unknown linux v1"
for mod in all_modules():
cls = importlib.import_module("bumblebee.modules.{}".format(mod["name"]))
name = "bumblebee.modules.{}".format(mod["name"])
cls = importlib.import_module(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()
def tearDown(self):
self._platform.stop()
self.popen.cleanup()
def test_widgets(self):
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)
self.assertTrue(isinstance(widget, Widget))
self.assertTrue(hasattr(widget, "full_text"))
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)
})
def test_update(self):
for mod in self.objects:
widgets = self.objects[mod].widgets()
self.objects[mod].update(widgets)

View file

@ -22,3 +22,5 @@ class TestStore(unittest.TestCase):
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,21 +1,29 @@
# pylint: disable=C0103,C0111,W0703
import mock
import unittest
from bumblebee.theme import Theme
from bumblebee.error import ThemeLoadError
from tests.util import MockWidget
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
@ -102,14 +110,25 @@ class TestTheme(unittest.TestCase):
self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["fg"])
self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["bg"])
self.anyWidget.attr_state = ["critical"]
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.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"])
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,18 +1,27 @@
# pylint: disable=C0103,C0111
import mock
import unittest
import tests.mocks as 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,26 @@ 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_nowait(self):
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):
execute(self.some_command_with_args)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -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

View file

@ -17,6 +17,9 @@
"bg": "#222222",
"critical": {
"fg": "#bababa"
},
"cycle-test": {
"fg": [ "#000000", "#111111" ]
}
}
}