diff --git a/openlp/core/projectors/__init__.py b/openlp/core/projectors/__init__.py index 396422902..66cfd6080 100644 --- a/openlp/core/projectors/__init__.py +++ b/openlp/core/projectors/__init__.py @@ -25,8 +25,6 @@ Initialization for the openlp.core.projectors modules. """ -from openlp.core.projectors.constants import PJLINK_PORT, ERROR_MSG, ERROR_STRING - class DialogSourceStyle(object): """ diff --git a/openlp/core/projectors/constants.py b/openlp/core/projectors/constants.py index 715896133..a9410d109 100644 --- a/openlp/core/projectors/constants.py +++ b/openlp/core/projectors/constants.py @@ -144,6 +144,24 @@ PJLINK_VALID_CMD = { } } +# QAbstractSocketState enums converted to string +S_QSOCKET_STATE = { + 0: 'QSocketState - UnconnectedState', + 1: 'QSocketState - HostLookupState', + 2: 'QSocketState - ConnectingState', + 3: 'QSocketState - ConnectedState', + 4: 'QSocketState - BoundState', + 5: 'QSocketState - ListeningState (internal use only)', + 6: 'QSocketState - ClosingState', + 'UnconnectedState': 0, + 'HostLookupState': 1, + 'ConnectingState': 2, + 'ConnectedState': 3, + 'BoundState': 4, + 'ListeningState': 5, + 'ClosingState': 6 +} + # Error and status codes S_OK = E_OK = 0 # E_OK included since I sometimes forget # Error codes. Start at 200 so we don't duplicate system error codes. diff --git a/openlp/core/projectors/db.py b/openlp/core/projectors/db.py index 99fe9515b..fe8785861 100644 --- a/openlp/core/projectors/db.py +++ b/openlp/core/projectors/db.py @@ -415,7 +415,7 @@ class ProjectorDB(Manager): for key in projector.source_available: item = self.get_object_filtered(ProjectorSource, and_(ProjectorSource.code == key, - ProjectorSource.projector_id == projector.dbid)) + ProjectorSource.projector_id == projector.id)) if item is None: source_dict[key] = PJLINK_DEFAULT_CODES[key] else: diff --git a/openlp/core/projectors/pjlink.py b/openlp/core/projectors/pjlink.py index 16a65bd11..12ae7e1d0 100644 --- a/openlp/core/projectors/pjlink.py +++ b/openlp/core/projectors/pjlink.py @@ -58,8 +58,7 @@ from openlp.core.projectors.constants import CONNECTION_ERRORS, CR, ERROR_MSG, E E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \ E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \ PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \ - STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \ - S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS + STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_QSOCKET_STATE, S_STATUS log = logging.getLogger(__name__) log.debug('pjlink loaded') @@ -111,7 +110,7 @@ class PJLinkCommands(object): """ log.debug('PJlinkCommands(args={args} kwargs={kwargs})'.format(args=args, kwargs=kwargs)) super().__init__() - # Map command to function + # Map PJLink command to method self.pjlink_functions = { 'AVMT': self.process_avmt, 'CLSS': self.process_clss, @@ -123,7 +122,9 @@ class PJLinkCommands(object): 'INST': self.process_inst, 'LAMP': self.process_lamp, 'NAME': self.process_name, - 'PJLINK': self.check_login, + 'PJLINK': self.process_pjlink, + # TODO: Part of check_login refactor - remove when done + # 'PJLINK': self.check_login, 'POWR': self.process_powr, 'SNUM': self.process_snum, 'SVER': self.process_sver, @@ -135,7 +136,8 @@ class PJLinkCommands(object): """ Initialize instance variables. Also used to reset projector-specific information to default. """ - log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip, state=self.state())) + log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip, + state=S_QSOCKET_STATE[self.state()])) self.fan = None # ERST self.filter_time = None # FILT self.lamp = None # LAMP @@ -165,6 +167,7 @@ class PJLinkCommands(object): self.socket_timer.stop() self.send_busy = False self.send_queue = [] + self.priority_queue = [] def process_command(self, cmd, data): """ @@ -176,18 +179,19 @@ class PJLinkCommands(object): log.debug('({ip}) Processing command "{cmd}" with data "{data}"'.format(ip=self.ip, cmd=cmd, data=data)) - # Check if we have a future command not available yet - _cmd = cmd.upper() + # cmd should already be in uppercase, but data may be in mixed-case. + # Due to some replies should stay as mixed-case, validate using separate uppercase check _data = data.upper() - if _cmd not in PJLINK_VALID_CMD: - log.error("({ip}) Ignoring command='{cmd}' (Invalid/Unknown)".format(ip=self.ip, cmd=cmd)) + # Check if we have a future command not available yet + if cmd not in PJLINK_VALID_CMD: + log.error('({ip}) Ignoring command="{cmd}" (Invalid/Unknown)'.format(ip=self.ip, cmd=cmd)) return elif _data == 'OK': log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd)) - # A command returned successfully, no further processing needed - return - elif _cmd not in self.pjlink_functions: - log.warning("({ip}) Unable to process command='{cmd}' (Future option)".format(ip=self.ip, cmd=cmd)) + # A command returned successfully, so do a query on command to verify status + return self.send_command(cmd=cmd) + elif cmd not in self.pjlink_functions: + log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd)) return elif _data in PJLINK_ERRORS: # Oops - projector error @@ -211,12 +215,10 @@ class PJLinkCommands(object): elif _data == PJLINK_ERRORS[E_PROJECTOR]: # Projector/display error self.change_status(E_PROJECTOR) - self.receive_data_signal() return # Command checks already passed log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd)) - self.receive_data_signal() - self.pjlink_functions[_cmd](data) + self.pjlink_functions[cmd](data) def process_avmt(self, data): """ @@ -259,19 +261,19 @@ class PJLinkCommands(object): # : Received: '%1CLSS=Class 1' (Optoma) # : Received: '%1CLSS=Version1' (BenQ) if len(data) > 1: - log.warning("({ip}) Non-standard CLSS reply: '{data}'".format(ip=self.ip, data=data)) + log.warning('({ip}) Non-standard CLSS reply: "{data}"'.format(ip=self.ip, data=data)) # Due to stupid projectors not following standards (Optoma, BenQ comes to mind), # AND the different responses that can be received, the semi-permanent way to # fix the class reply is to just remove all non-digit characters. try: clss = re.findall('\d', data)[0] # Should only be the first match except IndexError: - log.error("({ip}) No numbers found in class version reply '{data}' - " - "defaulting to class '1'".format(ip=self.ip, data=data)) + log.error('({ip}) No numbers found in class version reply "{data}" - ' + 'defaulting to class "1"'.format(ip=self.ip, data=data)) clss = '1' elif not data.isdigit(): - log.error("({ip}) NAN clss version reply '{data}' - " - "defaulting to class '1'".format(ip=self.ip, data=data)) + log.error('({ip}) NAN CLSS version reply "{data}" - ' + 'defaulting to class "1"'.format(ip=self.ip, data=data)) clss = '1' else: clss = data @@ -289,7 +291,7 @@ class PJLinkCommands(object): """ if len(data) != PJLINK_ERST_DATA['DATA_LENGTH']: count = PJLINK_ERST_DATA['DATA_LENGTH'] - log.warning("{ip}) Invalid error status response '{data}': length != {count}".format(ip=self.ip, + log.warning('{ip}) Invalid error status response "{data}": length != {count}'.format(ip=self.ip, data=data, count=count)) return @@ -297,7 +299,7 @@ class PJLinkCommands(object): datacheck = int(data) except ValueError: # Bad data - ignore - log.warning("({ip}) Invalid error status response '{data}'".format(ip=self.ip, data=data)) + log.warning('({ip}) Invalid error status response "{data}"'.format(ip=self.ip, data=data)) return if datacheck == 0: self.projector_errors = None @@ -430,6 +432,51 @@ class PJLinkCommands(object): log.debug('({ip}) Setting projector PJLink name to "{data}"'.format(ip=self.ip, data=self.pjlink_name)) return + def process_pjlink(self, data): + """ + Process initial socket connection to terminal. + + :param data: Initial packet with authentication scheme + """ + log.debug('({ip}) Processing PJLINK command'.format(ip=self.ip)) + chk = data.split(' ') + if len(chk[0]) != 1: + # Invalid - after splitting, first field should be 1 character, either '0' or '1' only + log.error('({ip}) Invalid initial authentication scheme - aborting'.format(ip=self.ip)) + return self.disconnect_from_host() + elif chk[0] == '0': + # Normal connection no authentication + if len(chk) > 1: + # Invalid data - there should be nothing after a normal authentication scheme + log.error('({ip}) Normal connection with extra information - aborting'.format(ip=self.ip)) + return self.disconnect_from_host() + elif self.pin: + log.error('({ip}) Normal connection but PIN set - aborting'.format(ip=self.ip)) + return self.disconnect_from_host() + else: + data_hash = None + elif chk[0] == '1': + if len(chk) < 2: + # Not enough information for authenticated connection + log.error('({ip}) Authenticated connection but not enough info - aborting'.format(ip=self.ip)) + return self.disconnect_from_host() + elif not self.pin: + log.error('({ip}) Authenticate connection but no PIN - aborting'.format(ip=self.ip)) + return self.disconnect_from_host() + else: + data_hash = str(qmd5_hash(salt=chk[1].encode('utf-8'), data=self.pin.encode('utf-8')), + encoding='ascii') + # Passed basic checks, so start connection + self.readyRead.connect(self.get_socket) + if not self.no_poll: + log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=self.ip)) + self.timer.setInterval(2000) # Set 2 seconds for initial information + self.timer.start() + self.change_status(S_CONNECTED) + log.debug('({ip}) process_pjlink(): Sending "CLSS" initial command'.format(ip=self.ip)) + # Since this is an initial connection, make it a priority just in case + return self.send_command(cmd="CLSS", salt=data_hash, priority=True) + def process_powr(self, data): """ Power status. See PJLink specification for format. @@ -450,7 +497,7 @@ class PJLinkCommands(object): self.send_command('INST') else: # Log unknown status response - log.warning('({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_rfil(self, data): @@ -460,9 +507,9 @@ class PJLinkCommands(object): if self.model_filter is None: self.model_filter = data else: - log.warning("({ip}) Filter model already set".format(ip=self.ip)) - log.warning("({ip}) Saved model: '{old}'".format(ip=self.ip, old=self.model_filter)) - log.warning("({ip}) New model: '{new}'".format(ip=self.ip, new=data)) + log.warning('({ip}) Filter model already set'.format(ip=self.ip)) + log.warning('({ip}) Saved model: "{old}"'.format(ip=self.ip, old=self.model_filter)) + log.warning('({ip}) New model: "{new}"'.format(ip=self.ip, new=data)) def process_rlmp(self, data): """ @@ -471,9 +518,9 @@ class PJLinkCommands(object): if self.model_lamp is None: self.model_lamp = data else: - log.warning("({ip}) Lamp model already set".format(ip=self.ip)) - log.warning("({ip}) Saved lamp: '{old}'".format(ip=self.ip, old=self.model_lamp)) - log.warning("({ip}) New lamp: '{new}'".format(ip=self.ip, new=data)) + log.warning('({ip}) Lamp model already set'.format(ip=self.ip)) + log.warning('({ip}) Saved lamp: "{old}"'.format(ip=self.ip, old=self.model_lamp)) + log.warning('({ip}) New lamp: "{new}"'.format(ip=self.ip, new=data)) def process_snum(self, data): """ @@ -482,16 +529,16 @@ class PJLinkCommands(object): :param data: Serial number from projector. """ if self.serial_no is None: - log.debug("({ip}) Setting projector serial number to '{data}'".format(ip=self.ip, data=data)) + log.debug('({ip}) Setting projector serial number to "{data}"'.format(ip=self.ip, data=data)) self.serial_no = data self.db_update = False else: # Compare serial numbers and see if we got the same projector if self.serial_no != data: - log.warning("({ip}) Projector serial number does not match saved serial number".format(ip=self.ip)) - log.warning("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.serial_no)) - log.warning("({ip}) Received: '{new}'".format(ip=self.ip, new=data)) - log.warning("({ip}) NOT saving serial number".format(ip=self.ip)) + log.warning('({ip}) Projector serial number does not match saved serial number'.format(ip=self.ip)) + log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.serial_no)) + log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data)) + log.warning('({ip}) NOT saving serial number'.format(ip=self.ip)) self.serial_no_received = data def process_sver(self, data): @@ -500,20 +547,20 @@ class PJLinkCommands(object): """ if len(data) > 32: # Defined in specs max version is 32 characters - log.warning("Invalid software version - too long") + log.warning('Invalid software version - too long') return elif self.sw_version is None: - log.debug("({ip}) Setting projector software version to '{data}'".format(ip=self.ip, data=data)) + log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data)) self.sw_version = data self.db_update = True else: # Compare software version and see if we got the same projector if self.serial_no != data: - log.warning("({ip}) Projector software version does not match saved " - "software version".format(ip=self.ip)) - log.warning("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.sw_version)) - log.warning("({ip}) Received: '{new}'".format(ip=self.ip, new=data)) - log.warning("({ip}) Saving new serial number as sw_version_received".format(ip=self.ip)) + log.warning('({ip}) Projector software version does not match saved ' + 'software version'.format(ip=self.ip)) + log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version)) + log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data)) + log.warning('({ip}) Saving new serial number as sw_version_received'.format(ip=self.ip)) self.sw_version_received = data @@ -540,9 +587,9 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): :param poll_time: Time (in seconds) to poll connected projector :param socket_timeout: Time (in seconds) to abort the connection if no response """ - log.debug('PJlink(projector={projector}, args={args} kwargs={kwargs})'.format(projector=projector, - args=args, - kwargs=kwargs)) + log.debug('PJlink(projector="{projector}", args="{args}" kwargs="{kwargs}")'.format(projector=projector, + args=args, + kwargs=kwargs)) super().__init__() self.entry = projector self.ip = self.entry.ip @@ -573,6 +620,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): self.widget = None # QListBox entry self.timer = None # Timer that calls the poll_loop self.send_queue = [] + self.priority_queue = [] self.send_busy = False # Socket timer for some possible brain-dead projectors or network cable pulled self.socket_timer = None @@ -586,6 +634,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): self.connected.connect(self.check_login) self.disconnected.connect(self.disconnect_from_host) self.error.connect(self.get_error) + self.projectorReceivedData.connect(self._send_command) def thread_stopped(self): """ @@ -608,6 +657,10 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): self.projectorReceivedData.disconnect(self._send_command) except TypeError: pass + try: + self.readyRead.disconnect(self.get_socket) # Set in process_pjlink + except TypeError: + pass self.disconnect_from_host() self.deleteLater() self.i_am_running = False @@ -625,10 +678,10 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): Retrieve information from projector that changes. Normally called by timer(). """ - if self.state() != self.ConnectedState: - log.warning("({ip}) poll_loop(): Not connected - returning".format(ip=self.ip)) + if self.state() != S_QSOCKET_STATE['ConnectedState']: + log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip)) return - log.debug('({ip}) Updating projector status'.format(ip=self.ip)) + log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip)) # Reset timer in case we were called from a set command if self.timer.interval() < self.poll_time: # Reset timer to 5 seconds @@ -640,28 +693,28 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): if self.pjlink_class == '2': check_list.extend(['FILT', 'FREZ']) for command in check_list: - self.send_command(command, queue=True) + self.send_command(command) # The following commands do not change, so only check them once if self.power == S_ON and self.source_available is None: - self.send_command('INST', queue=True) + self.send_command('INST') if self.other_info is None: - self.send_command('INFO', queue=True) + self.send_command('INFO') if self.manufacturer is None: - self.send_command('INF1', queue=True) + self.send_command('INF1') if self.model is None: - self.send_command('INF2', queue=True) + self.send_command('INF2') if self.pjlink_name is None: - self.send_command('NAME', queue=True) + self.send_command('NAME') if self.pjlink_class == '2': # Class 2 specific checks if self.serial_no is None: - self.send_command('SNUM', queue=True) + self.send_command('SNUM') if self.sw_version is None: - self.send_command('SVER', queue=True) + self.send_command('SVER') if self.model_filter is None: - self.send_command('RFIL', queue=True) + self.send_command('RFIL') if self.model_lamp is None: - self.send_command('RLMP', queue=True) + self.send_command('RLMP') def _get_status(self, status): """ @@ -713,14 +766,12 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): code=status_code, message=status_message if msg is None else msg)) self.changeStatus.emit(self.ip, status, message) + self.projectorUpdateIcons.emit() @QtCore.pyqtSlot() def check_login(self, data=None): """ - Processes the initial connection and authentication (if needed). - Starts poll timer if connection is established. - - NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function. + Processes the initial connection and convert to a PJLink packet if valid initial connection :param data: Optional data if called from another routine """ @@ -733,12 +784,12 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): self.change_status(E_SOCKET_TIMEOUT) return read = self.readLine(self.max_size) - self.readLine(self.max_size) # Clean out the trailing \r\n + self.readLine(self.max_size) # Clean out any trailing whitespace if read is None: log.warning('({ip}) read is None - socket error?'.format(ip=self.ip)) return elif len(read) < 8: - log.warning('({ip}) Not enough data read)'.format(ip=self.ip)) + log.warning('({ip}) Not enough data read - skipping'.format(ip=self.ip)) return data = decode(read, 'utf-8') # Possibility of extraneous data on input when reading. @@ -750,9 +801,16 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): # PJLink initial login will be: # 'PJLink 0' - Unauthenticated login - no extra steps required. # 'PJLink 1 XXXXXX' Authenticated login - extra processing required. - if not data.upper().startswith('PJLINK'): - # Invalid response + if not data.startswith('PJLINK'): + # Invalid initial packet - close socket + log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip)) return self.disconnect_from_host() + log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip)) + return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX, + clss='1', + data=data.replace(' ', '=', 1)).encode('utf-8')) + # TODO: The below is replaced by process_pjlink() - remove when working properly + """ if '=' in data: # Processing a login reply data_check = data.strip().split('=') @@ -801,18 +859,19 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): log.debug('({ip}) Starting timer'.format(ip=self.ip)) self.timer.setInterval(2000) # Set 2 seconds for initial information self.timer.start() + """ def _trash_buffer(self, msg=None): """ Clean out extraneous stuff in the buffer. """ - log.warning("({ip}) {message}".format(ip=self.ip, message='Invalid packet' if msg is None else msg)) + log.warning('({ip}) {message}'.format(ip=self.ip, message='Invalid packet' if msg is None else msg)) self.send_busy = False trash_count = 0 while self.bytesAvailable() > 0: trash = self.read(self.max_size) trash_count += len(trash) - log.debug("({ip}) Finished cleaning buffer - {count} bytes dropped".format(ip=self.ip, + log.debug('({ip}) Finished cleaning buffer - {count} bytes dropped'.format(ip=self.ip, count=trash_count)) return @@ -824,7 +883,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): :param data: Data to process. buffer must be formatted as a proper PJLink packet. :param ip: Destination IP for buffer. """ - log.debug("({ip}) get_buffer(data='{buff}' ip='{ip_in}'".format(ip=self.ip, buff=data, ip_in=ip)) + log.debug('({ip}) get_buffer(data="{buff}" ip="{ip_in}"'.format(ip=self.ip, buff=data, ip_in=ip)) if ip is None: log.debug("({ip}) get_buffer() Don't know who data is for - exiting".format(ip=self.ip)) return @@ -842,38 +901,52 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): return # Although we have a packet length limit, go ahead and use a larger buffer read = self.readLine(1024) - log.debug("({ip}) get_socket(): '{buff}'".format(ip=self.ip, buff=read)) + log.debug('({ip}) get_socket(): "{buff}"'.format(ip=self.ip, buff=read)) if read == -1: # No data available log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.ip)) return self.receive_data_signal() self.socket_timer.stop() - return self.get_data(buff=read, ip=self.ip) + self.get_data(buff=read, ip=self.ip) + return self.receive_data_signal() - def get_data(self, buff, ip): + def get_data(self, buff, ip=None): """ Process received data :param buff: Data to process. :param ip: (optional) Destination IP. """ - log.debug("({ip}) get_data(ip='{ip_in}' buffer='{buff}'".format(ip=self.ip, ip_in=ip, buff=buff)) + # Since "self" is not available to options and the "ip" keyword is a "maybe I'll use in the future", + # set to default here + if ip is None: + ip = self.ip + log.debug('({ip}) get_data(ip="{ip_in}" buffer="{buff}"'.format(ip=self.ip, ip_in=ip, buff=buff)) # NOTE: Class2 has changed to some values being UTF-8 data_in = decode(buff, 'utf-8') data = data_in.strip() - if (len(data) < 7) or (not data.startswith(PJLINK_PREFIX)): - return self._trash_buffer(msg='get_data(): Invalid packet - length or prefix') + # Initial packet checks + if (len(data) < 7): + return self._trash_buffer(msg='get_data(): Invalid packet - length') elif len(data) > self.max_size: return self._trash_buffer(msg='get_data(): Invalid packet - too long') + elif not data.startswith(PJLINK_PREFIX): + return self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing') elif '=' not in data: - return self._trash_buffer(msg='get_data(): Invalid packet does not have equal') + return self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="') log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data)) header, data = data.split('=') + # At this point, the header should contain: + # "PVCCCC" + # Where: + # P = PJLINK_PREFIX + # V = PJLink class or version + # C = PJLink command try: - version, cmd = header[1], header[2:] + version, cmd = header[1], header[2:].upper() except ValueError as e: self.change_status(E_INVALID_DATA) - log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip())) + log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in)) return self._trash_buffer('get_data(): Expected header + command + data') if cmd not in PJLINK_VALID_CMD: log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd)) @@ -881,6 +954,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): if int(self.pjlink_class) < int(version): log.warning('({ip}) get_data(): Projector returned class reply higher ' 'than projector stated class'.format(ip=self.ip)) + self.send_busy = False return self.process_command(cmd, data) @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError) @@ -910,19 +984,18 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): self.reset_information() return - def send_command(self, cmd, opts='?', salt=None, queue=False): + def send_command(self, cmd, opts='?', salt=None, priority=False): """ Add command to output queue if not already in queue. :param cmd: Command to send :param opts: Command option (if any) - defaults to '?' (get information) :param salt: Optional salt for md5 hash initial authentication - :param queue: Option to force add to queue rather than sending directly + :param priority: Option to send packet now rather than queue it up """ if self.state() != self.ConnectedState: log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip)) - self.send_queue = [] - return + return self.reset_information() if cmd not in PJLINK_VALID_CMD: log.error('({ip}) send_command(): Invalid command requested - ignoring.'.format(ip=self.ip)) return @@ -939,28 +1012,26 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): header = PJLINK_HEADER.format(linkclass=cmd_ver[0]) else: # NOTE: Once we get to version 3 then think about looping - log.error('({ip}): send_command(): PJLink class check issue? aborting'.format(ip=self.ip)) + log.error('({ip}): send_command(): PJLink class check issue? Aborting'.format(ip=self.ip)) return out = '{salt}{header}{command} {options}{suffix}'.format(salt="" if salt is None else salt, header=header, command=cmd, options=opts, suffix=CR) - if out in self.send_queue: - # Already there, so don't add - log.debug('({ip}) send_command(out="{data}") Already in queue - skipping'.format(ip=self.ip, - data=out.strip())) - elif not queue and len(self.send_queue) == 0: - # Nothing waiting to send, so just send it - log.debug('({ip}) send_command(out="{data}") Sending data'.format(ip=self.ip, data=out.strip())) - return self._send_command(data=out) + if out in self.priority_queue: + log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip)) + elif out in self.send_queue: + log.debug('({ip}) send_command(): Already in normal queue - skipping'.format(ip=self.ip)) else: - log.debug('({ip}) send_command(out="{data}") adding to queue'.format(ip=self.ip, data=out.strip())) - self.send_queue.append(out) - self.projectorReceivedData.emit() - log.debug('({ip}) send_command(): send_busy is {data}'.format(ip=self.ip, data=self.send_busy)) - if not self.send_busy: - log.debug('({ip}) send_command() calling _send_string()'.format(ip=self.ip)) + if priority: + log.debug('({ip}) send_command(): Adding to priority queue'.format(ip=self.ip)) + self.priority_queue.append(out) + else: + log.debug('({ip}) send_command(): Adding to normal queue'.format(ip=self.ip)) + self.send_queue.append(out) + if self.priority_queue or self.send_queue: + # May be some initial connection setup so make sure we send data self._send_command() @QtCore.pyqtSlot() @@ -971,43 +1042,53 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): :param data: Immediate data to send :param utf8: Send as UTF-8 string otherwise send as ASCII string """ - log.debug('({ip}) _send_string()'.format(ip=self.ip)) - log.debug('({ip}) _send_string(): Connection status: {data}'.format(ip=self.ip, data=self.state())) + # Funny looking data check, but it's a quick check for data=None + log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data)) + log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip, + data=S_QSOCKET_STATE[self.state()])) if self.state() != self.ConnectedState: - log.debug('({ip}) _send_string() Not connected - abort'.format(ip=self.ip)) - self.send_queue = [] + log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip)) self.send_busy = False - return + return self.disconnect_from_host() + if data and data not in self.priority_queue: + log.debug('({ip}) _send_command(): Priority packet - adding to priority queue'.format(ip=self.ip)) + self.priority_queue.append(data) + if self.send_busy: # Still waiting for response from last command sent + log.debug('({ip}) _send_command(): Still busy, returning'.format(ip=self.ip)) + log.debug('({ip}) _send_command(): Priority queue = {data}'.format(ip=self.ip, data=self.priority_queue)) + log.debug('({ip}) _send_command(): Normal queue = {data}'.format(ip=self.ip, data=self.send_queue)) return - if data is not None: - out = data - log.debug('({ip}) _send_string(data="{data}")'.format(ip=self.ip, data=out.strip())) + + if len(self.priority_queue) != 0: + out = self.priority_queue.pop(0) + log.debug('({ip}) _send_command(): Getting priority queued packet'.format(ip=self.ip)) elif len(self.send_queue) != 0: out = self.send_queue.pop(0) - log.debug('({ip}) _send_string(queued data="{data}"%s)'.format(ip=self.ip, data=out.strip())) + log.debug('({ip}) _send_command(): Getting normal queued packet'.format(ip=self.ip)) else: # No data to send - log.debug('({ip}) _send_string(): No data to send'.format(ip=self.ip)) + log.debug('({ip}) _send_command(): No data to send'.format(ip=self.ip)) self.send_busy = False return self.send_busy = True - log.debug('({ip}) _send_string(): Sending "{data}"'.format(ip=self.ip, data=out.strip())) - log.debug('({ip}) _send_string(): Queue = {data}'.format(ip=self.ip, data=self.send_queue)) + log.debug('({ip}) _send_command(): Sending "{data}"'.format(ip=self.ip, data=out.strip())) self.socket_timer.start() sent = self.write(out.encode('{string_encoding}'.format(string_encoding='utf-8' if utf8 else 'ascii'))) self.waitForBytesWritten(2000) # 2 seconds should be enough if sent == -1: # Network error? - log.warning("({ip}) _send_command(): -1 received".format(ip=self.ip)) + log.warning('({ip}) _send_command(): -1 received - disconnecting from host'.format(ip=self.ip)) self.change_status(E_NETWORK, translate('OpenLP.PJLink', 'Error while sending data to projector')) + self.disconnect_from_host() def connect_to_host(self): """ Initiate connection to projector. """ + log.debug('{ip}) connect_to_host(): Starting connection'.format(ip=self.ip)) if self.state() == self.ConnectedState: log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip)) return @@ -1023,22 +1104,19 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): if abort: log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip)) else: - log.warning('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip)) - self.reset_information() + log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip)) self.disconnectFromHost() try: self.readyRead.disconnect(self.get_socket) except TypeError: pass + log.debug('({ip}) disconnect_from_host() ' + 'Current status {data}'.format(ip=self.ip, data=self._get_status(self.status_connect)[0])) if abort: self.change_status(E_NOT_CONNECTED) else: - log.debug('({ip}) disconnect_from_host() ' - 'Current status {data}'.format(ip=self.ip, data=self._get_status(self.status_connect)[0])) - if self.status_connect != E_NOT_CONNECTED: - self.change_status(S_NOT_CONNECTED) + self.change_status(S_NOT_CONNECTED) self.reset_information() - self.projectorUpdateIcons.emit() def get_av_mute_status(self): """ diff --git a/tests/functional/openlp_core/api/http/test_error.py b/tests/functional/openlp_core/api/http/test_error.py index 1a694705c..599ecfc03 100644 --- a/tests/functional/openlp_core/api/http/test_error.py +++ b/tests/functional/openlp_core/api/http/test_error.py @@ -42,8 +42,8 @@ class TestApiError(TestCase): raise NotFound() # THEN: we get an error and a status - self.assertEquals('Not Found', context.exception.message, 'A Not Found exception should be thrown') - self.assertEquals(404, context.exception.status, 'A 404 status should be thrown') + assert 'Not Found' == context.exception.message, 'A Not Found exception should be thrown' + assert 404 == context.exception.status, 'A 404 status should be thrown' def test_server_error(self): """ @@ -55,5 +55,5 @@ class TestApiError(TestCase): raise ServerError() # THEN: we get an error and a status - self.assertEquals('Server Error', context.exception.message, 'A Not Found exception should be thrown') - self.assertEquals(500, context.exception.status, 'A 500 status should be thrown') + assert'Server Error' == context.exception.message, 'A Not Found exception should be thrown' + assert 500 == context.exception.status, 'A 500 status should be thrown' diff --git a/tests/functional/openlp_core/api/http/test_http.py b/tests/functional/openlp_core/api/http/test_http.py index ed584c1b9..7dd8418ae 100644 --- a/tests/functional/openlp_core/api/http/test_http.py +++ b/tests/functional/openlp_core/api/http/test_http.py @@ -53,8 +53,8 @@ class TestHttpServer(TestCase): HttpServer() # THEN: the api environment should have been created - self.assertEquals(1, mock_qthread.call_count, 'The qthread should have been called once') - self.assertEquals(1, mock_thread.call_count, 'The http thread should have been called once') + assert mock_qthread.call_count == 1, 'The qthread should have been called once' + assert mock_thread.call_count == 1, 'The http thread should have been called once' @patch('openlp.core.api.http.server.HttpWorker') @patch('openlp.core.api.http.server.QtCore.QThread') @@ -68,5 +68,5 @@ class TestHttpServer(TestCase): HttpServer() # THEN: the api environment should have been created - self.assertEquals(0, mock_qthread.call_count, 'The qthread should not have have been called') - self.assertEquals(0, mock_thread.call_count, 'The http thread should not have been called') + assert mock_qthread.call_count == 0, 'The qthread should not have have been called' + assert mock_thread.call_count == 0, 'The http thread should not have been called' diff --git a/tests/functional/openlp_core/api/http/test_wsgiapp.py b/tests/functional/openlp_core/api/http/test_wsgiapp.py index aff27404a..17b3ae8c5 100644 --- a/tests/functional/openlp_core/api/http/test_wsgiapp.py +++ b/tests/functional/openlp_core/api/http/test_wsgiapp.py @@ -61,7 +61,7 @@ class TestRouting(TestCase): application.dispatch(rqst) # THEN: the not found returned - self.assertEqual(context.exception.args[0], 'Not Found', 'URL not found in dispatcher') + assert context.exception.args[0] == 'Not Found', 'URL not found in dispatcher' # WHEN: when the URL is correct and dispatch called rqst = MagicMock() @@ -69,8 +69,8 @@ class TestRouting(TestCase): rqst.method = 'GET' application.dispatch(rqst) # THEN: the not found id called - self.assertEqual(1, application.route_map['^\\/test\\/image$']['GET'].call_count, - 'main_index function should have been called') + assert 1 == application.route_map['^\\/test\\/image$']['GET'].call_count, \ + 'main_index function should have been called' @test_endpoint.route('image') diff --git a/tests/functional/openlp_core/api/test_deploy.py b/tests/functional/openlp_core/api/test_deploy.py index 702e2a35d..0aaf1308b 100644 --- a/tests/functional/openlp_core/api/test_deploy.py +++ b/tests/functional/openlp_core/api/test_deploy.py @@ -58,4 +58,4 @@ class TestRemoteDeploy(TestCase): deploy_zipfile(self.app_root_path, 'site.zip') # THEN: test if www directory has been created - self.assertTrue((self.app_root_path / 'www').is_dir(), 'We should have a www directory') + assert (self.app_root_path / 'www').is_dir(), 'We should have a www directory' diff --git a/tests/functional/openlp_core/api/test_tab.py b/tests/functional/openlp_core/api/test_tab.py index f3c4f31e6..bd701784d 100644 --- a/tests/functional/openlp_core/api/test_tab.py +++ b/tests/functional/openlp_core/api/test_tab.py @@ -81,8 +81,8 @@ class TestApiTab(TestCase, TestMixin): # WHEN: the default ip address is given ip_address = self.form.get_ip_address(ZERO_URL) # THEN: the default ip address will be returned - self.assertTrue(re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), - 'The return value should be a valid ip address') + assert re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), \ + 'The return value should be a valid ip address' def test_get_ip_address_with_ip(self): """ @@ -93,7 +93,7 @@ class TestApiTab(TestCase, TestMixin): # WHEN: the default ip address is given ip_address = self.form.get_ip_address(given_ip) # THEN: the default ip address will be returned - self.assertEqual(ip_address, given_ip, 'The return value should be %s' % given_ip) + assert ip_address == given_ip, 'The return value should be %s' % given_ip def test_set_urls(self): """ @@ -104,12 +104,11 @@ class TestApiTab(TestCase, TestMixin): # WHEN: the urls are generated self.form.set_urls() # THEN: the following links are returned - self.assertEqual(self.form.remote_url.text(), - "http://192.168.1.1:4316/", - 'The return value should be a fully formed link') - self.assertEqual(self.form.stage_url.text(), - "http://192.168.1.1:4316/stage", - 'The return value should be a fully formed stage link') - self.assertEqual(self.form.live_url.text(), - "http://192.168.1.1:4316/main", - 'The return value should be a fully formed main link') + assert self.form.remote_url.text() == "http://192.168.1.1:4316/", \ + 'The return value should be a fully formed link' + assert self.form.stage_url.text() == \ + "http://192.168.1.1:4316/stage", \ + 'The return value should be a fully formed stage link' + assert self.form.live_url.text() == \ + "http://192.168.1.1:4316/main", \ + 'The return value should be a fully formed main link' diff --git a/tests/functional/openlp_core/api/test_websockets.py b/tests/functional/openlp_core/api/test_websockets.py index f400c50a5..7da90123d 100644 --- a/tests/functional/openlp_core/api/test_websockets.py +++ b/tests/functional/openlp_core/api/test_websockets.py @@ -74,8 +74,8 @@ class TestWSServer(TestCase, TestMixin): WebSocketServer() # THEN: the api environment should have been created - self.assertEquals(1, mock_qthread.call_count, 'The qthread should have been called once') - self.assertEquals(1, mock_worker.call_count, 'The http thread should have been called once') + assert mock_qthread.call_count == 1, 'The qthread should have been called once' + assert mock_worker.call_count == 1, 'The http thread should have been called once' @patch('openlp.core.api.websockets.WebSocketWorker') @patch('openlp.core.api.websockets.QtCore.QThread') @@ -89,8 +89,8 @@ class TestWSServer(TestCase, TestMixin): WebSocketServer() # THEN: the api environment should have been created - self.assertEquals(0, mock_qthread.call_count, 'The qthread should not have been called') - self.assertEquals(0, mock_worker.call_count, 'The http thread should not have been called') + assert mock_qthread.call_count == 0, 'The qthread should not have been called' + assert mock_worker.call_count == 0, 'The http thread should not have been called' def test_main_poll(self): """ @@ -102,8 +102,7 @@ class TestWSServer(TestCase, TestMixin): Registry().register('live_controller', mocked_live_controller) # THEN: the live json should be generated main_json = self.poll.main_poll() - self.assertEquals(b'{"results": {"slide_count": 5}}', main_json, - 'The return value should match the defined json') + assert b'{"results": {"slide_count": 5}}' == main_json, 'The return value should match the defined json' def test_poll(self): """ @@ -130,13 +129,13 @@ class TestWSServer(TestCase, TestMixin): mocked_is_chords_active.return_value = True poll_json = self.poll.poll() # THEN: the live json should be generated and match expected results - self.assertTrue(poll_json['results']['blank'], 'The blank return value should be True') - self.assertFalse(poll_json['results']['theme'], 'The theme return value should be False') - self.assertFalse(poll_json['results']['display'], 'The display return value should be False') - self.assertFalse(poll_json['results']['isSecure'], 'The isSecure return value should be False') - self.assertFalse(poll_json['results']['isAuthorised'], 'The isAuthorised return value should be False') - self.assertTrue(poll_json['results']['twelve'], 'The twelve return value should be False') - self.assertEquals(poll_json['results']['version'], 3, 'The version return value should be 3') - self.assertEquals(poll_json['results']['slide'], 5, 'The slide return value should be 5') - self.assertEquals(poll_json['results']['service'], 21, 'The version return value should be 21') - self.assertEquals(poll_json['results']['item'], '23-34-45', 'The item return value should match 23-34-45') + assert poll_json['results']['blank'] is True, 'The blank return value should be True' + assert poll_json['results']['theme'] is False, 'The theme return value should be False' + assert poll_json['results']['display'] is False, 'The display return value should be False' + assert poll_json['results']['isSecure'] is False, 'The isSecure return value should be False' + assert poll_json['results']['isAuthorised'] is False, 'The isAuthorised return value should be False' + assert poll_json['results']['twelve'] is True, 'The twelve return value should be True' + assert poll_json['results']['version'] == 3, 'The version return value should be 3' + assert poll_json['results']['slide'] == 5, 'The slide return value should be 5' + assert poll_json['results']['service'] == 21, 'The version return value should be 21' + assert poll_json['results']['item'] == '23-34-45', 'The item return value should match 23-34-45' diff --git a/tests/functional/openlp_core/common/test_actions.py b/tests/functional/openlp_core/common/test_actions.py index 57905654d..7d5ac6fca 100644 --- a/tests/functional/openlp_core/common/test_actions.py +++ b/tests/functional/openlp_core/common/test_actions.py @@ -59,8 +59,8 @@ class TestCategoryActionList(TestCase): self.list.append(self.action1) # THEN: The actions should (not) be in the list. - self.assertTrue(self.action1 in self.list) - self.assertFalse(self.action2 in self.list) + assert self.action1 in self.list + assert self.action2 not in self.list def test_len(self): """ @@ -69,14 +69,14 @@ class TestCategoryActionList(TestCase): # GIVEN: The list. # WHEN: Do nothing. # THEN: Check the length. - self.assertEqual(len(self.list), 0, "The length should be 0.") + assert len(self.list) == 0, "The length should be 0." # GIVEN: The list. # WHEN: Append an action. self.list.append(self.action1) # THEN: Check the length. - self.assertEqual(len(self.list), 1, "The length should be 1.") + assert len(self.list) == 1, "The length should be 1." def test_append(self): """ @@ -88,10 +88,10 @@ class TestCategoryActionList(TestCase): self.list.append(self.action2) # THEN: Check if the actions are in the list and check if they have the correct weights. - self.assertTrue(self.action1 in self.list) - self.assertTrue(self.action2 in self.list) - self.assertEqual(self.list.actions[0], (0, self.action1)) - self.assertEqual(self.list.actions[1], (1, self.action2)) + assert self.action1 in self.list + assert self.action2 in self.list + assert self.list.actions[0] == (0, self.action1) + assert self.list.actions[1] == (1, self.action2) def test_add(self): """ @@ -106,11 +106,11 @@ class TestCategoryActionList(TestCase): self.list.add(self.action2, action2_weight) # THEN: Check if they were added and have the specified weights. - self.assertTrue(self.action1 in self.list) - self.assertTrue(self.action2 in self.list) + assert self.action1 in self.list + assert self.action2 in self.list # Now check if action1 is second and action2 is first (due to their weights). - self.assertEqual(self.list.actions[0], (41, self.action2)) - self.assertEqual(self.list.actions[1], (42, self.action1)) + assert self.list.actions[0] == (41, self.action2) + assert self.list.actions[1] == (42, self.action1) def test_iterator(self): """ @@ -121,11 +121,11 @@ class TestCategoryActionList(TestCase): self.list.add(self.action2) # WHEN: Iterating over the list - list = [a for a in self.list] + local_list = [a for a in self.list] # THEN: Make sure they are returned in correct order - self.assertEquals(len(self.list), 2) - self.assertIs(list[0], self.action1) - self.assertIs(list[1], self.action2) + assert len(self.list) == 2 + assert local_list[0] is self.action1 + assert local_list[1] is self.action2 def test_remove(self): """ @@ -138,7 +138,7 @@ class TestCategoryActionList(TestCase): self.list.remove(self.action1) # THEN: Now the element should not be in the list anymore. - self.assertFalse(self.action1 in self.list) + assert self.action1 not in self.list # THEN: Check if an exception is raised when trying to remove a not present action. self.assertRaises(ValueError, self.list.remove, self.action2) diff --git a/tests/functional/openlp_core/common/test_common.py b/tests/functional/openlp_core/common/test_common.py index 1d817ee90..368705821 100644 --- a/tests/functional/openlp_core/common/test_common.py +++ b/tests/functional/openlp_core/common/test_common.py @@ -48,7 +48,7 @@ class TestCommonFunctions(TestCase): extension_loader('glob', ['file2.py', 'file3.py']) # THEN: `extension_loader` should not try to import any files - self.assertFalse(mocked_import_module.called) + assert mocked_import_module.called is False def test_extension_loader_files_found(self): """ @@ -69,7 +69,8 @@ class TestCommonFunctions(TestCase): # THEN: `extension_loader` should only try to import the files that are matched by the blob, excluding the # files listed in the `excluded_files` argument - mocked_import_module.assert_has_calls([call('openlp.import_dir.file1'), call('openlp.import_dir.file4')]) + mocked_import_module.assert_has_calls([call('openlp.import_dir.file1'), + call('openlp.import_dir.file4')]) def test_extension_loader_import_error(self): """ @@ -87,7 +88,7 @@ class TestCommonFunctions(TestCase): extension_loader('glob') # THEN: The `ImportError` should be caught and logged - self.assertTrue(mocked_logger.warning.called) + assert mocked_logger.warning.called def test_extension_loader_os_error(self): """ @@ -105,7 +106,7 @@ class TestCommonFunctions(TestCase): extension_loader('glob') # THEN: The `OSError` should be caught and logged - self.assertTrue(mocked_logger.warning.called) + assert mocked_logger.warning.called def test_de_hump_conversion(self): """ @@ -118,7 +119,7 @@ class TestCommonFunctions(TestCase): new_string = de_hump(string) # THEN: the new string should be converted to python format - self.assertEqual(new_string, "my_class", 'The class name should have been converted') + assert new_string == "my_class", 'The class name should have been converted' def test_de_hump_static(self): """ @@ -131,7 +132,7 @@ class TestCommonFunctions(TestCase): new_string = de_hump(string) # THEN: the new string should be converted to python format - self.assertEqual(new_string, "my_class", 'The class name should have been preserved') + assert new_string == "my_class", 'The class name should have been preserved' def test_path_to_module(self): """ @@ -144,7 +145,7 @@ class TestCommonFunctions(TestCase): result = path_to_module(path) # THEN: path_to_module should return the module name - self.assertEqual(result, 'openlp.core.ui.media.webkitplayer') + assert result == 'openlp.core.ui.media.webkitplayer' def test_trace_error_handler(self): """ @@ -174,9 +175,9 @@ class TestCommonFunctions(TestCase): mocked_sys.platform = 'win32' # THEN: The three platform functions should perform properly - self.assertTrue(is_win(), 'is_win() should return True') - self.assertFalse(is_macosx(), 'is_macosx() should return False') - self.assertFalse(is_linux(), 'is_linux() should return False') + assert is_win() is True, 'is_win() should return True' + assert is_macosx() is False, 'is_macosx() should return False' + assert is_linux() is False, 'is_linux() should return False' def test_is_macosx(self): """ @@ -190,9 +191,9 @@ class TestCommonFunctions(TestCase): mocked_sys.platform = 'darwin' # THEN: The three platform functions should perform properly - self.assertTrue(is_macosx(), 'is_macosx() should return True') - self.assertFalse(is_win(), 'is_win() should return False') - self.assertFalse(is_linux(), 'is_linux() should return False') + assert is_macosx() is True, 'is_macosx() should return True' + assert is_win() is False, 'is_win() should return False' + assert is_linux() is False, 'is_linux() should return False' def test_is_linux(self): """ @@ -206,9 +207,9 @@ class TestCommonFunctions(TestCase): mocked_sys.platform = 'linux3' # THEN: The three platform functions should perform properly - self.assertTrue(is_linux(), 'is_linux() should return True') - self.assertFalse(is_win(), 'is_win() should return False') - self.assertFalse(is_macosx(), 'is_macosx() should return False') + assert is_linux() is True, 'is_linux() should return True' + assert is_win() is False, 'is_win() should return False' + assert is_macosx() is False, 'is_macosx() should return False' def test_clean_button_text(self): """ @@ -222,4 +223,4 @@ class TestCommonFunctions(TestCase): actual_text = clean_button_text(input_text) # THEN: The text should have been cleaned - self.assertEqual(expected_text, actual_text, 'The text should be clean') + assert expected_text == actual_text, 'The text should be clean' diff --git a/tests/functional/openlp_core/common/test_httputils.py b/tests/functional/openlp_core/common/test_httputils.py index 5e7a396b2..b7c08993f 100644 --- a/tests/functional/openlp_core/common/test_httputils.py +++ b/tests/functional/openlp_core/common/test_httputils.py @@ -59,7 +59,7 @@ class TestHttpUtils(TestCase, TestMixin): # THEN: The user agent is a Linux (or ChromeOS) user agent result = 'Linux' in user_agent or 'CrOS' in user_agent - self.assertTrue(result, 'The user agent should be a valid Linux user agent') + assert result is True, 'The user agent should be a valid Linux user agent' def test_get_user_agent_windows(self): """ @@ -74,7 +74,7 @@ class TestHttpUtils(TestCase, TestMixin): user_agent = get_user_agent() # THEN: The user agent is a Linux (or ChromeOS) user agent - self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent') + assert 'Windows' in user_agent, 'The user agent should be a valid Windows user agent' def test_get_user_agent_macos(self): """ @@ -89,7 +89,7 @@ class TestHttpUtils(TestCase, TestMixin): user_agent = get_user_agent() # THEN: The user agent is a Linux (or ChromeOS) user agent - self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent') + assert 'Mac OS X' in user_agent, 'The user agent should be a valid OS X user agent' def test_get_user_agent_default(self): """ @@ -104,7 +104,7 @@ class TestHttpUtils(TestCase, TestMixin): user_agent = get_user_agent() # THEN: The user agent is a Linux (or ChromeOS) user agent - self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent') + assert 'NetBSD'in user_agent, 'The user agent should be the default user agent' def test_get_web_page_no_url(self): """ @@ -117,7 +117,7 @@ class TestHttpUtils(TestCase, TestMixin): result = get_web_page(test_url) # THEN: None should be returned - self.assertIsNone(result, 'The return value of get_web_page should be None') + assert result is None, 'The return value of get_web_page should be None' @patch('openlp.core.common.httputils.requests') @patch('openlp.core.common.httputils.get_user_agent') @@ -240,4 +240,4 @@ class TestHttpUtils(TestCase, TestMixin): # THEN: socket.timeout should have been caught # NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files - assert not os.path.exists(self.tempfile), 'tempfile should have been deleted' + assert os.path.exists(self.tempfile) is False, 'tempfile should have been deleted' diff --git a/tests/functional/openlp_core/common/test_init.py b/tests/functional/openlp_core/common/test_init.py index 9b86c99aa..9965a07ee 100644 --- a/tests/functional/openlp_core/common/test_init.py +++ b/tests/functional/openlp_core/common/test_init.py @@ -63,8 +63,8 @@ class TestInit(TestCase, TestMixin): add_actions(mocked_target, empty_list) # THEN: The add method on the mocked target is never called - self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called') - self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called') + assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called' + assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called' def test_add_actions_none_action(self): """ @@ -79,7 +79,7 @@ class TestInit(TestCase, TestMixin): # THEN: The addSeparator method is called, but the addAction method is never called mocked_target.addSeparator.assert_called_with() - self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called') + assert mocked_target.addAction.call_count == 0, 'addAction method should not have been called' def test_add_actions_add_action(self): """ @@ -93,7 +93,7 @@ class TestInit(TestCase, TestMixin): add_actions(mocked_target, action_list) # THEN: The addSeparator method is not called, and the addAction method is called - self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called') + assert mocked_target.addSeparator.call_count == 0, 'addSeparator method should not have been called' mocked_target.addAction.assert_called_with('action') def test_add_actions_action_and_none(self): @@ -150,9 +150,8 @@ class TestInit(TestCase, TestMixin): result = get_uno_command() # THEN: The command 'libreoffice' should be called with the appropriate parameters - self.assertEquals(result, - 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' - ' "--accept=pipe,name=openlp_pipe;urp;"') + assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \ + ' "--accept=pipe,name=openlp_pipe;urp;"' def test_get_uno_command_only_soffice_command_exists(self): """ @@ -169,8 +168,8 @@ class TestInit(TestCase, TestMixin): result = get_uno_command() # THEN: The command 'soffice' should be called with the appropriate parameters - self.assertEquals(result, 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard' - ' "--accept=pipe,name=openlp_pipe;urp;"') + assert result == 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \ + ' "--accept=pipe,name=openlp_pipe;urp;"' def test_get_uno_command_when_no_command_exists(self): """ @@ -198,8 +197,8 @@ class TestInit(TestCase, TestMixin): result = get_uno_command('socket') # THEN: The connection parameters should be set for socket - self.assertEqual(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' - ' "--accept=socket,host=localhost,port=2002;urp;"') + assert result == 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' \ + ' "--accept=socket,host=localhost,port=2002;urp;"' def test_get_filesystem_encoding_sys_function_not_called(self): """ @@ -215,8 +214,8 @@ class TestInit(TestCase, TestMixin): # THEN: getdefaultencoding should have been called mocked_getfilesystemencoding.assert_called_with() - self.assertEqual(0, mocked_getdefaultencoding.called, 'getdefaultencoding should not have been called') - self.assertEqual('cp1252', result, 'The result should be "cp1252"') + assert mocked_getdefaultencoding.called == 0, 'getdefaultencoding should not have been called' + assert 'cp1252' == result, 'The result should be "cp1252"' def test_get_filesystem_encoding_sys_function_is_called(self): """ @@ -234,7 +233,7 @@ class TestInit(TestCase, TestMixin): # THEN: getdefaultencoding should have been called mocked_getfilesystemencoding.assert_called_with() mocked_getdefaultencoding.assert_called_with() - self.assertEqual('utf-8', result, 'The result should be "utf-8"') + assert 'utf-8' == result, 'The result should be "utf-8"' def test_clean_filename(self): """ @@ -248,7 +247,7 @@ class TestInit(TestCase, TestMixin): result = clean_filename(invalid_name) # THEN: The file name should be cleaned. - self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.') + assert wanted_name == result, 'The file name should not contain any special characters.' def test_delete_file_no_path(self): """ @@ -259,7 +258,7 @@ class TestInit(TestCase, TestMixin): result = delete_file(None) # THEN: delete_file should return False - self.assertFalse(result, "delete_file should return False when called with None") + assert result is False, "delete_file should return False when called with None" def test_delete_file_path_success(self): """ @@ -272,7 +271,7 @@ class TestInit(TestCase, TestMixin): result = delete_file(Path('path', 'file.ext')) # THEN: delete_file should return True - self.assertTrue(result, 'delete_file should return True when it successfully deletes a file') + assert result is True, 'delete_file should return True when it successfully deletes a file' def test_delete_file_path_no_file_exists(self): """ @@ -286,8 +285,8 @@ class TestInit(TestCase, TestMixin): result = delete_file(Path('path', 'file.ext')) # THEN: The function should not attempt to delete the file and it should return True - self.assertFalse(mocked_unlink.called) - self.assertTrue(result, 'delete_file should return True when the file doesnt exist') + assert mocked_unlink.called is False + assert result is True, 'delete_file should return True when the file doesnt exist' def test_delete_file_path_exception(self): """ @@ -303,8 +302,8 @@ class TestInit(TestCase, TestMixin): result = delete_file(Path('path', 'file.ext')) # THEN: The exception should be logged and `delete_file` should return False - self.assertTrue(mocked_log.exception.called) - self.assertFalse(result, 'delete_file should return False when an OSError is raised') + assert mocked_log.exception.called + assert result is False, 'delete_file should return False when an OSError is raised' def test_get_file_encoding_done(self): """ @@ -323,9 +322,9 @@ class TestInit(TestCase, TestMixin): # THEN: The feed method of UniversalDetector should only br called once before returning a result mocked_open.assert_called_once_with('rb') - self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256)]) + assert mocked_universal_detector_inst.feed.mock_calls == [call(b"data" * 256)] mocked_universal_detector_inst.close.assert_called_once_with() - self.assertEqual(result, encoding_result) + assert result == encoding_result def test_get_file_encoding_eof(self): """ @@ -345,9 +344,9 @@ class TestInit(TestCase, TestMixin): # THEN: The feed method of UniversalDetector should have been called twice before returning a result mocked_open.assert_called_once_with('rb') - self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256), call(b"data" * 4)]) + assert mocked_universal_detector_inst.feed.mock_calls == [call(b"data" * 256), call(b"data" * 4)] mocked_universal_detector_inst.close.assert_called_once_with() - self.assertEqual(result, encoding_result) + assert result == encoding_result def test_get_file_encoding_oserror(self): """ @@ -364,4 +363,4 @@ class TestInit(TestCase, TestMixin): # THEN: log.exception should be called and get_file_encoding should return None mocked_log.exception.assert_called_once_with('Error detecting file encoding') - self.assertIsNone(result) + assert result is None diff --git a/tests/functional/openlp_core/common/test_json.py b/tests/functional/openlp_core/common/test_json.py index 3b0631dc4..18cba3b4e 100644 --- a/tests/functional/openlp_core/common/test_json.py +++ b/tests/functional/openlp_core/common/test_json.py @@ -45,7 +45,7 @@ class TestOpenLPJsonDecoder(TestCase): result = instance.object_hook({'__Path__': ['test', 'path']}) # THEN: A Path object should be returned - self.assertEqual(result, Path('test', 'path')) + assert result == Path('test', 'path') def test_object_hook_non_path_object(self): """ @@ -59,8 +59,8 @@ class TestOpenLPJsonDecoder(TestCase): result = instance.object_hook({'key': 'value'}) # THEN: The object should be returned unchanged and a Path object should not have been initiated - self.assertEqual(result, {'key': 'value'}) - self.assertFalse(mocked_path.called) + assert result == {'key': 'value'} + assert mocked_path.called is False def test_json_decode(self): """ @@ -73,7 +73,7 @@ class TestOpenLPJsonDecoder(TestCase): obj = json.loads(json_string, cls=OpenLPJsonDecoder) # THEN: The object returned should be a python version of the JSON string - self.assertEqual(obj, [Path('test', 'path1'), Path('test', 'path2')]) + assert obj == [Path('test', 'path1'), Path('test', 'path2')] class TestOpenLPJsonEncoder(TestCase): @@ -91,7 +91,7 @@ class TestOpenLPJsonEncoder(TestCase): result = instance.default(Path('test', 'path')) # THEN: A dictionary object that can be JSON encoded should be returned - self.assertEqual(result, {'__Path__': ('test', 'path')}) + assert result == {'__Path__': ('test', 'path')} def test_default_non_path_object(self): """ @@ -119,4 +119,4 @@ class TestOpenLPJsonEncoder(TestCase): json_string = json.dumps(obj, cls=OpenLPJsonEncoder) # THEN: The JSON string return should be a representation of the object encoded - self.assertEqual(json_string, '[{"__Path__": ["test", "path1"]}, {"__Path__": ["test", "path2"]}]') + assert json_string == '[{"__Path__": ["test", "path1"]}, {"__Path__": ["test", "path2"]}]' diff --git a/tests/functional/openlp_core/common/test_mixins.py b/tests/functional/openlp_core/common/test_mixins.py index 8eee60c6f..f49c2b797 100644 --- a/tests/functional/openlp_core/common/test_mixins.py +++ b/tests/functional/openlp_core/common/test_mixins.py @@ -46,7 +46,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): # GIVEN an Empty Registry # WHEN there is no Application # THEN the application should be none - self.assertEqual(self.application, None, 'The application value should be None') + assert self.application is None, 'The application value should be None' def test_application(self): """ @@ -59,7 +59,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): Registry().register('application', application) # THEN the application should be none - self.assertEqual(self.application, application, 'The application value should match') + assert self.application == application, 'The application value should match' @patch('openlp.core.common.mixins.is_win') def test_application_on_windows(self, mocked_is_win): @@ -74,7 +74,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): Registry().register('application', application) # THEN the application should be none - self.assertEqual(self.application, application, 'The application value should match') + assert self.application == application, 'The application value should match' @patch('openlp.core.common.mixins.is_win') def test_get_application_on_windows(self, mocked_is_win): @@ -93,6 +93,6 @@ class TestRegistryProperties(TestCase, RegistryProperties): 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') + assert mock_application == actual_application, 'The application value should match' mocked_is_win.assert_called_with() mocked_get.assert_called_with('application') diff --git a/tests/functional/openlp_core/common/test_path.py b/tests/functional/openlp_core/common/test_path.py index 498b7aaa0..b069c251d 100644 --- a/tests/functional/openlp_core/common/test_path.py +++ b/tests/functional/openlp_core/common/test_path.py @@ -47,8 +47,8 @@ class TestShutil(TestCase): result_args, result_kwargs = replace_params(test_args, test_kwargs, test_params) # THEN: The positional and keyword args should not have changed - self.assertEqual(test_args, result_args) - self.assertEqual(test_kwargs, result_kwargs) + assert test_args == result_args + assert test_kwargs == result_kwargs def test_replace_params_params(self): """ @@ -63,8 +63,8 @@ class TestShutil(TestCase): result_args, result_kwargs = replace_params(test_args, test_kwargs, test_params) # THEN: The positional and keyword args should have have changed - self.assertEqual(result_args, (1, '2')) - self.assertEqual(result_kwargs, {'arg3': '3', 'arg4': 4}) + assert result_args == (1, '2') + assert result_kwargs == {'arg3': '3', 'arg4': 4} def test_copy(self): """ @@ -82,7 +82,7 @@ class TestShutil(TestCase): # :func:`shutil.copy` as a Path object. mocked_shutil_copy.assert_called_once_with(os.path.join('source', 'test', 'path'), os.path.join('destination', 'test', 'path')) - self.assertEqual(result, Path('destination', 'test', 'path')) + assert result == Path('destination', 'test', 'path') def test_copy_follow_optional_params(self): """ @@ -114,7 +114,7 @@ class TestShutil(TestCase): # :func:`shutil.copyfile` as a Path object. mocked_shutil_copyfile.assert_called_once_with(os.path.join('source', 'test', 'path'), os.path.join('destination', 'test', 'path')) - self.assertEqual(result, Path('destination', 'test', 'path')) + assert result == Path('destination', 'test', 'path') def test_copyfile_optional_params(self): """ @@ -147,7 +147,7 @@ class TestShutil(TestCase): # :func:`shutil.copytree` as a Path object. mocked_shutil_copytree.assert_called_once_with(os.path.join('source', 'test', 'path'), os.path.join('destination', 'test', 'path')) - self.assertEqual(result, Path('destination', 'test', 'path')) + assert result == Path('destination', 'test', 'path') def test_copytree_optional_params(self): """ @@ -177,12 +177,11 @@ class TestShutil(TestCase): path = Path('test', 'path') # WHEN: Calling :func:`openlp.core.common.path.rmtree` with the path parameter as Path object type - result = path.rmtree() + path.rmtree() # THEN: :func:`shutil.rmtree` should have been called with the str equivalents of the Path object. mocked_shutil_rmtree.assert_called_once_with( os.path.join('test', 'path'), False, None) - self.assertIsNone(result) def test_rmtree_optional_params(self): """ @@ -214,7 +213,7 @@ class TestShutil(TestCase): # THEN: :func:`shutil.which` should have been called with the command, and :func:`which` should return None. mocked_shutil_which.assert_called_once_with('no_command') - self.assertIsNone(result) + assert result is None def test_which_command(self): """ @@ -230,7 +229,7 @@ class TestShutil(TestCase): # THEN: :func:`shutil.which` should have been called with the command, and :func:`which` should return a # Path object equivalent of the command path. mocked_shutil_which.assert_called_once_with('command') - self.assertEqual(result, Path('path', 'to', 'command')) + assert result == Path('path', 'to', 'command') class TestPath(TestCase): @@ -257,7 +256,7 @@ class TestPath(TestCase): result = path_to_str(None) # THEN: `path_to_str` should return an empty string - self.assertEqual(result, '') + assert result == '' def test_path_to_str_path_object(self): """ @@ -268,7 +267,7 @@ class TestPath(TestCase): result = path_to_str(Path('test/path')) # THEN: `path_to_str` should return a string representation of the Path object - self.assertEqual(result, os.path.join('test', 'path')) + assert result == os.path.join('test', 'path') def test_str_to_path_type_error(self): """ @@ -289,7 +288,7 @@ class TestPath(TestCase): result = str_to_path('') # THEN: `path_to_str` should return None - self.assertEqual(result, None) + assert result is None def test_path_encode_json(self): """ @@ -301,7 +300,7 @@ class TestPath(TestCase): path = Path.encode_json({'__Path__': ['path', 'to', 'fi.le']}, extra=1, args=2) # THEN: A Path object should have been returned - self.assertEqual(path, Path('path', 'to', 'fi.le')) + assert path == Path('path', 'to', 'fi.le') def test_path_encode_json_base_path(self): """ @@ -313,7 +312,7 @@ class TestPath(TestCase): path = Path.encode_json({'__Path__': ['path', 'to', 'fi.le']}, base_path=Path('/base')) # THEN: A Path object should have been returned with an absolute path - self.assertEqual(path, Path('/', 'base', 'path', 'to', 'fi.le')) + assert path == Path('/', 'base', 'path', 'to', 'fi.le') def test_path_json_object(self): """ @@ -326,7 +325,7 @@ class TestPath(TestCase): obj = path.json_object(extra=1, args=2) # THEN: A JSON decodable object should have been returned. - self.assertEqual(obj, {'__Path__': ('/', 'base', 'path', 'to', 'fi.le')}) + assert obj == {'__Path__': ('/', 'base', 'path', 'to', 'fi.le')} def test_path_json_object_base_path(self): """ @@ -340,7 +339,7 @@ class TestPath(TestCase): obj = path.json_object(base_path=Path('/', 'base')) # THEN: A JSON decodable object should have been returned. - self.assertEqual(obj, {'__Path__': ('path', 'to', 'fi.le')}) + assert obj == {'__Path__': ('path', 'to', 'fi.le')} def test_create_paths_dir_exists(self): """ diff --git a/tests/functional/openlp_core/common/test_projector_utilities.py b/tests/functional/openlp_core/common/test_projector_utilities.py index cbdfec238..5a3f886cf 100644 --- a/tests/functional/openlp_core/common/test_projector_utilities.py +++ b/tests/functional/openlp_core/common/test_projector_utilities.py @@ -45,7 +45,7 @@ ip6_link_local = 'fe80::223:14ff:fe99:d315' ip6_bad = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' -class testProjectorUtilities(TestCase): +class TestProjectorUtilities(TestCase): """ Validate functions in the projector utilities module """ @@ -57,7 +57,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip4_loopback) # THEN: Verify we received True - self.assertTrue(valid, 'IPv4 loopback address should have been valid') + assert valid, 'IPv4 loopback address should have been valid' def test_ip4_local_valid(self): """ @@ -67,7 +67,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip4_local) # THEN: Verify we received True - self.assertTrue(valid, 'IPv4 local address should have been valid') + assert valid is True, 'IPv4 local address should have been valid' def test_ip4_broadcast_valid(self): """ @@ -77,7 +77,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip4_broadcast) # THEN: Verify we received True - self.assertTrue(valid, 'IPv4 broadcast address should have been valid') + assert valid is True, 'IPv4 broadcast address should have been valid' def test_ip4_address_invalid(self): """ @@ -87,7 +87,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip4_bad) # THEN: Verify we received True - self.assertFalse(valid, 'Bad IPv4 address should not have been valid') + assert valid is False, 'Bad IPv4 address should not have been valid' def test_ip6_loopback_valid(self): """ @@ -97,7 +97,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip6_loopback) # THEN: Validate return - self.assertTrue(valid, 'IPv6 loopback address should have been valid') + assert valid is True, 'IPv6 loopback address should have been valid' def test_ip6_local_valid(self): """ @@ -107,7 +107,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip6_link_local) # THEN: Validate return - self.assertTrue(valid, 'IPv6 link-local address should have been valid') + assert valid is True, 'IPv6 link-local address should have been valid' def test_ip6_address_invalid(self): """ @@ -117,7 +117,7 @@ class testProjectorUtilities(TestCase): valid = verify_ip_address(addr=ip6_bad) # THEN: Validate bad return - self.assertFalse(valid, 'IPv6 bad address should have been invalid') + assert valid is False, 'IPv6 bad address should have been invalid' def test_md5_hash(self): """ @@ -127,7 +127,7 @@ class testProjectorUtilities(TestCase): hash_ = md5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8')) # THEN: Validate return has is same - self.assertEquals(hash_, test_hash, 'MD5 should have returned a good hash') + assert hash_ == test_hash, 'MD5 should have returned a good hash' def test_md5_hash_bad(self): """ @@ -137,7 +137,7 @@ class testProjectorUtilities(TestCase): hash_ = md5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8')) # THEN: return data is different - self.assertNotEquals(hash_, test_hash, 'MD5 should have returned a bad hash') + assert hash_ is not test_hash, 'MD5 should have returned a bad hash' def test_qmd5_hash(self): """ @@ -147,7 +147,7 @@ class testProjectorUtilities(TestCase): hash_ = qmd5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8')) # THEN: Validate return has is same - self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash') + assert hash_ == test_hash, 'Qt-MD5 should have returned a good hash' def test_qmd5_hash_bad(self): """ @@ -157,7 +157,7 @@ class testProjectorUtilities(TestCase): hash_ = qmd5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8')) # THEN: return data is different - self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash') + assert hash_ is not test_hash, 'Qt-MD5 should have returned a bad hash' def test_md5_non_ascii_string(self): """ @@ -167,7 +167,7 @@ class testProjectorUtilities(TestCase): hash_ = md5_hash(salt=test_non_ascii_string.encode('utf-8'), data=None) # THEN: Valid MD5 hash should be returned - self.assertEqual(hash_, test_non_ascii_hash, 'MD5 should have returned a valid hash') + assert hash_ == test_non_ascii_hash, 'MD5 should have returned a valid hash' def test_qmd5_non_ascii_string(self): """ @@ -177,4 +177,4 @@ class testProjectorUtilities(TestCase): hash_ = md5_hash(data=test_non_ascii_string.encode('utf-8')) # THEN: Valid MD5 hash should be returned - self.assertEqual(hash_, test_non_ascii_hash, 'Qt-MD5 should have returned a valid hash') + assert hash_ == test_non_ascii_hash, 'Qt-MD5 should have returned a valid hash' diff --git a/tests/functional/openlp_core/common/test_registry.py b/tests/functional/openlp_core/common/test_registry.py index a274243bd..6f3cc5752 100644 --- a/tests/functional/openlp_core/common/test_registry.py +++ b/tests/functional/openlp_core/common/test_registry.py @@ -51,19 +51,19 @@ class TestRegistry(TestCase): # THEN and I will get an exception with self.assertRaises(KeyError) as context: Registry().register('test1', mock_1) - self.assertEqual(context.exception.args[0], 'Duplicate service exception test1', - 'KeyError exception should have been thrown for duplicate service') + assert context.exception.args[0] == 'Duplicate service exception test1', \ + 'KeyError exception should have been thrown for duplicate service' # WHEN I try to get back a non existent component # THEN I will get an exception temp = Registry().get('test2') - self.assertEqual(temp, None, 'None should have been returned for missing service') + assert temp is None, 'None should have been returned for missing service' # WHEN I try to replace a component I should be allowed Registry().remove('test1') # THEN I will get an exception temp = Registry().get('test1') - self.assertEqual(temp, None, 'None should have been returned for deleted service') + assert temp is None, 'None should have been returned for deleted service' def test_registry_function(self): """ @@ -77,21 +77,21 @@ class TestRegistry(TestCase): return_value = Registry().execute('test1') # THEN: I expect then function to have been called and a return given - self.assertEqual(return_value[0], 'function_1', 'A return value is provided and matches') + assert return_value[0] == 'function_1', 'A return value is provided and matches' # WHEN: I execute the a function with the same reference and execute the function Registry().register_function('test1', self.dummy_function_1) return_value = Registry().execute('test1') # THEN: I expect then function to have been called and a return given - self.assertEqual(return_value, ['function_1', 'function_1'], 'A return value list is provided and matches') + assert return_value == ['function_1', 'function_1'], 'A return value list is provided and matches' # WHEN: I execute the a 2nd function with the different reference and execute the function Registry().register_function('test2', self.dummy_function_2) return_value = Registry().execute('test2') # THEN: I expect then function to have been called and a return given - self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches') + assert return_value[0] == 'function_2', 'A return value is provided and matches' def test_registry_working_flags(self): """ @@ -107,28 +107,28 @@ class TestRegistry(TestCase): # THEN: we should be able retrieve the saved component temp = Registry().get_flag('test1') - self.assertEquals(temp, my_data, 'The value should have been saved') + assert temp == my_data, 'The value should have been saved' # WHEN: I add a component for the second time I am not mad. # THEN and I will not get an exception Registry().set_flag('test1', my_data2) temp = Registry().get_flag('test1') - self.assertEquals(temp, my_data2, 'The value should have been updated') + assert temp == my_data2, 'The value should have been updated' # WHEN I try to get back a non existent Working Flag # THEN I will get an exception with self.assertRaises(KeyError) as context1: temp = Registry().get_flag('test2') - self.assertEqual(context1.exception.args[0], 'Working Flag test2 not found in list', - 'KeyError exception should have been thrown for missing working flag') + assert context1.exception.args[0] == 'Working Flag test2 not found in list', \ + 'KeyError exception should have been thrown for missing working flag' # WHEN I try to replace a working flag I should be allowed Registry().remove_flag('test1') # THEN I will get an exception with self.assertRaises(KeyError) as context: temp = Registry().get_flag('test1') - self.assertEqual(context.exception.args[0], 'Working Flag test1 not found in list', - 'KeyError exception should have been thrown for duplicate working flag') + assert context.exception.args[0] == 'Working Flag test1 not found in list', \ + 'KeyError exception should have been thrown for duplicate working flag' def test_remove_function(self): """ @@ -142,7 +142,7 @@ class TestRegistry(TestCase): Registry().remove_function('test1', self.dummy_function_1) # THEN: The method should not be available. - assert not Registry().functions_list['test1'], 'The function should not be in the dict anymore.' + assert Registry().functions_list['test1'] == [], 'The function should not be in the dict anymore.' def dummy_function_1(self): return "function_1" @@ -174,7 +174,7 @@ class TestRegistryBase(TestCase): PlainStub() # THEN: Nothing is registered with the registry - self.assertEqual(len(Registry().functions_list), 0), 'The function should not be in the dict anymore.' + assert len(Registry().functions_list) == 0, 'The function should not be in the dict anymore.' def test_registry_mixin_present(self): """ @@ -187,4 +187,4 @@ class TestRegistryBase(TestCase): RegistryStub() # THEN: The bootstrap methods should be registered - self.assertEqual(len(Registry().functions_list), 2), 'The bootstrap functions should be in the dict.' + assert len(Registry().functions_list) == 2, 'The bootstrap functions should be in the dict.' diff --git a/tests/functional/openlp_core/common/test_settings.py b/tests/functional/openlp_core/common/test_settings.py index ff6ee8765..4cad58af0 100644 --- a/tests/functional/openlp_core/common/test_settings.py +++ b/tests/functional/openlp_core/common/test_settings.py @@ -139,13 +139,13 @@ class TestSettings(TestCase, TestMixin): extend = settings.value('extend') # THEN the default value is returned - self.assertEqual('very wide', extend, 'The default value defined should be returned') + assert 'very wide' == extend, 'The default value defined should be returned' # WHEN a new value is saved into config Settings().setValue('test/extend', 'very short') # THEN the new value is returned when re-read - self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned') + assert 'very short' == Settings().value('test/extend'), 'The saved value should be returned' def test_settings_nonexisting(self): """Test the Settings on query for non-existing value""" @@ -155,7 +155,7 @@ class TestSettings(TestCase, TestMixin): Settings().value('core/does not exists') # THEN: An exception with the non-existing key should be thrown - self.assertEqual(str(cm.exception), "'core/does not exists'", 'We should get an exception') + assert str(cm.exception) == "'core/does not exists'", 'We should get an exception' def test_extend_default_settings(self): """Test that the extend_default_settings method extends the default settings""" @@ -167,9 +167,8 @@ class TestSettings(TestCase, TestMixin): Settings.extend_default_settings({'test/setting 3': 4, 'test/extended 1': 1, 'test/extended 2': 2}) # THEN: The _default_settings__ dictionary_ should have the new keys - self.assertEqual( - Settings.__default_settings__, {'test/setting 1': 1, 'test/setting 2': 2, 'test/setting 3': 4, - 'test/extended 1': 1, 'test/extended 2': 2}) + assert Settings.__default_settings__ == {'test/setting 1': 1, 'test/setting 2': 2, 'test/setting 3': 4, + 'test/extended 1': 1, 'test/extended 2': 2} @patch('openlp.core.common.settings.QtCore.QSettings.contains') @patch('openlp.core.common.settings.QtCore.QSettings.value') diff --git a/tests/functional/openlp_core/display/test_renderer.py b/tests/functional/openlp_core/display/test_renderer.py index c30fe083b..b1478c7b9 100644 --- a/tests/functional/openlp_core/display/test_renderer.py +++ b/tests/functional/openlp_core/display/test_renderer.py @@ -113,7 +113,7 @@ class TestRenderer(TestCase): result = get_start_tags(given_raw_text) # THEN: Check if the correct tuple is returned. - self.assertEqual(result, expected_tuple), 'A tuple should be returned containing the text with correct ' \ + assert result == expected_tuple, 'A tuple should be returned containing the text with correct ' \ 'tags, the opening tags, and the opening html tags.' def test_word_split(self): @@ -128,7 +128,7 @@ class TestRenderer(TestCase): result_words = words_split(given_line) # THEN: The word lists should be the same. - self.assertListEqual(result_words, expected_words) + assert result_words == expected_words def test_format_slide_logical_split(self): """ @@ -145,7 +145,7 @@ class TestRenderer(TestCase): result_words = renderer.format_slide(given_line, service_item) # THEN: The word lists should be the same. - self.assertListEqual(result_words, expected_words) + assert result_words == expected_words def test_format_slide_blank_before_split(self): """ @@ -162,7 +162,7 @@ class TestRenderer(TestCase): result_words = renderer.format_slide(given_line, service_item) # THEN: The blanks have been removed. - self.assertListEqual(result_words, expected_words) + assert result_words == expected_words def test_format_slide_blank_after_split(self): """ @@ -179,7 +179,7 @@ class TestRenderer(TestCase): result_words = renderer.format_slide(given_line, service_item) # THEN: The blanks have been removed. - self.assertListEqual(result_words, expected_words) + assert result_words == expected_words @patch('openlp.core.display.renderer.QtWebKitWidgets.QWebView') @patch('openlp.core.display.renderer.build_lyrics_format_css') diff --git a/tests/functional/openlp_core/display/test_screens.py b/tests/functional/openlp_core/display/test_screens.py index 258f3b69a..960f9d0a8 100644 --- a/tests/functional/openlp_core/display/test_screens.py +++ b/tests/functional/openlp_core/display/test_screens.py @@ -75,6 +75,6 @@ class TestScreenList(TestCase): # THEN: The screen should have been added and the screens should be identical new_screen_count = len(self.screens.screen_list) - self.assertEqual(old_screen_count + 1, new_screen_count, 'The new_screens list should be bigger') - self.assertEqual(SCREEN, self.screens.screen_list.pop(), - 'The 2nd screen should be identical to the first screen') + assert old_screen_count + 1 == new_screen_count, 'The new_screens list should be bigger' + assert SCREEN == self.screens.screen_list.pop(), \ + 'The 2nd screen should be identical to the first screen' diff --git a/tests/functional/openlp_core/lib/test_db.py b/tests/functional/openlp_core/lib/test_db.py index 871980498..033508965 100644 --- a/tests/functional/openlp_core/lib/test_db.py +++ b/tests/functional/openlp_core/lib/test_db.py @@ -80,8 +80,8 @@ class TestDB(TestCase): MockedMetaData.assert_called_with(bind=mocked_engine) mocked_sessionmaker.assert_called_with(autoflush=True, autocommit=False, bind=mocked_engine) mocked_scoped_session.assert_called_with(mocked_sessionmaker_object) - self.assertIs(session, mocked_scoped_session_object, 'The ``session`` object should be the mock') - self.assertIs(metadata, mocked_metadata, 'The ``metadata`` object should be the mock') + assert session is mocked_scoped_session_object, 'The ``session`` object should be the mock' + assert metadata is mocked_metadata, 'The ``metadata`` object should be the mock' def test_init_db_defaults(self): """ @@ -94,8 +94,8 @@ class TestDB(TestCase): session, metadata = init_db(db_url) # THEN: Valid session and metadata objects should be returned - self.assertIsInstance(session, ScopedSession, 'The ``session`` object should be a ``ScopedSession`` instance') - self.assertIsInstance(metadata, MetaData, 'The ``metadata`` object should be a ``MetaData`` instance') + assert isinstance(session, ScopedSession), 'The ``session`` object should be a ``ScopedSession`` instance' + assert isinstance(metadata, MetaData), 'The ``metadata`` object should be a ``MetaData`` instance' def test_get_upgrade_op(self): """ @@ -116,7 +116,7 @@ class TestDB(TestCase): op = get_upgrade_op(mocked_session) # THEN: The op object should be mocked_op, and the correction function calls should have been made - self.assertIs(op, mocked_op, 'The return value should be the mocked object') + assert op is mocked_op, 'The return value should be the mocked object' mocked_session.bind.connect.assert_called_with() MockedMigrationContext.configure.assert_called_with(mocked_connection) MockedOperations.assert_called_with(mocked_context) @@ -139,7 +139,7 @@ class TestDB(TestCase): # THEN: The AppLocation.get_section_data_path and delete_file methods should have been called MockedAppLocation.get_section_data_path.assert_called_with(test_plugin) mocked_delete_file.assert_called_with(test_location) - self.assertTrue(result, 'The result of delete_file should be True (was rigged that way)') + assert result is True, 'The result of delete_file should be True (was rigged that way)' def test_delete_database_with_db_file_name(self): """ @@ -160,7 +160,7 @@ class TestDB(TestCase): # THEN: The AppLocation.get_section_data_path and delete_file methods should have been called MockedAppLocation.get_section_data_path.assert_called_with(test_plugin) mocked_delete_file.assert_called_with(test_location) - self.assertFalse(result, 'The result of delete_file should be False (was rigged that way)') + assert result is False, 'The result of delete_file should be False (was rigged that way)' def test_skip_db_upgrade_with_no_database(self): """ @@ -174,4 +174,4 @@ class TestDB(TestCase): upgrade_db(url, mocked_upgrade) # THEN: upgrade should NOT have been called - self.assertFalse(mocked_upgrade.called, 'Database upgrade function should NOT have been called') + assert mocked_upgrade.called is False, 'Database upgrade function should NOT have been called' diff --git a/tests/functional/openlp_core/lib/test_htmlbuilder.py b/tests/functional/openlp_core/lib/test_htmlbuilder.py index 7c8d7809f..ffd796ecb 100644 --- a/tests/functional/openlp_core/lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core/lib/test_htmlbuilder.py @@ -309,7 +309,7 @@ class Htmbuilder(TestCase, TestMixin): html = build_html(item, screen, is_live, background, plugins=plugins) # THEN: The returned html should match. - self.assertEqual(html, HTML, 'The returned html should match') + assert html == HTML, 'The returned html should match' def test_build_background_css_radial(self): """ @@ -325,7 +325,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_background_css(item, width) # THEN: The returned css should match. - self.assertEqual(BACKGROUND_CSS_RADIAL, css, 'The background css should be equal.') + assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.' def test_build_lyrics_css(self): """ @@ -346,7 +346,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_css(item) # THEN: The css should be equal. - self.assertEqual(LYRICS_CSS, css, 'The lyrics css should be equal.') + assert LYRICS_CSS == css, 'The lyrics css should be equal.' def test_build_lyrics_outline_css(self): """ @@ -363,7 +363,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_outline_css(theme_data) # THEN: The css should be equal. - self.assertEqual(LYRICS_OUTLINE_CSS, css, 'The outline css should be equal.') + assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.' def test_build_lyrics_format_css(self): """ @@ -386,7 +386,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_format_css(theme_data, width, height) # THEN: They should be equal. - self.assertEqual(LYRICS_FORMAT_CSS, css, 'The lyrics format css should be equal.') + assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.' def test_build_footer_css(self): """ @@ -404,7 +404,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: THE css should be the same. - self.assertEqual(FOOTER_CSS, css, 'The footer strings should be equal.') + assert FOOTER_CSS == css, 'The footer strings should be equal.' def test_build_footer_css_wrap(self): """ @@ -423,7 +423,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: Footer should wrap - self.assertEqual(FOOTER_CSS_WRAP, css, 'The footer strings should be equal.') + assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.' def test_build_footer_invalid(self): """ @@ -443,8 +443,8 @@ class Htmbuilder(TestCase, TestMixin): css.append(build_footer_css(item, height)) # THEN: Footer should wrap - self.assertEqual(FOOTER_CSS_INVALID, css[0], 'The footer strings should be blank.') - self.assertEqual(FOOTER_CSS_INVALID, css[1], 'The footer strings should be blank.') + assert FOOTER_CSS_INVALID == css[0], 'The footer strings should be blank.' + assert FOOTER_CSS_INVALID == css[1], 'The footer strings should be blank.' def test_webkit_version(self): """ @@ -454,7 +454,7 @@ class Htmbuilder(TestCase, TestMixin): webkit_ver = float(QtWebKit.qWebKitVersion()) # WHEN: Retrieving the webkit version # THEN: Webkit versions should match - self.assertEquals(webkit_version(), webkit_ver, "The returned webkit version doesn't match the installed one") + assert webkit_version() == webkit_ver, "The returned webkit version doesn't match the installed one" def test_build_chords_css(self): """ @@ -468,4 +468,4 @@ class Htmbuilder(TestCase, TestMixin): chord_css = build_chords_css() # THEN: The build css should look as expected - self.assertEqual(CHORD_CSS_ENABLED, chord_css, 'The chord CSS should look as expected') + assert CHORD_CSS_ENABLED == chord_css, 'The chord CSS should look as expected' diff --git a/tests/functional/openlp_core/lib/test_image_manager.py b/tests/functional/openlp_core/lib/test_image_manager.py index c39f6e8f4..3c47e81a1 100644 --- a/tests/functional/openlp_core/lib/test_image_manager.py +++ b/tests/functional/openlp_core/lib/test_image_manager.py @@ -84,7 +84,7 @@ class TestImageManager(TestCase, TestMixin): # THEN a KeyError is thrown with self.assertRaises(KeyError) as context: self.image_manager.get_image(TEST_PATH, 'church1.jpg') - self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image') + assert context.exception is not '', 'KeyError exception should have been thrown for missing image' def test_different_dimension_image(self): """ @@ -98,7 +98,7 @@ class TestImageManager(TestCase, TestMixin): image = self.image_manager.get_image(full_path, 'church.jpg', 80, 80) # THEN: The return should be of type image - self.assertEqual(isinstance(image, QtGui.QImage), True, 'The returned object should be a QImage') + assert isinstance(image, QtGui.QImage), 'The returned object should be a QImage' # WHEN: adding the same image with different dimensions self.image_manager.add_image(full_path, 'church.jpg', None, 100, 100) @@ -116,7 +116,7 @@ class TestImageManager(TestCase, TestMixin): # WHEN: calling with correct image, but wrong dimensions with self.assertRaises(KeyError) as context: self.image_manager.get_image(full_path, 'church.jpg', 120, 120) - self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing dimension') + assert context.exception is not '', 'KeyError exception should have been thrown for missing dimension' def test_process_cache(self): """ @@ -141,10 +141,8 @@ class TestImageManager(TestCase, TestMixin): # is being processed (see mocked methods/functions). # Note: Priority.Normal means, that the resize_image() was not completed yet (because afterwards the # # priority is adjusted to Priority.Lowest). - self.assertEqual(self.get_image_priority(image1), Priority.Normal, - "image1's priority should be 'Priority.Normal'") - self.assertEqual(self.get_image_priority(image2), Priority.Normal, - "image2's priority should be 'Priority.Normal'") + assert self.get_image_priority(image1) == Priority.Normal, "image1's priority should be 'Priority.Normal'" + assert self.get_image_priority(image2) == Priority.Normal, "image2's priority should be 'Priority.Normal'" # WHEN: Add more images. self.image_manager.add_image(TEST_PATH, image3, None) @@ -162,15 +160,15 @@ class TestImageManager(TestCase, TestMixin): # Because empty() is not reliable, wait a litte; just to make sure. time.sleep(0.1) # THEN: The images' priority reflect how they were processed. - self.assertEqual(self.image_manager._conversion_queue.qsize(), 0, "The queue should be empty.") - self.assertEqual(self.get_image_priority(image1), Priority.Lowest, - "The image should have not been requested (=Lowest)") - self.assertEqual(self.get_image_priority(image2), Priority.Lowest, - "The image should have not been requested (=Lowest)") - self.assertEqual(self.get_image_priority(image3), Priority.Low, - "Only the QImage should have been requested (=Low).") - self.assertEqual(self.get_image_priority(image4), Priority.Urgent, - "The image bytes should have been requested (=Urgent).") + assert self.image_manager._conversion_queue.qsize() == 0, "The queue should be empty." + assert self.get_image_priority(image1) == Priority.Lowest, \ + "The image should have not been requested (=Lowest)" + assert self.get_image_priority(image2) == Priority.Lowest, \ + "The image should have not been requested (=Lowest)" + assert self.get_image_priority(image3) == Priority.Low, \ + "Only the QImage should have been requested (=Low)." + assert self.get_image_priority(image4) == Priority.Urgent, \ + "The image bytes should have been requested (=Urgent)." def get_image_priority(self, image): """ diff --git a/tests/functional/openlp_core/lib/test_lib.py b/tests/functional/openlp_core/lib/test_lib.py index e9788060e..7cc44ec4e 100644 --- a/tests/functional/openlp_core/lib/test_lib.py +++ b/tests/functional/openlp_core/lib/test_lib.py @@ -49,8 +49,8 @@ class TestLib(TestCase): true_result = str_to_bool(true_boolean) # THEN: We should get back a True bool - self.assertIsInstance(true_result, bool, 'The result should be a boolean') - self.assertTrue(true_result, 'The result should be True') + assert isinstance(true_result, bool), 'The result should be a boolean' + assert true_result is True, 'The result should be True' def test_str_to_bool_with_bool_false(self): """ @@ -63,8 +63,8 @@ class TestLib(TestCase): false_result = str_to_bool(false_boolean) # THEN: We should get back a True bool - self.assertIsInstance(false_result, bool, 'The result should be a boolean') - self.assertFalse(false_result, 'The result should be True') + assert isinstance(false_result, bool), 'The result should be a boolean' + assert false_result is False, 'The result should be True' def test_str_to_bool_with_integer(self): """ @@ -77,7 +77,7 @@ class TestLib(TestCase): int_result = str_to_bool(int_string) # THEN: we should get back a false - self.assertFalse(int_result, 'The result should be False') + assert int_result is False, 'The result should be False' def test_str_to_bool_with_invalid_string(self): """ @@ -90,7 +90,7 @@ class TestLib(TestCase): str_result = str_to_bool(invalid_string) # THEN: we should get back a false - self.assertFalse(str_result, 'The result should be False') + assert str_result is False, 'The result should be False' def test_str_to_bool_with_string_false(self): """ @@ -103,7 +103,7 @@ class TestLib(TestCase): false_result = str_to_bool(false_string) # THEN: we should get back a false - self.assertFalse(false_result, 'The result should be False') + assert false_result is False, 'The result should be False' def test_str_to_bool_with_string_no(self): """ @@ -116,7 +116,7 @@ class TestLib(TestCase): str_result = str_to_bool(no_string) # THEN: we should get back a false - self.assertFalse(str_result, 'The result should be False') + assert str_result is False, 'The result should be False' def test_str_to_bool_with_true_string_value(self): """ @@ -129,7 +129,7 @@ class TestLib(TestCase): true_result = str_to_bool(true_string) # THEN: we should get back a true - self.assertTrue(true_result, 'The result should be True') + assert true_result is True, 'The result should be True' def test_str_to_bool_with_yes_string_value(self): """ @@ -142,7 +142,7 @@ class TestLib(TestCase): str_result = str_to_bool(yes_string) # THEN: we should get back a true - self.assertTrue(str_result, 'The result should be True') + assert str_result is True, 'The result should be True' def test_get_text_file_string_no_file(self): """ @@ -157,7 +157,7 @@ class TestLib(TestCase): # THEN: The result should be False file_path.is_file.assert_called_with() - self.assertFalse(result, 'False should be returned if no file exists') + assert result is False, 'False should be returned if no file exists' def test_get_text_file_string_read_error(self): """ @@ -176,7 +176,7 @@ class TestLib(TestCase): # THEN: None should be returned file_path.is_file.assert_called_once_with() file_path.open.assert_called_once_with('r', encoding='utf-8') - self.assertIsNone(result, 'None should be returned if the file cannot be opened') + assert result is None, 'None should be returned if the file cannot be opened' def test_get_text_file_string_decode_error(self): """ @@ -195,7 +195,7 @@ class TestLib(TestCase): result = build_icon(icon) # THEN: The result should be the same icon as we passed in - self.assertIs(icon, result, 'The result should be the same icon as we passed in') + assert icon is result, 'The result should be the same icon as we passed in' def test_build_icon_with_resource(self): """ @@ -217,7 +217,7 @@ class TestLib(TestCase): MockedQPixmap.assert_called_with(resource_uri) # There really should be more assert statements here but due to type checking and things they all break. The # best we can do is to assert that we get back a MagicMock object. - self.assertIsInstance(result, MagicMock, 'The result should be a MagicMock, because we mocked it out') + assert isinstance(result, MagicMock), 'The result should be a MagicMock, because we mocked it out' def test_image_to_byte(self): """ @@ -240,8 +240,8 @@ class TestLib(TestCase): MockedQtCore.QBuffer.assert_called_with(mocked_byte_array) mocked_buffer.open.assert_called_with('writeonly') mocked_image.save.assert_called_with(mocked_buffer, "PNG") - self.assertFalse(mocked_byte_array.toBase64.called) - self.assertEqual(mocked_byte_array, result, 'The mocked out byte array should be returned') + assert mocked_byte_array.toBase64.called is False + assert mocked_byte_array == result, 'The mocked out byte array should be returned' def test_image_to_byte_base_64(self): """ @@ -266,8 +266,7 @@ class TestLib(TestCase): mocked_buffer.open.assert_called_with('writeonly') mocked_image.save.assert_called_with(mocked_buffer, "PNG") mocked_byte_array.toBase64.assert_called_with() - self.assertEqual('base64mock', result, 'The result should be the return value of the mocked out ' - 'base64 method') + assert 'base64mock' == result, 'The result should be the return value of the mocked out base64 method' def test_create_thumb_with_size(self): """ @@ -286,16 +285,16 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. icon = create_thumb(image_path, thumb_path, size=thumb_size) # THEN: Check if the thumb was created and scaled to the given size. self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual(thumb_size, QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size') + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert thumb_size == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -320,17 +319,16 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. icon = create_thumb(image_path, thumb_path) # THEN: Check if the thumb was created, retaining its aspect ratio. self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual(expected_size, QtGui.QImageReader(str(thumb_path)).size(), - 'The thumb should have the given size') + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -356,17 +354,16 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. icon = create_thumb(image_path, thumb_path, size=thumb_size) # THEN: Check if the thumb was created, retaining its aspect ratio. - self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual(expected_size, QtGui.QImageReader(str(thumb_path)).size(), - 'The thumb should have the given size') + assert thumb_path.exists() is True, 'Test was not ran, because the thumb already exists' + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -392,17 +389,16 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. icon = create_thumb(image_path, thumb_path, size=thumb_size) # THEN: Check if the thumb was created, retaining its aspect ratio. - self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual( - expected_size, QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size') + assert thumb_path.exists() is True, 'Test was not ran, because the thumb already exists' + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -428,17 +424,16 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. icon = create_thumb(image_path, thumb_path, size=thumb_size) # THEN: Check if the thumb was created, retaining its aspect ratio. self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual( - expected_size, QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size') + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -465,7 +460,7 @@ class TestLib(TestCase): pass # Only continue when the thumb does not exist. - self.assertFalse(thumb_path.exists(), 'Test was not run, because the thumb already exists.') + assert thumb_path.exists() is False, 'Test was not run, because the thumb already exists.' # WHEN: Create the thumb. with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: @@ -474,10 +469,9 @@ class TestLib(TestCase): # THEN: Check if the thumb was created with aspect ratio of 1. self.assertTrue(thumb_path.exists(), 'Test was not ran, because the thumb already exists') - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual( - expected_size_1, QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size') + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size_1 == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # WHEN: Create the thumb. with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: @@ -485,10 +479,9 @@ class TestLib(TestCase): icon = create_thumb(image_path, thumb_path, size=thumb_size) # THEN: Check if the thumb was created with aspect ratio of 1. - self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') - self.assertFalse(icon.isNull(), 'The icon should not be null') - self.assertEqual( - expected_size_2, QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size') + assert isinstance(icon, QtGui.QIcon), 'The icon should be a QIcon' + assert icon.isNull() is False, 'The icon should not be null' + assert expected_size_2 == QtGui.QImageReader(str(thumb_path)).size(), 'The thumb should have the given size' # Remove the thumb so that the test actually tests if the thumb will be created. try: @@ -511,7 +504,7 @@ class TestLib(TestCase): # THEN: The selectedIndexes function should have been called and the result should be true mocked_list_widget.selectedIndexes.assert_called_with() - self.assertTrue(result, 'The result should be True') + assert result is True, 'The result should be True' def test_check_item_selected_false(self): """ @@ -532,7 +525,7 @@ class TestLib(TestCase): # THEN: The selectedIndexes function should have been called and the result should be true mocked_list_widget.selectedIndexes.assert_called_with() MockedQtWidgets.QMessageBox.information.assert_called_with('parent', 'mocked translate', 'message') - self.assertFalse(result, 'The result should be False') + assert result is False, 'The result should be False' def test_clean_tags(self): """ @@ -554,7 +547,7 @@ class TestLib(TestCase): result_string = clean_tags(string_to_pass) # THEN: The strings should be identical. - self.assertEqual(wanted_string, result_string, 'The strings should be identical') + assert wanted_string == result_string, 'The strings should be identical' def test_expand_tags(self): """ @@ -593,7 +586,7 @@ class TestLib(TestCase): result_string = expand_tags(string_to_pass) # THEN: The strings should be identical. - self.assertEqual(wanted_string, result_string, 'The strings should be identical.') + assert wanted_string == result_string, 'The strings should be identical.' def test_validate_thumb_file_does_not_exist(self): """ @@ -609,7 +602,7 @@ class TestLib(TestCase): # THEN: we should have called a few functions, and the result should be False thumb_path.exists.assert_called_once_with() - self.assertFalse(result, 'The result should be False') + assert result is False, 'The result should be False' def test_validate_thumb_file_exists_and_newer(self): """ @@ -624,7 +617,7 @@ class TestLib(TestCase): result = validate_thumb(file_path, thumb_path) # THEN: `validate_thumb` should return True - self.assertTrue(result) + assert result is True def test_validate_thumb_file_exists_and_older(self): """ @@ -639,7 +632,7 @@ class TestLib(TestCase): # THEN: `validate_thumb` should return False thumb_path.stat.assert_called_once_with() - self.assertFalse(result, 'The result should be False') + assert result is False, 'The result should be False' def test_resize_thumb(self): """ @@ -658,9 +651,9 @@ class TestLib(TestCase): # THEN: Check if the size is correct and the background was set. result_size = image.size() - self.assertEqual(wanted_height, result_size.height(), 'The image should have the requested height.') - self.assertEqual(wanted_width, result_size.width(), 'The image should have the requested width.') - self.assertEqual(image.pixel(0, 0), wanted_background_rgb, 'The background should be white.') + assert wanted_height == result_size.height(), 'The image should have the requested height.' + assert wanted_width == result_size.width(), 'The image should have the requested width.' + assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.' def test_resize_thumb_ignoring_aspect_ratio(self): """ @@ -679,9 +672,9 @@ class TestLib(TestCase): # THEN: Check if the size is correct and the background was set. result_size = image.size() - self.assertEqual(wanted_height, result_size.height(), 'The image should have the requested height.') - self.assertEqual(wanted_width, result_size.width(), 'The image should have the requested width.') - self.assertEqual(image.pixel(0, 0), wanted_background_rgb, 'The background should be white.') + assert wanted_height == result_size.height(), 'The image should have the requested height.' + assert wanted_width == result_size.width(), 'The image should have the requested width.' + assert image.pixel(0, 0) == wanted_background_rgb, 'The background should be white.' @patch('openlp.core.lib.QtCore.QLocale.createSeparatedList') def test_create_separated_list_qlocate(self, mocked_createSeparatedList): @@ -696,8 +689,8 @@ class TestLib(TestCase): string_result = create_separated_list(string_list) # THEN: We should have "Author 1, Author 2, and Author 3" - self.assertEqual(string_result, 'Author 1, Author 2 and Author 3', 'The string should be "Author 1, ' - 'Author 2, and Author 3".') + assert string_result == 'Author 1, Author 2 and Author 3', \ + 'The string should be "Author 1, Author 2, and Author 3".' def test_create_separated_list_empty_list(self): """ @@ -710,7 +703,7 @@ class TestLib(TestCase): string_result = create_separated_list(string_list) # THEN: We shoud have an emptry string. - self.assertEqual(string_result, '', 'The string sould be empty.') + assert string_result == '', 'The string sould be empty.' def test_create_separated_list_with_one_item(self): """ @@ -723,7 +716,7 @@ class TestLib(TestCase): string_result = create_separated_list(string_list) # THEN: We should have "Author 1" - self.assertEqual(string_result, 'Author 1', 'The string should be "Author 1".') + assert string_result == 'Author 1', 'The string should be "Author 1".' def test_create_separated_list_with_two_items(self): """ @@ -736,7 +729,7 @@ class TestLib(TestCase): string_result = create_separated_list(string_list) # THEN: We should have "Author 1 and Author 2" - self.assertEqual(string_result, 'Author 1 and Author 2', 'The string should be "Author 1 and Author 2".') + assert string_result == 'Author 1 and Author 2', 'The string should be "Author 1 and Author 2".' def test_create_separated_list_with_three_items(self): """ @@ -749,8 +742,8 @@ class TestLib(TestCase): string_result = create_separated_list(string_list) # THEN: We should have "Author 1, Author 2 and Author 3" - self.assertEqual(string_result, 'Author 1, Author 2 and Author 3', 'The string should be "Author 1, ' - 'Author 2, and Author 3".') + assert string_result == 'Author 1, Author 2 and Author 3', \ + 'The string should be "Author 1, Author 2, and Author 3".' def test_expand_chords(self): """ @@ -766,7 +759,7 @@ class TestLib(TestCase): expected_html = 'HC' \ 'alleluya.F' \ ' G' - self.assertEqual(expected_html, text_with_expanded_chords, 'The expanded chords should look as expected!') + assert expected_html == text_with_expanded_chords, 'The expanded chords should look as expected!' def test_expand_chords2(self): """ @@ -782,7 +775,7 @@ class TestLib(TestCase): expected_html = 'ID' \ ''M NOT MOVED BY WHAT I SEE HALLEF' \ 'LUJACH' - self.assertEqual(expected_html, text_with_expanded_chords, 'The expanded chords should look as expected!') + assert expected_html == text_with_expanded_chords, 'The expanded chords should look as expected!' def test_compare_chord_lyric_short_chord(self): """ @@ -810,7 +803,7 @@ class TestLib(TestCase): ret = compare_chord_lyric(chord, lyrics) # THEN: The returned value should 4 because the chord is longer than the lyric - self.assertEquals(4, ret, 'The returned value should 4 because the chord is longer than the lyric') + assert 4 == ret, 'The returned value should 4 because the chord is longer than the lyric' def test_find_formatting_tags(self): """ @@ -825,7 +818,7 @@ class TestLib(TestCase): active_tags = find_formatting_tags(lyrics, tags) # THEN: The list of active tags should contain only 'st' - self.assertListEqual(['st'], active_tags, 'The list of active tags should contain only "st"') + assert ['st'] == active_tags, 'The list of active tags should contain only "st"' def test_expand_chords_for_printing(self): """ @@ -862,4 +855,4 @@ class TestLib(TestCase): '
F |
{st}{/st} | ' \ '