Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/bitmessageqt/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
from .main import TestMain, TestUISignaler
from .settings import TestSettings
from .support import TestSupport
from .test_import import TestImports
from .test_startup import TestStartup
from .test_widgets import (
TestAddressValidator, TestLanguageBox, TestMessageView,
TestSafeHTMLParser
)

__all__ = [
"TestAddressbook", "TestMain", "TestSettings", "TestSupport",
"TestUISignaler"
"TestAddressbook", "TestAddressValidator", "TestLanguageBox",
"TestImports", "TestMain", "TestMessageView", "TestSafeHTMLParser",
"TestSettings", "TestStartup", "TestSupport", "TestUISignaler"
]
35 changes: 32 additions & 3 deletions src/bitmessageqt/tests/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,47 @@
from bitmessageqt import _translate, config, queues


# pylint: disable=too-few-public-methods
class TestApp(QtGui.QApplication):
"""Lightweight QApplication subclass for tests, without the heavy
BitmessageQtApplication init (QLocalSocket singleton check,
organisation metadata, etc.)."""

@staticmethod
def get_windowstyle():
"""Get window style set in config or default"""
return config.safeGet(
'bitmessagesettings', 'windowstyle',
'Windows' if sys.platform.startswith('win') else 'GTK+'
)


def get_test_app():
"""Return the existing QApplication or create a TestApp.

If the running app is a plain QApplication (missing get_windowstyle),
patch in the required methods from TestApp."""
app = QtGui.QApplication.instance()
if app is None:
return TestApp(sys.argv)
if not hasattr(app, 'get_windowstyle'):
# Bolt on the methods the tests expect; this happens when
# another test already created a bare QApplication.
app.get_windowstyle = TestApp.get_windowstyle
return app


class TestBase(unittest.TestCase):
"""Base class for bitmessageqt test case"""

@classmethod
def setUpClass(cls):
"""Provide the UI test cases with common settings"""
cls.config = config
cls.app = get_test_app()

def setUp(self):
self.app = (
QtGui.QApplication.instance()
or bitmessageqt.BitmessageQtApplication(sys.argv))
self.app = self.__class__.app
self.window = self.app.activeWindow()
if not self.window:
self.window = bitmessageqt.MyForm()
Expand Down
67 changes: 67 additions & 0 deletions src/bitmessageqt/tests/test_import.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Smoke tests: verify that bitmessageqt modules can be imported.

These tests require PyQt4 to be installed but do NOT need a running
X server, database, or any bitmessage backend threads.
"""
import unittest


# pylint: disable=import-error,unused-variable
class TestImports(unittest.TestCase):
"""Verify that key bitmessageqt modules are importable"""

@staticmethod
def test_import_bitmessageqt():
"""The main bitmessageqt package should be importable"""
import bitmessageqt

@staticmethod
def test_import_bitmessageui():
"""The generated UI module should be importable"""
from bitmessageqt import bitmessageui

@staticmethod
def test_import_settings():
"""The settings dialog module should be importable"""
from bitmessageqt import settings

@staticmethod
def test_import_address_dialogs():
"""The address dialogs module should be importable"""
from bitmessageqt import address_dialogs

@staticmethod
def test_import_networkstatus():
"""The network status module should be importable"""
from bitmessageqt import networkstatus

@staticmethod
def test_import_safehtmlparser():
"""safehtmlparser should be importable"""
from bitmessageqt import safehtmlparser

@staticmethod
def test_import_support():
"""The support module should be importable"""
from bitmessageqt import support

@staticmethod
def test_import_foldertree():
"""The foldertree module should be importable"""
from bitmessageqt import foldertree

@staticmethod
def test_import_messageview():
"""The messageview module should be importable"""
from bitmessageqt import messageview

@staticmethod
def test_import_utils():
"""The utils module should be importable"""
from bitmessageqt import utils

@staticmethod
def test_import_account():
"""The account module should be importable"""
from bitmessageqt import account
54 changes: 54 additions & 0 deletions src/bitmessageqt/tests/test_startup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Smoke test: verify the main window can be created and shut down.

This test requires the full bitmessage backend to be running
(it is designed to run via ``bitmessagemain.py -t`` or from
``src/tests/core.py``). It also needs a display (Xvfb is fine).
"""
import sys
import unittest

try:
from PyQt4 import QtCore, QtGui
has_qt = True
except ImportError:
has_qt = False


@unittest.skipUnless(has_qt, "requires PyQt4")
class TestStartup(unittest.TestCase):
"""Verify the main window starts and has expected structure"""

def setUp(self):
import bitmessageqt
self.app = (
QtGui.QApplication.instance()
or bitmessageqt.BitmessageQtApplication(sys.argv))
self.window = self.app.activeWindow()
if not self.window:
self.window = bitmessageqt.MyForm()
self.window.appIndicatorInit(self.app)

def test_window_exists(self):
"""The main window should be created successfully"""
self.assertIsNotNone(self.window)
self.assertIsNotNone(self.window.ui)

def test_window_has_tabs(self):
"""The main window should have the expected tab widget"""
tabs = self.window.ui.tabWidget
self.assertIsNotNone(tabs)
self.assertGreater(tabs.count(), 0)

def test_window_title(self):
"""The main window should have a non-empty title"""
self.assertTrue(len(self.window.windowTitle()) > 0)

def test_status_bar(self):
"""The main window should have a status bar"""
self.assertIsNotNone(self.window.statusBar())

def test_quit_cycle(self):
"""The event loop should start and stop without crashing"""
QtCore.QTimer.singleShot(50, self.app.quit)
self.app.exec_()
92 changes: 92 additions & 0 deletions src/bitmessageqt/tests/test_widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Unit tests for individual bitmessageqt widgets.

These tests need a display (real or virtual via Xvfb/xvfb-run) and PyQt4,
but do NOT require the full bitmessage backend, database, or network.
Each test creates only the minimal widget under test.
"""
import sys
import unittest

try:
from PyQt4 import QtCore, QtGui, QtTest
has_qt = True
except ImportError:
has_qt = False


def get_app():
"""Return existing QApplication or create a new one"""
return QtGui.QApplication.instance() or QtGui.QApplication(sys.argv)


@unittest.skipUnless(has_qt, "requires PyQt4")
class TestSafeHTMLParser(unittest.TestCase):
"""Test the SafeHTMLParser used for message rendering"""

def test_sanitise(self):
"""Check that dangerous HTML is stripped"""
from bitmessageqt.safehtmlparser import SafeHTMLParser
parser = SafeHTMLParser()
parser.reset()
parser.reset_safe()
parser.feed("<b>hello</b> <script/>alert('x')</script> &amp; world")
self.assertIn("hello", parser.sanitised)
self.assertNotIn("<script", parser.sanitised)


@unittest.skipUnless(has_qt, "requires PyQt4")
class TestMessageView(unittest.TestCase):
"""Test the MessageView widget in isolation"""

def setUp(self):
self.app = get_app()

def test_create_messageview(self):
"""MessageView widget can be instantiated"""
from bitmessageqt.messageview import MessageView
widget = MessageView(None)
self.assertIsNotNone(widget)

def test_messageview_set_content(self):
"""MessageView.setContent renders the given text"""
from bitmessageqt.messageview import MessageView
widget = MessageView(None)
widget.setContent("Hello, this is a <b>test</b> message.")
self.assertIn("test", widget.toPlainText())


@unittest.skipUnless(has_qt, "requires PyQt4")
class TestAddressValidator(unittest.TestCase):
"""Test the AddressValidator"""

def setUp(self):
self.app = get_app()

def test_create_validator(self):
"""AddressValidator can be instantiated with a buttonBox"""
from bitmessageqt.addressvalidator import AddressValidator
line_edit = QtGui.QLineEdit()
# AddressValidator.setParams() reads the Ok button label on init,
# so a real QDialogButtonBox is the simplest way to satisfy that.
button_box = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok)
validator = AddressValidator(
line_edit, buttonBox=button_box)
self.assertIsNotNone(validator)
self.assertFalse(validator.isValid)


@unittest.skipUnless(has_qt, "requires PyQt4")
class TestLanguageBox(unittest.TestCase):
"""Test the language selection combobox"""

def setUp(self):
self.app = get_app()

def test_create_languagebox(self):
"""LanguageBox can be instantiated"""
from bitmessageqt.languagebox import LanguageBox
parent = QtGui.QWidget()
combo = LanguageBox(parent)
self.assertIsNotNone(combo)
self.assertGreater(combo.count(), 0)
Loading