python-fido2/test/pyu2f/macos_test.py

143 lines
4.9 KiB
Python

# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for pyu2f.hid.macos."""
import ctypes
import sys
import mock
from fido_host.pyu2f import macos, errors
if sys.version_info[:2] < (2, 7):
import unittest2 as unittest # pylint: disable=g-import-not-at-top
else:
import unittest # pylint: disable=g-import-not-at-top
def init_mock_iokit(mock_iokit):
# Device open should always return 0 (success)
mock_iokit.IOHIDDeviceOpen = mock.Mock(return_value=0)
mock_iokit.IOHIDDeviceSetReport = mock.Mock(return_value=0)
mock_iokit.IOHIDDeviceCreate = mock.Mock(return_value='handle')
def init_mock_cf(mock_cf):
mock_cf.CFGetTypeID = mock.Mock(return_value=123)
mock_cf.CFNumberGetTypeID = mock.Mock(return_value=123)
mock_cf.CFStringGetTypeID = mock.Mock(return_value=123)
def init_mock_get_int_property(mock_get_int_property):
mock_get_int_property.return_value = 64
class MacOsTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
macos.MacOsHidDevice.__del__ = lambda x: None
@mock.patch.object(macos.threading, 'Thread')
@mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT,
GetDeviceIntProperty=mock.DEFAULT)
def testInitHidDevice(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name
init_mock_iokit(iokit)
init_mock_cf(cf)
init_mock_get_int_property(GetDeviceIntProperty)
device = macos.MacOsHidDevice('fakepath')
self.assertEqual(64, device.GetInReportDataLength())
self.assertEqual(64, device.GetOutReportDataLength())
@mock.patch.object(macos.threading, 'Thread')
@mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT,
GetDeviceIntProperty=mock.DEFAULT)
def testCallWriteSuccess(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name
init_mock_iokit(iokit)
init_mock_cf(cf)
init_mock_get_int_property(GetDeviceIntProperty)
device = macos.MacOsHidDevice('fakepath')
# Write 64 bytes to device
data = bytearray(range(64))
# Write to device
device.Write(data)
# Validate that write calls into IOKit
set_report_call_args = iokit.IOHIDDeviceSetReport.call_args
self.assertIsNotNone(set_report_call_args)
set_report_call_pos_args = iokit.IOHIDDeviceSetReport.call_args[0]
self.assertEqual(len(set_report_call_pos_args), 5)
self.assertEqual(set_report_call_pos_args[0], 'handle')
self.assertEqual(set_report_call_pos_args[1], 1)
self.assertEqual(set_report_call_pos_args[2], 0)
self.assertEqual(set_report_call_pos_args[4], 64)
report_buffer = set_report_call_pos_args[3]
self.assertEqual(len(report_buffer), 64)
self.assertEqual(bytearray(report_buffer), data, 'Data sent to '
'IOHIDDeviceSetReport should match data sent to the '
'device')
@mock.patch.object(macos.threading, 'Thread')
@mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT,
GetDeviceIntProperty=mock.DEFAULT)
def testCallWriteFailure(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name
init_mock_iokit(iokit)
init_mock_cf(cf)
init_mock_get_int_property(GetDeviceIntProperty)
# Make set report call return failure (non-zero)
iokit.IOHIDDeviceSetReport.return_value = -1
device = macos.MacOsHidDevice('fakepath')
# Write 64 bytes to device
data = bytearray(range(64))
# Write should throw an OsHidError exception
with self.assertRaises(errors.OsHidError):
device.Write(data)
@mock.patch.object(macos.threading, 'Thread')
@mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT,
GetDeviceIntProperty=mock.DEFAULT)
def testCallReadSuccess(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name
init_mock_iokit(iokit)
init_mock_cf(cf)
init_mock_get_int_property(GetDeviceIntProperty)
device = macos.MacOsHidDevice('fakepath')
# Call callback for IN report
report = (ctypes.c_uint8 * 64)()
report[:] = range(64)[:]
q = device.read_queue
macos.HidReadCallback(q, None, None, None, 0, report, 64)
# Device read should return the callback data
read_result = device.Read()
self.assertEqual(read_result, list(range(64)), 'Read data should match data '
'passed into the callback')
if __name__ == '__main__':
unittest.main()