68 lines
3.5 KiB
Python
68 lines
3.5 KiB
Python
import importlib.util
|
|
from pathlib import Path
|
|
import stat
|
|
import struct
|
|
from types import SimpleNamespace
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
path = Path(__file__).parents[1] / 'src/camera_test_pkg/camera_test_pkg/devices.py'
|
|
spec = importlib.util.spec_from_file_location('camera_devices', path)
|
|
devices = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(devices)
|
|
|
|
|
|
def capability(caps, device_caps=0):
|
|
data = bytearray(104)
|
|
struct.pack_into('II', data, 84, caps, device_caps)
|
|
return data
|
|
|
|
|
|
class DeviceTests(unittest.TestCase):
|
|
def test_capture_only_not_metadata_or_codec(self):
|
|
for caps in [0x04000001, 0x04001000, 0x01000001]:
|
|
self.assertTrue(devices.capture_capabilities(capability(caps)))
|
|
for caps in [0x04800000, 0x04008001, 0x04004001, 0x04000002, 1]:
|
|
self.assertFalse(devices.capture_capabilities(capability(caps)))
|
|
self.assertFalse(devices.capture_capabilities(capability(0x84000001, 0x04800000)))
|
|
|
|
def test_discovery_filters_nodes_and_sorts_numbers(self):
|
|
def query(fd, request, data, mutate):
|
|
self.assertEqual(request, 0x80685600)
|
|
data[:] = capability(0x04800000 if fd == 1 else 0x04000001)
|
|
with patch.object(devices.glob, 'glob', return_value=['/dev/video10', '/dev/video1', '/dev/video0', '/dev/videobad']), \
|
|
patch.object(devices.os, 'lstat', return_value=SimpleNamespace(st_mode=stat.S_IFCHR)), \
|
|
patch.object(devices.os, 'open', side_effect=lambda path, flags: int(path[10:])), \
|
|
patch.object(devices.os, 'close') as close, patch.object(devices.fcntl, 'ioctl', side_effect=query):
|
|
self.assertEqual(devices.discover_devices(), ['/dev/video0', '/dev/video10'])
|
|
self.assertEqual(close.call_count, 3)
|
|
|
|
def test_no_devices_and_invalid_roots_fail_without_scanning(self):
|
|
with patch.object(devices.glob, 'glob', return_value=[]):
|
|
with self.assertRaisesRegex(RuntimeError, 'No usable'):
|
|
devices.discover_devices()
|
|
with self.assertRaises(ValueError):
|
|
devices.discover_devices('/etc')
|
|
|
|
def test_launch_creates_independent_topic_and_raw_streams(self):
|
|
import ast
|
|
source = ast.parse((path.parents[1] / 'launch/camera.launch.py').read_text())
|
|
nodes = [node for node in source.body if not isinstance(node, (ast.Import, ast.ImportFrom))]
|
|
class Configuration:
|
|
def __init__(self, name): self.name = name
|
|
def perform(self, context): return context[self.name]
|
|
scope = {'LaunchConfiguration': Configuration, 'ParameterValue': lambda value, value_type: value,
|
|
'Node': lambda **kwargs: kwargs, 'discover_devices': lambda: ['/dev/video0', '/dev/video2']}
|
|
exec(compile(ast.Module(body=nodes, type_ignores=[]), 'camera-launch', 'exec'), scope)
|
|
result = scope['camera_nodes']({'video_device': '/dev'})
|
|
self.assertEqual([node['name'] for node in result], ['camera_test_video0', 'camera_test_video2'])
|
|
self.assertEqual(result[1]['parameters'][0]['jpeg_topic'], '/camera_test/cameras/video2/image_jpeg')
|
|
self.assertEqual(result[1]['parameters'][0]['raw_topic'], '/camera_test/cameras/video2/image_raw')
|
|
single = scope['camera_nodes']({'video_device': '/dev/video0'})
|
|
self.assertEqual(single[0]['name'], 'camera_test')
|
|
self.assertEqual(single[0]['parameters'][0]['jpeg_topic'].name, 'jpeg_topic')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|