diff --git a/src/bitmessageqt/tests/__init__.py b/src/bitmessageqt/tests/__init__.py index a81ddb047..f8a578a0f 100644 --- a/src/bitmessageqt/tests/__init__.py +++ b/src/bitmessageqt/tests/__init__.py @@ -4,8 +4,9 @@ from .main import TestMain, TestUISignaler from .settings import TestSettings from .support import TestSupport +from .test_import import TestImports __all__ = [ - "TestAddressbook", "TestMain", "TestSettings", "TestSupport", - "TestUISignaler" + "TestAddressbook", "TestImports", "TestMain", "TestSettings", + "TestSupport", "TestUISignaler" ] diff --git a/src/bitmessageqt/tests/test_import.py b/src/bitmessageqt/tests/test_import.py new file mode 100644 index 000000000..2e2bdb0da --- /dev/null +++ b/src/bitmessageqt/tests/test_import.py @@ -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 diff --git a/src/bitmessageqt/tests/test_startup.py b/src/bitmessageqt/tests/test_startup.py new file mode 100644 index 000000000..232702014 --- /dev/null +++ b/src/bitmessageqt/tests/test_startup.py @@ -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_() diff --git a/src/bitmessageqt/tests/test_widgets.py b/src/bitmessageqt/tests/test_widgets.py new file mode 100644 index 000000000..35a193a73 --- /dev/null +++ b/src/bitmessageqt/tests/test_widgets.py @@ -0,0 +1,87 @@ +""" +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_unescape(self): + """Undo urlencoding""" + from bitmessageqt.safehtmlparser import SafeHTMLParser + parser = SafeHTMLParser() + parser.reset() + parser.reset_safe() + parser.feed("hello & world") + self.assertIn("hello", parser.sanitised) + self.assertNotIn("test message.") + + +@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""" + from bitmessageqt.addressvalidator import AddressValidator + line_edit = QtGui.QLineEdit() + validator = AddressValidator(line_edit) + self.assertIsNotNone(validator) + + +@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)