← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~raoul-snyman/openlp/stricter-slot-signatures-2.4 into lp:openlp/2.4

 

Raoul Snyman has proposed merging lp:~raoul-snyman/openlp/stricter-slot-signatures-2.4 into lp:openlp/2.4.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~raoul-snyman/openlp/stricter-slot-signatures-2.4/+merge/302525

Update slot signatures to comply with PyQt5.6's stricter checks.

Add this to your merge proposal:
--------------------------------
lp:~raoul-snyman/openlp/stricter-slot-signatures-2.4 (revision 2648)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1711/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1622/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1560/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1322/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/912/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/980/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/848/

-- 
Your team OpenLP Core is requested to review the proposed merge of lp:~raoul-snyman/openlp/stricter-slot-signatures-2.4 into lp:openlp/2.4.
=== modified file 'openlp/core/lib/projector/pjlink1.py'
--- openlp/core/lib/projector/pjlink1.py	2016-06-25 17:32:32 +0000
+++ openlp/core/lib/projector/pjlink1.py	2016-08-10 10:01:02 +0000
@@ -312,10 +312,10 @@
             read = self.readLine(self.maxSize)
             dontcare = self.readLine(self.maxSize)  # Clean out the trailing \r\n
             if read is None:
-                log.warn('({ip}) read is None - socket error?'.format(ip=self.ip))
+                log.warning('({ip}) read is None - socket error?'.format(ip=self.ip))
                 return
             elif len(read) < 8:
-                log.warn('({ip}) Not enough data read)'.format(ip=self.ip))
+                log.warning('({ip}) Not enough data read)'.format(ip=self.ip))
                 return
             data = decode(read, 'ascii')
             # Possibility of extraneous data on input when reading.
@@ -413,7 +413,7 @@
             self.projectorReceivedData.emit()
             return
         elif '=' not in data:
-            log.warn('({ip}) get_data(): Invalid packet received'.format(ip=self.ip))
+            log.warning('({ip}) get_data(): Invalid packet received'.format(ip=self.ip))
             self.send_busy = False
             self.projectorReceivedData.emit()
             return
@@ -421,21 +421,21 @@
         try:
             (prefix, class_, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1])
         except ValueError as e:
-            log.warn('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip))
-            log.warn('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip()))
+            log.warning('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip))
+            log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip()))
             self.change_status(E_INVALID_DATA)
             self.send_busy = False
             self.projectorReceivedData.emit()
             return
 
         if not (self.pjlink_class in PJLINK_VALID_CMD and cmd in PJLINK_VALID_CMD[self.pjlink_class]):
-            log.warn('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
+            log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
             self.send_busy = False
             self.projectorReceivedData.emit()
             return
         return self.process_command(cmd, data)
 
-    @pyqtSlot(int)
+    @pyqtSlot(QAbstractSocket.SocketError)
     def get_error(self, err):
         """
         Process error from SocketError signal.
@@ -472,7 +472,7 @@
         :param queue: Option to force add to queue rather than sending directly
         """
         if self.state() != self.ConnectedState:
-            log.warn('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
+            log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
             self.send_queue = []
             return
         self.projectorNetwork.emit(self.ip, S_NETWORK_SENDING)
@@ -592,7 +592,7 @@
         if cmd in self.PJLINK1_FUNC:
             self.PJLINK1_FUNC[cmd](data)
         else:
-            log.warn('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd))
+            log.warning('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd))
         self.send_busy = False
         self.projectorReceivedData.emit()
 
@@ -611,7 +611,7 @@
                 fill = {'Hours': int(data_dict[0]), 'On': False if data_dict[1] == '0' else True}
             except ValueError:
                 # In case of invalid entry
-                log.warn('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data))
+                log.warning('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data))
                 return
             lamps.append(fill)
             data_dict.pop(0)  # Remove lamp hours
@@ -638,7 +638,7 @@
                     self.send_command('INST')
         else:
             # Log unknown status response
-            log.warn('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data))
+            log.warning('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data))
         return
 
     def process_avmt(self, data):
@@ -663,7 +663,7 @@
             shutter = True
             mute = True
         else:
-            log.warn('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data))
+            log.warning('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data))
         update_icons = shutter != self.shutter
         update_icons = update_icons or mute != self.mute
         self.shutter = shutter
@@ -812,7 +812,7 @@
         Initiate connection to projector.
         """
         if self.state() == self.ConnectedState:
-            log.warn('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
+            log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
             return
         self.change_status(S_CONNECTING)
         self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port))
@@ -824,9 +824,9 @@
         """
         if abort or self.state() != self.ConnectedState:
             if abort:
-                log.warn('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
+                log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
             else:
-                log.warn('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip))
+                log.warning('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip))
             self.reset_information()
         self.disconnectFromHost()
         try:

=== modified file 'openlp/core/ui/projector/sourceselectform.py'
--- openlp/core/ui/projector/sourceselectform.py	2016-01-09 16:26:14 +0000
+++ openlp/core/ui/projector/sourceselectform.py	2016-08-10 10:01:02 +0000
@@ -20,24 +20,22 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 """
-    :mod: `openlp.core.ui.projector.sourceselectform` module
+:mod: `openlp.core.ui.projector.sourceselectform` module
 
-    Provides the dialog window for selecting video source for projector.
+Provides the dialog window for selecting video source for projector.
 """
 import logging
-log = logging.getLogger(__name__)
-log.debug('editform loaded')
 
 from PyQt5 import QtCore, QtWidgets
-from PyQt5.QtCore import pyqtSlot, QSize
-from PyQt5.QtWidgets import QDialog, QButtonGroup, QDialogButtonBox, QFormLayout, QLineEdit, QRadioButton, \
-    QStyle, QStylePainter, QStyleOptionTab, QTabBar, QTabWidget, QVBoxLayout, QWidget
 
 from openlp.core.common import translate, is_macosx
 from openlp.core.lib import build_icon
 from openlp.core.lib.projector.db import ProjectorSource
 from openlp.core.lib.projector.constants import PJLINK_DEFAULT_SOURCES, PJLINK_DEFAULT_CODES
 
+log = logging.getLogger(__name__)
+log.debug('editform loaded')
+
 
 def source_group(inputs, source_text):
     """
@@ -104,8 +102,8 @@
     :param edit: If we're editing the source text
     """
     buttonchecked = False
-    widget = QWidget()
-    layout = QFormLayout() if edit else QVBoxLayout()
+    widget = QtWidgets.QWidget()
+    layout = QtWidgets.QFormLayout() if edit else QtWidgets.QVBoxLayout()
     layout.setSpacing(10)
     widget.setLayout(layout)
     tempkey = list(source_key.keys())[0]  # Should only be 1 key
@@ -114,7 +112,7 @@
     button_count = len(sourcelist)
     if edit:
         for key in sourcelist:
-            item = QLineEdit()
+            item = QtWidgets.QLineEdit()
             item.setObjectName('source_key_%s' % key)
             source_item = projectordb.get_source_by_code(code=key, projector_id=projector.db_item.id)
             if source_item is None:
@@ -130,7 +128,7 @@
                 text = source_key[tempkey][key]
             else:
                 text = source_item.text
-            itemwidget = QRadioButton(text)
+            itemwidget = QtWidgets.QRadioButton(text)
             itemwidget.setAutoExclusive(True)
             if default == key:
                 itemwidget.setChecked(True)
@@ -141,30 +139,30 @@
     return widget, button_count, buttonchecked
 
 
-def set_button_tooltip(bar):
+def set_button_tooltip(button_bar):
     """
     Set the toolip for the standard buttons used
 
     :param bar: QDialogButtonBar instance to update
     """
-    for button in bar.buttons():
-        if bar.standardButton(button) == QDialogButtonBox.Cancel:
+    for button in button_bar.buttons():
+        if button_bar.standardButton(button) == QtWidgets.QDialogButtonBox.Cancel:
             button.setToolTip(translate('OpenLP.SourceSelectForm',
                                         'Ignoring current changes and return to OpenLP'))
-        elif bar.standardButton(button) == QDialogButtonBox.Reset:
+        elif button_bar.standardButton(button) == QtWidgets.QDialogButtonBox.Reset:
             button.setToolTip(translate('OpenLP.SourceSelectForm',
                                         'Delete all user-defined text and revert to PJLink default text'))
-        elif bar.standardButton(button) == QDialogButtonBox.Discard:
+        elif button_bar.standardButton(button) == QtWidgets.QDialogButtonBox.Discard:
             button.setToolTip(translate('OpenLP.SourceSelectForm',
                                         'Discard changes and reset to previous user-defined text'))
-        elif bar.standardButton(button) == QDialogButtonBox.Ok:
+        elif button_bar.standardButton(button) == QtWidgets.QDialogButtonBox.Ok:
             button.setToolTip(translate('OpenLP.SourceSelectForm',
                                         'Save changes and return to OpenLP'))
         else:
-            log.debug('No tooltip for button {}'.format(button.text()))
-
-
-class FingerTabBarWidget(QTabBar):
+            log.debug('No tooltip for button %s', button.text())
+
+
+class FingerTabBarWidget(QtWidgets.QTabBar):
     """
     Realign west -orientation tabs to left-right text rather than south-north text
     Borrowed from
@@ -177,8 +175,8 @@
         :param width: Remove default width parameter in kwargs
         :param height: Remove default height parameter in kwargs
         """
-        self.tabSize = QSize(kwargs.pop('width', 100), kwargs.pop('height', 25))
-        QTabBar.__init__(self, parent, *args, **kwargs)
+        self.tabSize = QtWidgets.QSize(kwargs.pop('width', 100), kwargs.pop('height', 25))
+        QtWidgets.QTabBar.__init__(self, parent, *args, **kwargs)
 
     def paintEvent(self, event):
         """
@@ -186,14 +184,14 @@
 
         :param event: Repaint event signal
         """
-        painter = QStylePainter(self)
-        option = QStyleOptionTab()
+        painter = QtWidgets.QStylePainter(self)
+        option = QtWidgets.QStyleOptionTab()
 
         for index in range(self.count()):
             self.initStyleOption(option, index)
             tabRect = self.tabRect(index)
             tabRect.moveLeft(10)
-            painter.drawControl(QStyle.CE_TabBarTabShape, option)
+            painter.drawControl(QtWidgets.QStyle.CE_TabBarTabShape, option)
             painter.drawText(tabRect, QtCore.Qt.AlignVCenter |
                              QtCore.Qt.TextDontClip,
                              self.tabText(index))
@@ -209,7 +207,7 @@
         return self.tabSize
 
 
-class FingerTabWidget(QTabWidget):
+class FingerTabWidget(QtWidgets.QTabWidget):
     """
     A QTabWidget equivalent which uses our FingerTabBarWidget
 
@@ -220,11 +218,11 @@
         """
         Initialize FingerTabWidget instance
         """
-        QTabWidget.__init__(self, parent, *args)
+        QtWidgets.QTabWidget.__init__(self, parent, *args)
         self.setTabBar(FingerTabBarWidget(self))
 
 
-class SourceSelectTabs(QDialog):
+class SourceSelectTabs(QtWidgets.QDialog):
     """
     Class for handling selecting the source for the projector to use.
     Uses tabbed interface.
@@ -248,18 +246,18 @@
         self.setObjectName('source_select_tabs')
         self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
         self.setModal(True)
-        self.layout = QVBoxLayout()
+        self.layout = QtWidgets.QVBoxLayout()
         self.layout.setObjectName('source_select_tabs_layout')
         if is_macosx():
-            self.tabwidget = QTabWidget(self)
+            self.tabwidget = QtWidgets.QTabWidget(self)
         else:
             self.tabwidget = FingerTabWidget(self)
         self.tabwidget.setObjectName('source_select_tabs_tabwidget')
         self.tabwidget.setUsesScrollButtons(False)
         if is_macosx():
-            self.tabwidget.setTabPosition(QTabWidget.North)
+            self.tabwidget.setTabPosition(QtWidgets.QTabWidget.North)
         else:
-            self.tabwidget.setTabPosition(QTabWidget.West)
+            self.tabwidget.setTabPosition(QtWidgets.QTabWidget.West)
         self.layout.addWidget(self.tabwidget)
         self.setLayout(self.layout)
 
@@ -273,7 +271,7 @@
         self.source_text = self.projectordb.get_source_list(projector=projector)
         self.source_group = source_group(projector.source_available, self.source_text)
         # self.source_group = {'4': {'41': 'Storage 1'}, '5': {"51": 'Network 1'}}
-        self.button_group = [] if self.edit else QButtonGroup()
+        self.button_group = [] if self.edit else QtWidgets.QButtonGroup()
         keys = list(self.source_group.keys())
         keys.sort()
         if self.edit:
@@ -287,10 +285,10 @@
                 thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
                 if buttonchecked:
                     self.tabwidget.setCurrentIndex(thistab)
-            self.button_box = QDialogButtonBox(QtWidgets.QDialogButtonBox.Reset |
-                                               QtWidgets.QDialogButtonBox.Discard |
-                                               QtWidgets.QDialogButtonBox.Ok |
-                                               QtWidgets.QDialogButtonBox.Cancel)
+            self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Reset |
+                                                         QtWidgets.QDialogButtonBox.Discard |
+                                                         QtWidgets.QDialogButtonBox.Ok |
+                                                         QtWidgets.QDialogButtonBox.Cancel)
         else:
             for key in keys:
                 (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group,
@@ -302,15 +300,15 @@
                 thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
                 if buttonchecked:
                     self.tabwidget.setCurrentIndex(thistab)
-            self.button_box = QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
-                                               QtWidgets.QDialogButtonBox.Cancel)
+            self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
+                                                         QtWidgets.QDialogButtonBox.Cancel)
         self.button_box.clicked.connect(self.button_clicked)
         self.layout.addWidget(self.button_box)
         set_button_tooltip(self.button_box)
         selected = super(SourceSelectTabs, self).exec()
         return selected
 
-    @pyqtSlot(object)
+    @QtCore.pyqtSlot(QtWidgets.QAbstractButton)
     def button_clicked(self, button):
         """
         Checks which button was clicked
@@ -333,6 +331,9 @@
             return 100
 
     def delete_sources(self):
+        """
+        Delete the source
+        """
         msg = QtWidgets.QMessageBox()
         msg.setText(translate('OpenLP.SourceSelectForm', 'Delete entries for this projector'))
         msg.setInformativeText(translate('OpenLP.SourceSelectForm',
@@ -359,20 +360,20 @@
                     continue
                 item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id)
                 if item is None:
-                    log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text))
+                    log.debug("(%s) Adding new source text %s: %s", projector.ip, code, text)
                     item = ProjectorSource(projector_id=projector.id, code=code, text=text)
                 else:
                     item.text = text
-                    log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text))
+                    log.debug('(%s) Updating source code %s with text="%s"', projector.ip, item.code, item.text)
                 self.projectordb.add_source(item)
             selected = 0
         else:
             selected = self.button_group.checkedId()
-            log.debug('SourceSelectTabs().accepted() Setting source to %s' % selected)
+            log.debug('SourceSelectTabs().accepted() Setting source to %s', selected)
         self.done(selected)
 
 
-class SourceSelectSingle(QDialog):
+class SourceSelectSingle(QtWidgets.QDialog):
     """
     Class for handling selecting the source for the projector to use.
     Uses single dialog interface.
@@ -393,6 +394,7 @@
             title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
         self.setObjectName('source_select_single')
         self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
+        self.setWindowTitle(title)
         self.setModal(True)
         self.edit = edit
 
@@ -403,12 +405,12 @@
         :param projector: Projector instance to build source list from
         """
         self.projector = projector
-        self.layout = QFormLayout() if self.edit else QVBoxLayout()
+        self.layout = QtWidgets.QFormLayout() if self.edit else QtWidgets.QVBoxLayout()
         self.layout.setObjectName('source_select_tabs_layout')
         self.layout.setSpacing(10)
         self.setLayout(self.layout)
         self.setMinimumWidth(350)
-        self.button_group = [] if self.edit else QButtonGroup()
+        self.button_group = [] if self.edit else QtWidgets.QButtonGroup()
         self.source_text = self.projectordb.get_source_list(projector=projector)
         keys = list(self.source_text.keys())
         keys.sort()
@@ -416,7 +418,7 @@
         button_list = []
         if self.edit:
             for key in keys:
-                item = QLineEdit()
+                item = QtWidgets.QLineEdit()
                 item.setObjectName('source_key_%s' % key)
                 source_item = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id)
                 if source_item is None:
@@ -426,10 +428,10 @@
                     item.setText(source_item.text)
                 self.layout.addRow(PJLINK_DEFAULT_CODES[key], item)
                 self.button_group.append(item)
-            self.button_box = QDialogButtonBox(QtWidgets.QDialogButtonBox.Reset |
-                                               QtWidgets.QDialogButtonBox.Discard |
-                                               QtWidgets.QDialogButtonBox.Ok |
-                                               QtWidgets.QDialogButtonBox.Cancel)
+            self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Reset |
+                                                         QtWidgets.QDialogButtonBox.Discard |
+                                                         QtWidgets.QDialogButtonBox.Ok |
+                                                         QtWidgets.QDialogButtonBox.Cancel)
         else:
             for key in keys:
                 source_text = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id)
@@ -439,8 +441,8 @@
                 self.layout.addWidget(button)
                 self.button_group.addButton(button, int(key))
                 button_list.append(key)
-            self.button_box = QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
-                                               QtWidgets.QDialogButtonBox.Cancel)
+            self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
+                                                         QtWidgets.QDialogButtonBox.Cancel)
         self.button_box.clicked.connect(self.button_clicked)
         self.layout.addWidget(self.button_box)
         self.setMinimumHeight(key_count * 25)
@@ -448,7 +450,7 @@
         selected = super(SourceSelectSingle, self).exec()
         return selected
 
-    @pyqtSlot(object)
+    @QtCore.pyqtSlot(QtWidgets.QAbstractButton)
     def button_clicked(self, button):
         """
         Checks which button was clicked
@@ -471,6 +473,9 @@
             return 100
 
     def delete_sources(self):
+        """
+        Delete all the entries for this projector
+        """
         msg = QtWidgets.QMessageBox()
         msg.setText(translate('OpenLP.SourceSelectForm', 'Delete entries for this projector'))
         msg.setInformativeText(translate('OpenLP.SourceSelectForm',
@@ -484,7 +489,7 @@
         self.projectordb.delete_all_objects(ProjectorSource, ProjectorSource.projector_id == self.projector.db_item.id)
         self.done(100)
 
-    @pyqtSlot()
+    @QtCore.pyqtSlot()
     def accept_me(self):
         """
         Slot to accept 'OK' button
@@ -498,14 +503,14 @@
                     continue
                 item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id)
                 if item is None:
-                    log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text))
+                    log.debug('(%s) Adding new source text %s: %s', projector.ip, code, text)
                     item = ProjectorSource(projector_id=projector.id, code=code, text=text)
                 else:
                     item.text = text
-                    log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text))
+                    log.debug('(%s) Updating source code %s with text="%s"', projector.ip, item.code, item.text)
                 self.projectordb.add_source(item)
             selected = 0
         else:
             selected = self.button_group.checkedId()
-            log.debug('SourceSelectDialog().accepted() Setting source to %s' % selected)
+            log.debug('SourceSelectDialog().accepted() Setting source to %s', selected)
         self.done(selected)

=== modified file 'tests/functional/openlp_core_common/test_registryproperties.py'
--- tests/functional/openlp_core_common/test_registryproperties.py	2015-12-31 22:46:06 +0000
+++ tests/functional/openlp_core_common/test_registryproperties.py	2016-08-10 10:01:02 +0000
@@ -25,7 +25,8 @@
 from unittest import TestCase
 
 from openlp.core.common import Registry, RegistryProperties
-from tests.functional import MagicMock
+
+from tests.functional import MagicMock, patch
 
 
 class TestRegistryProperties(TestCase, RegistryProperties):
@@ -36,7 +37,7 @@
         """
         Create the Register
         """
-        Registry.create()
+        self.registry = Registry.create()
 
     def no_application_test(self):
         """
@@ -53,7 +54,29 @@
         """
         # GIVEN an Empty Registry
         application = MagicMock()
+
         # WHEN the application is registered
         Registry().register('application', application)
+
         # THEN the application should be none
         self.assertEqual(self.application, application, 'The application value should match')
+
+    @patch('openlp.core.common.registryproperties.is_win')
+    def test_get_application_on_windows(self, mocked_is_win):
+        """
+        Set that getting the application object on Windows happens dynamically
+        """
+        # GIVEN an Empty Registry and we're on Windows
+        mocked_is_win.return_value = True
+        mock_application = MagicMock()
+        reg_props = RegistryProperties()
+
+        # WHEN the application is accessed
+        with patch.object(self.registry, 'get') as mocked_get:
+            mocked_get.return_value = mock_application
+            actual_application = reg_props.application
+
+        # THEN the application should be the mock object, and the correct function should have been called
+        self.assertEqual(mock_application, actual_application, 'The application value should match')
+        mocked_is_win.assert_called_with()
+        mocked_get.assert_called_with('application')


Follow ups