Skip to content

Commit

Permalink
Merge pull request #102 from Galvant/comm_tests
Browse files Browse the repository at this point in the history
Comm tests
  • Loading branch information
scasagrande committed Apr 8, 2016
2 parents c1447ec + b316200 commit 2f35500
Show file tree
Hide file tree
Showing 11 changed files with 999 additions and 16 deletions.
17 changes: 10 additions & 7 deletions instruments/abstract_instruments/comm/file_communicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,19 @@ class FileCommunicator(io.IOBase, AbstractCommunicator):
:param filelike: File or name of a file to be wrapped as a communicator.
Any file-like object wrapped by this class **must** support both
reading and writing. If using the `open` builtin function, the mode
``r+`` is recommended, and has been tested to work with character
``rb+`` is recommended, and has been tested to work with character
devices under Linux.
:type filelike: `str` or `file`
"""

def __init__(self, filelike):
super(FileCommunicator, self).__init__(self)
if isinstance(filelike, str):
if isinstance(filelike, str): # pragma: no cover
filelike = open(filelike, 'rb+')

self._filelike = filelike
self._terminator = "\n"
self._testing = False

# PROPERTIES #

Expand Down Expand Up @@ -105,7 +106,7 @@ def close(self):
"""
try:
self._filelike.close()
except IOError as e:
except IOError as e: # pragma: no cover
logger.warning("Failed to close file, exception: %s", repr(e))

def read_raw(self, size=-1):
Expand Down Expand Up @@ -196,8 +197,9 @@ def _query(self, msg, size=-1):
:rtype: `str`
"""
self.sendcmd(msg)
time.sleep(0.02) # Give the bus time to respond.
resp = ""
if not self._testing:
time.sleep(0.02) # Give the bus time to respond.
resp = b""
try:
# FIXME: this is slow, but we do it to avoid unreliable
# filelike devices such as some usbtmc-class devices.
Expand All @@ -206,7 +208,8 @@ def _query(self, msg, size=-1):
if not nextchar:
break
resp += nextchar
if nextchar.endswith(self._terminator):
if nextchar.endswith(self._terminator.encode("utf-8")):
resp = resp[:-len(self._terminator)]
break
except IOError as ex:
if ex.errno == errno.ETIMEDOUT:
Expand All @@ -224,4 +227,4 @@ def _query(self, msg, size=-1):
"the instrument. Consider restarting the instrument.".format(
self.address
))
return resp
return resp.decode("utf-8")
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def eos(self):
def eos(self, newval):
# pylint: disable=redefined-variable-type
if self._version <= 4:
if isinstance(newval, str):
if isinstance(newval, (str, bytes)):
newval = ord(newval)
self._file.sendcmd("+eos:{}".format(newval))
self._eos = newval
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def address(self):

@address.setter
def address(self, newval):
raise NotImplementedError()
raise NotImplementedError

@property
def terminator(self):
Expand Down Expand Up @@ -144,15 +144,15 @@ def seek(self, offset): # pylint: disable=unused-argument,no-self-use
Not implemented for loopback communicator.
"""
return NotImplemented
raise NotImplementedError

def tell(self): # pylint: disable=no-self-use
"""
Get the current positional offset for the input data source.
Not implemented for loopback communicator.
"""
return NotImplemented
raise NotImplementedError

def flush_input(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions instruments/abstract_instruments/comm/serial_communicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ def seek(self, offset): # pylint: disable=unused-argument,no-self-use
Not implemented for serial communicator.
"""
return NotImplemented
raise NotImplementedError

def tell(self): # pylint: disable=no-self-use
"""
Get the current positional offset for the input data source.
Not implemented for serial communicator.
"""
return NotImplemented
raise NotImplementedError

def flush_input(self):
"""
Expand Down
6 changes: 3 additions & 3 deletions instruments/abstract_instruments/comm/socket_communicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ def seek(self, offset): # pylint: disable=unused-argument,no-self-use
Not implemented for socket communicator.
"""
return NotImplemented
raise NotImplementedError

def tell(self): # pylint: disable=no-self-use
"""
Get the current positional offset for the input data source.
Not implemented for socket communicator.
"""
return NotImplemented
raise NotImplementedError

def flush_input(self):
"""
Expand All @@ -160,7 +160,7 @@ def _sendcmd(self, msg):
:param str msg: The command message to send to the instrument
"""
msg += self._terminator
self._conn.sendall(msg)
self.write(msg)

def _query(self, msg, size=-1):
"""
Expand Down
138 changes: 138 additions & 0 deletions instruments/tests/test_comm/test_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Unit tests for the file communication layer
"""

# IMPORTS ####################################################################

from __future__ import absolute_import

from nose.tools import raises, eq_
import mock

from instruments.abstract_instruments.comm import FileCommunicator

# TEST CASES #################################################################

# pylint: disable=protected-access,unused-argument

patch_path = "instruments.abstract_instruments.comm.file_communicator.usbtmc"


def test_filecomm_init():
mock_file = mock.MagicMock()
comm = FileCommunicator(mock_file)
assert comm._filelike is mock_file


def test_filecomm_address_getter():
mock_file = mock.MagicMock()
comm = FileCommunicator(mock_file)

mock_name = mock.PropertyMock(return_value="/home/user/file")
type(comm._filelike).name = mock_name

eq_(comm.address, "/home/user/file")
mock_name.assert_called_with()


def test_filecomm_address_getter_no_name():
mock_file = mock.MagicMock()
comm = FileCommunicator(mock_file)

del comm._filelike.name

eq_(comm.address, None)


@raises(NotImplementedError)
def test_filecomm_address_setter():
comm = FileCommunicator(mock.MagicMock())
comm.address = "abc123"


def test_filecomm_terminator():
comm = FileCommunicator(mock.MagicMock())

eq_(comm.terminator, "\n")

comm.terminator = "*"
eq_(comm._terminator, "*")

comm.terminator = b"*" # pylint: disable=redefined-variable-type
eq_(comm._terminator, "*")


@raises(NotImplementedError)
def test_filecomm_timeout_getter():
comm = FileCommunicator(mock.MagicMock())
_ = comm.timeout


@raises(NotImplementedError)
def test_filecomm_timeout_setter():
comm = FileCommunicator(mock.MagicMock())
comm.timeout = 1


def test_filecomm_close():
comm = FileCommunicator(mock.MagicMock())

comm.close()
comm._filelike.close.assert_called_with()


def test_filecomm_read_raw():
comm = FileCommunicator(mock.MagicMock())
comm._filelike.read = mock.MagicMock(side_effect=[b"a", b"b", b"c", b"\n"])

eq_(comm.read_raw(), b"abc")
comm._filelike.read.assert_has_calls([mock.call(1)] * 4)
assert comm._filelike.read.call_count == 4

comm._filelike.read = mock.MagicMock()
comm.read_raw(10)
comm._filelike.read.assert_called_with(10)


def test_filecomm_write_raw():
comm = FileCommunicator(mock.MagicMock())

comm.write_raw(b"mock")
comm._filelike.write.assert_called_with(b"mock")


def test_filecomm_sendcmd():
comm = FileCommunicator(mock.MagicMock())

comm._sendcmd("mock")
comm._filelike.write.assert_called_with(b"mock\n")


def test_filecomm_query():
comm = FileCommunicator(mock.MagicMock())
comm._testing = True # to disable the delay in the _query function
comm._filelike.read = mock.MagicMock(side_effect=[b"a", b"b", b"c", b"\n"])

eq_(comm._query("mock"), "abc")


def test_filecomm_seek():
comm = FileCommunicator(mock.MagicMock())
comm.seek(1)
comm._filelike.seek.assert_called_with(1)


def test_filecomm_tell():
comm = FileCommunicator(mock.MagicMock())
comm._filelike.tell.return_value = 5

eq_(comm.tell(), 5)
comm._filelike.tell.assert_called_with()


def test_filecomm_flush_input():
comm = FileCommunicator(mock.MagicMock())
comm.flush_input()
comm._filelike.flush.assert_called_with()

0 comments on commit 2f35500

Please sign in to comment.