AVT相机arm版本SDK
This commit is contained in:
346
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/c_binding_test.py
Normal file
346
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/c_binding_test.py
Normal file
@@ -0,0 +1,346 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import ctypes
|
||||
|
||||
from vimba.c_binding import *
|
||||
|
||||
|
||||
class VimbaCommonTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_decode_cstr_behavior(self):
|
||||
# Expected Behavior:
|
||||
# c_char_p() == ''
|
||||
# c_char_p(b'foo') == 'foo'
|
||||
|
||||
expected = ''
|
||||
actual = decode_cstr(ctypes.c_char_p())
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
expected = 'test'
|
||||
actual = decode_cstr(ctypes.c_char_p(b'test').value)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_decode_flags_zero(self):
|
||||
# Expected Behavior: In case no bytes are set the
|
||||
# zero value of the Flag Enum must be returned
|
||||
|
||||
expected = (VmbFeatureFlags.None_,)
|
||||
actual = decode_flags(VmbFeatureFlags, 0)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_decode_flags_some(self):
|
||||
# Expected Behavior: Given Integer must be decided correctly.
|
||||
# the order of the fields does not matter for this test.
|
||||
|
||||
expected = (
|
||||
VmbFeatureFlags.Write,
|
||||
VmbFeatureFlags.Read,
|
||||
VmbFeatureFlags.ModifyWrite
|
||||
)
|
||||
|
||||
input_data = 0
|
||||
|
||||
for val in expected:
|
||||
input_data |= int(val)
|
||||
|
||||
actual = decode_flags(VmbFeatureFlags, input_data)
|
||||
|
||||
# Convert both collections into a list and sort it.
|
||||
# That way order doesn't matter. It is only important that values are
|
||||
# decoded correctly.
|
||||
self.assertEqual(list(expected).sort(), list(actual).sort())
|
||||
|
||||
|
||||
class CBindingVimbaCTypesTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_enum_vmb_error(self):
|
||||
self.assertEqual(VmbError.Success, 0)
|
||||
self.assertEqual(VmbError.InternalFault, -1)
|
||||
self.assertEqual(VmbError.ApiNotStarted, -2)
|
||||
self.assertEqual(VmbError.NotFound, -3)
|
||||
self.assertEqual(VmbError.BadHandle, -4)
|
||||
self.assertEqual(VmbError.DeviceNotOpen, -5)
|
||||
self.assertEqual(VmbError.InvalidAccess, -6)
|
||||
self.assertEqual(VmbError.BadParameter, -7)
|
||||
self.assertEqual(VmbError.StructSize, -8)
|
||||
self.assertEqual(VmbError.MoreData, -9)
|
||||
self.assertEqual(VmbError.WrongType, -10)
|
||||
self.assertEqual(VmbError.InvalidValue, -11)
|
||||
self.assertEqual(VmbError.Timeout, -12)
|
||||
self.assertEqual(VmbError.Other, -13)
|
||||
self.assertEqual(VmbError.Resources, -14)
|
||||
self.assertEqual(VmbError.InvalidCall, -15)
|
||||
self.assertEqual(VmbError.NoTL, -16)
|
||||
self.assertEqual(VmbError.NotImplemented_, -17)
|
||||
self.assertEqual(VmbError.NotSupported, -18)
|
||||
self.assertEqual(VmbError.Incomplete, -19)
|
||||
self.assertEqual(VmbError.IO, -20)
|
||||
|
||||
def test_enum_vmb_pixel_format(self):
|
||||
self.assertEqual(VmbPixelFormat.Mono8, 0x01080001)
|
||||
self.assertEqual(VmbPixelFormat.Mono10, 0x01100003)
|
||||
self.assertEqual(VmbPixelFormat.Mono10p, 0x010A0046)
|
||||
self.assertEqual(VmbPixelFormat.Mono12, 0x01100005)
|
||||
self.assertEqual(VmbPixelFormat.Mono12Packed, 0x010C0006)
|
||||
self.assertEqual(VmbPixelFormat.Mono12p, 0x010C0047)
|
||||
self.assertEqual(VmbPixelFormat.Mono14, 0x01100025)
|
||||
self.assertEqual(VmbPixelFormat.Mono16, 0x01100007)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR8, 0x01080008)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG8, 0x01080009)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB8, 0x0108000A)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG8, 0x0108000B)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR10, 0x0110000C)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG10, 0x0110000D)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB10, 0x0110000E)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG10, 0x0110000F)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR12, 0x01100010)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG12, 0x01100011)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB12, 0x01100012)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG12, 0x01100013)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR12Packed, 0x010C002A)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG12Packed, 0x010C002B)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB12Packed, 0x010C002C)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG12Packed, 0x010C002D)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR10p, 0x010A0056)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG10p, 0x010A0058)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB10p, 0x010A0054)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG10p, 0x010A0052)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR12p, 0x010C0057)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG12p, 0x010C0059)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB12p, 0x010C0055)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG12p, 0x010C0053)
|
||||
self.assertEqual(VmbPixelFormat.BayerGR16, 0x0110002E)
|
||||
self.assertEqual(VmbPixelFormat.BayerRG16, 0x0110002F)
|
||||
self.assertEqual(VmbPixelFormat.BayerGB16, 0x01100030)
|
||||
self.assertEqual(VmbPixelFormat.BayerBG16, 0x01100031)
|
||||
self.assertEqual(VmbPixelFormat.Rgb8, 0x02180014)
|
||||
self.assertEqual(VmbPixelFormat.Bgr8, 0x02180015)
|
||||
self.assertEqual(VmbPixelFormat.Rgb10, 0x02300018)
|
||||
self.assertEqual(VmbPixelFormat.Bgr10, 0x02300019)
|
||||
self.assertEqual(VmbPixelFormat.Rgb12, 0x0230001A)
|
||||
self.assertEqual(VmbPixelFormat.Bgr12, 0x0230001B)
|
||||
self.assertEqual(VmbPixelFormat.Rgb14, 0x0230005E)
|
||||
self.assertEqual(VmbPixelFormat.Bgr14, 0x0230004A)
|
||||
self.assertEqual(VmbPixelFormat.Rgb16, 0x02300033)
|
||||
self.assertEqual(VmbPixelFormat.Bgr16, 0x0230004B)
|
||||
self.assertEqual(VmbPixelFormat.Argb8, 0x02200016)
|
||||
self.assertEqual(VmbPixelFormat.Rgba8, 0x02200016)
|
||||
self.assertEqual(VmbPixelFormat.Bgra8, 0x02200017)
|
||||
self.assertEqual(VmbPixelFormat.Rgba10, 0x0240005F)
|
||||
self.assertEqual(VmbPixelFormat.Bgra10, 0x0240004C)
|
||||
self.assertEqual(VmbPixelFormat.Rgba12, 0x02400061)
|
||||
self.assertEqual(VmbPixelFormat.Bgra12, 0x0240004E)
|
||||
self.assertEqual(VmbPixelFormat.Rgba14, 0x02400063)
|
||||
self.assertEqual(VmbPixelFormat.Bgra14, 0x02400050)
|
||||
self.assertEqual(VmbPixelFormat.Rgba16, 0x02400064)
|
||||
self.assertEqual(VmbPixelFormat.Bgra16, 0x02400051)
|
||||
self.assertEqual(VmbPixelFormat.Yuv411, 0x020C001E)
|
||||
self.assertEqual(VmbPixelFormat.Yuv422, 0x0210001F)
|
||||
self.assertEqual(VmbPixelFormat.Yuv444, 0x02180020)
|
||||
self.assertEqual(VmbPixelFormat.YCbCr411_8_CbYYCrYY, 0x020C003C)
|
||||
self.assertEqual(VmbPixelFormat.YCbCr422_8_CbYCrY, 0x02100043)
|
||||
self.assertEqual(VmbPixelFormat.YCbCr8_CbYCr, 0x0218003A)
|
||||
|
||||
def test_enum_vmb_interface(self):
|
||||
self.assertEqual(VmbInterface.Unknown, 0)
|
||||
self.assertEqual(VmbInterface.Firewire, 1)
|
||||
self.assertEqual(VmbInterface.Ethernet, 2)
|
||||
self.assertEqual(VmbInterface.Usb, 3)
|
||||
self.assertEqual(VmbInterface.CL, 4)
|
||||
self.assertEqual(VmbInterface.CSI2, 5)
|
||||
|
||||
def test_enum_vmb_access_mode(self):
|
||||
self.assertEqual(VmbAccessMode.None_, 0)
|
||||
self.assertEqual(VmbAccessMode.Full, 1)
|
||||
self.assertEqual(VmbAccessMode.Read, 2)
|
||||
self.assertEqual(VmbAccessMode.Config, 4)
|
||||
self.assertEqual(VmbAccessMode.Lite, 8)
|
||||
|
||||
def test_enum_vmb_feature_data(self):
|
||||
self.assertEqual(VmbFeatureData.Unknown, 0)
|
||||
self.assertEqual(VmbFeatureData.Int, 1)
|
||||
self.assertEqual(VmbFeatureData.Float, 2)
|
||||
self.assertEqual(VmbFeatureData.Enum, 3)
|
||||
self.assertEqual(VmbFeatureData.String, 4)
|
||||
self.assertEqual(VmbFeatureData.Bool, 5)
|
||||
self.assertEqual(VmbFeatureData.Command, 6)
|
||||
self.assertEqual(VmbFeatureData.Raw, 7)
|
||||
self.assertEqual(VmbFeatureData.None_, 8)
|
||||
|
||||
def test_enum_vmb_feature_persist(self):
|
||||
self.assertEqual(VmbFeaturePersist.All, 0)
|
||||
self.assertEqual(VmbFeaturePersist.Streamable, 1)
|
||||
self.assertEqual(VmbFeaturePersist.NoLUT, 2)
|
||||
|
||||
def test_enum_vmb_feature_visibility(self):
|
||||
self.assertEqual(VmbFeatureVisibility.Unknown, 0)
|
||||
self.assertEqual(VmbFeatureVisibility.Beginner, 1)
|
||||
self.assertEqual(VmbFeatureVisibility.Expert, 2)
|
||||
self.assertEqual(VmbFeatureVisibility.Guru, 3)
|
||||
self.assertEqual(VmbFeatureVisibility.Invisible, 4)
|
||||
|
||||
def test_enum_vmb_feature_flags(self):
|
||||
self.assertEqual(VmbFeatureFlags.None_, 0)
|
||||
self.assertEqual(VmbFeatureFlags.Read, 1)
|
||||
self.assertEqual(VmbFeatureFlags.Write, 2)
|
||||
self.assertEqual(VmbFeatureFlags.Volatile, 8)
|
||||
self.assertEqual(VmbFeatureFlags.ModifyWrite, 16)
|
||||
|
||||
def test_enum_vmb_frame_status(self):
|
||||
self.assertEqual(VmbFrameStatus.Complete, 0)
|
||||
self.assertEqual(VmbFrameStatus.Incomplete, -1)
|
||||
self.assertEqual(VmbFrameStatus.TooSmall, -2)
|
||||
self.assertEqual(VmbFrameStatus.Invalid, -3)
|
||||
|
||||
def test_enum_vmd_frame_flags(self):
|
||||
self.assertEqual(VmbFrameFlags.None_, 0)
|
||||
self.assertEqual(VmbFrameFlags.Dimension, 1)
|
||||
self.assertEqual(VmbFrameFlags.Offset, 2)
|
||||
self.assertEqual(VmbFrameFlags.FrameID, 4)
|
||||
self.assertEqual(VmbFrameFlags.Timestamp, 8)
|
||||
|
||||
|
||||
class VimbaCTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_call_vimba_c_valid(self):
|
||||
# Expectation for valid call: No exceptions, no errors
|
||||
expected_ver_info = (1, 9, 0)
|
||||
ver_info = VmbVersionInfo()
|
||||
|
||||
call_vimba_c('VmbVersionQuery', byref(ver_info), sizeof(ver_info))
|
||||
|
||||
ver_info = (ver_info.major, ver_info.minor, ver_info.patch)
|
||||
|
||||
# Not an actual check for compatibility. Just make sure a sensible value was filled
|
||||
self.assertGreaterEqual(ver_info, expected_ver_info)
|
||||
|
||||
def test_call_vimba_c_invalid_func_name(self):
|
||||
# Expectation: An invalid function name must throw an AttributeError
|
||||
|
||||
ver_info = VmbVersionInfo()
|
||||
self.assertRaises(AttributeError, call_vimba_c, 'VmbVersionQuer', byref(ver_info),
|
||||
sizeof(ver_info))
|
||||
|
||||
def test_call_vimba_c_invalid_arg_number(self):
|
||||
# Expectation: Invalid number of arguments with sane types.
|
||||
# must lead to TypeErrors
|
||||
|
||||
ver_info = VmbVersionInfo()
|
||||
self.assertRaises(TypeError, call_vimba_c, 'VmbVersionQuery', byref(ver_info))
|
||||
|
||||
def test_call_vimba_c_invalid_arg_type(self):
|
||||
# Expectation: Arguments with invalid types must lead to TypeErrors
|
||||
|
||||
# Call with unexpected base types
|
||||
self.assertRaises(ctypes.ArgumentError, call_vimba_c, 'VmbVersionQuery', 0, 'hi')
|
||||
|
||||
# Call with valid ctypes used wrongly
|
||||
ver_info = VmbVersionInfo()
|
||||
self.assertRaises(ctypes.ArgumentError, call_vimba_c, 'VmbVersionQuery', byref(ver_info),
|
||||
ver_info)
|
||||
|
||||
def test_call_vimba_c_exception(self):
|
||||
# Expectation: Errors returned from the C-Layer must be mapped
|
||||
# to a special Exception Type call VimbaCError. This error must
|
||||
# contain the returned Error Code from the failed C-Call.
|
||||
|
||||
# VmbVersionQuery has two possible Errors (taken from VimbaC.h):
|
||||
# - VmbErrorStructSize: The given struct size is not valid for this version of the API
|
||||
# - VmbErrorBadParameter: If "pVersionInfo" is NULL.
|
||||
|
||||
ver_info = VmbVersionInfo()
|
||||
|
||||
try:
|
||||
call_vimba_c('VmbVersionQuery', byref(ver_info), sizeof(ver_info) - 1)
|
||||
self.fail("Previous call must raise Exception.")
|
||||
|
||||
except VimbaCError as e:
|
||||
self.assertEqual(e.get_error_code(), VmbError.StructSize)
|
||||
|
||||
try:
|
||||
call_vimba_c('VmbVersionQuery', None, sizeof(ver_info))
|
||||
self.fail("Previous call must raise Exception.")
|
||||
|
||||
except VimbaCError as e:
|
||||
self.assertEqual(e.get_error_code(), VmbError.BadParameter)
|
||||
|
||||
|
||||
class ImageTransformTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_call_vimba_image_transform_valid(self):
|
||||
# Expectation for valid call: No exceptions, no errors
|
||||
expected_ver_info = EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION
|
||||
v = VmbUint32()
|
||||
|
||||
call_vimba_image_transform('VmbGetVersion', byref(v))
|
||||
|
||||
ver_info = str(v.value >> 24 & 0xff) + '.' + str(v.value >> 16 & 0xff)
|
||||
|
||||
self.assertEqual(expected_ver_info, ver_info)
|
||||
|
||||
def test_call_vimba_c_invalid_func_name(self):
|
||||
# Expectation: An invalid function name must throw an AttributeError
|
||||
v = VmbUint32()
|
||||
self.assertRaises(AttributeError, call_vimba_image_transform, 'VmbGetVersio', byref(v))
|
||||
|
||||
def test_call_vimba_c_invalid_arg_number(self):
|
||||
# Expectation: Invalid number of arguments with sane types must lead to TypeErrors
|
||||
self.assertRaises(TypeError, call_vimba_image_transform, 'VmbGetVersion')
|
||||
|
||||
def test_call_vimba_c_invalid_arg_type(self):
|
||||
# Expectation: Arguments with invalid types must lead to TypeErrors
|
||||
self.assertRaises(ctypes.ArgumentError, call_vimba_image_transform, 'VmbGetVersion',
|
||||
VmbDouble())
|
||||
self.assertRaises(ctypes.ArgumentError, call_vimba_image_transform, 'VmbGetVersion', 0)
|
||||
self.assertRaises(ctypes.ArgumentError, call_vimba_image_transform, 'VmbGetVersion',
|
||||
'invalid')
|
||||
|
||||
def test_call_vimba_c_exception(self):
|
||||
# Expectation: Failed operations must raise a VimbaCError
|
||||
self.assertRaises(VimbaCError, call_vimba_image_transform, 'VmbGetVersion', None)
|
||||
176
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/interface_test.py
Normal file
176
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/interface_test.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from vimba import *
|
||||
|
||||
|
||||
class InterfaceTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
inters = self.vimba.get_all_interfaces()
|
||||
|
||||
if not inters:
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('No Interface available to test against. Abort.')
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_interface_decode_id(self):
|
||||
# Expectation all interface ids can be decoded in something not ''
|
||||
for i in self.vimba.get_all_interfaces():
|
||||
self.assertNotEqual(i.get_id(), '')
|
||||
|
||||
def test_interface_decode_type(self):
|
||||
# Expectation all interface types be in interface types
|
||||
excpected = (
|
||||
InterfaceType.Firewire,
|
||||
InterfaceType.Ethernet,
|
||||
InterfaceType.Usb,
|
||||
InterfaceType.CL,
|
||||
InterfaceType.CSI2,
|
||||
)
|
||||
|
||||
for i in self.vimba.get_all_interfaces():
|
||||
self.assertIn(i.get_type(), excpected)
|
||||
|
||||
def test_interface_decode_name(self):
|
||||
# Expectation all interface names can be decoded in something not ''
|
||||
for i in self.vimba.get_all_interfaces():
|
||||
self.assertNotEqual(i.get_name(), '')
|
||||
|
||||
def test_interface_decode_serial(self):
|
||||
# Expectation: Serials can be '' on some interfaces. This test success
|
||||
# if get serial does not raise
|
||||
for i in self.vimba.get_all_interfaces():
|
||||
self.assertNoRaise(i.get_serial)
|
||||
|
||||
def test_interface_get_all_features(self):
|
||||
# Expectation: Call get_all_features raises RuntimeError outside of with
|
||||
# Inside of with return a non empty set
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
self.assertNotEqual(inter.get_all_features(), ())
|
||||
|
||||
def test_interface_get_features_affected_by(self):
|
||||
# Expectation: Call get_features_affected_by raises RuntimeError outside of with.
|
||||
# Inside with it must either return and empty set if the given feature has no affected
|
||||
# Feature or a set off affected features
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
try:
|
||||
affects_feats = inter.get_feature_by_name('DeviceUpdateList')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.skipTest('Test requires Feature \'DeviceUpdateList\'.')
|
||||
|
||||
try:
|
||||
not_affects_feats = inter.get_feature_by_name('DeviceCount')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.skipTest('Test requires Feature \'DeviceCount\'.')
|
||||
|
||||
self.assertTrue(affects_feats.has_affected_features())
|
||||
self.assertNotEquals(inter.get_features_affected_by(affects_feats), ())
|
||||
|
||||
self.assertFalse(not_affects_feats.has_affected_features())
|
||||
self.assertEquals(inter.get_features_affected_by(not_affects_feats), ())
|
||||
|
||||
def test_interface_get_features_selected_by(self):
|
||||
# Expectation: Call get_features_selected_by raises RuntimeError outside of with.
|
||||
# Inside with it must either return and empty set if the given feature has no selected
|
||||
# Feature or a set off affected features
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
try:
|
||||
selects_feats = inter.get_feature_by_name('DeviceSelector')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.skipTest('Test requires Feature \'DeviceSelector\'.')
|
||||
|
||||
try:
|
||||
not_selects_feats = inter.get_feature_by_name('DeviceCount')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.skipTest('Test requires Feature \'DeviceCount\'.')
|
||||
|
||||
self.assertTrue(selects_feats.has_selected_features())
|
||||
self.assertNotEquals(inter.get_features_selected_by(selects_feats), ())
|
||||
|
||||
self.assertFalse(not_selects_feats.has_selected_features())
|
||||
self.assertEquals(inter.get_features_selected_by(not_selects_feats), ())
|
||||
|
||||
def test_interface_get_features_by_type(self):
|
||||
# Expectation: Call get_features_by_type raises RuntimeError outside of with
|
||||
# Inside of with return a non empty set for IntFeature (DeviceCount is IntFeature)
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
self.assertNotEqual(inter.get_features_by_type(IntFeature), ())
|
||||
|
||||
def test_interface_get_features_by_category(self):
|
||||
# Expectation: Call get_features_by_category raises RuntimeError outside of with
|
||||
# Inside of with return a non empty set for /DeviceEnumeration)
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
self.assertNotEqual(inter.get_features_by_category('/DeviceEnumeration'), ())
|
||||
|
||||
def test_interface_get_feature_by_name(self):
|
||||
# Expectation: Call get_feature_by_name raises RuntimeError outside of with
|
||||
# Inside of with return dont raise VimbaFeatureError for 'DeviceCount'
|
||||
# A invalid name must raise VimbaFeatureError
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
self.assertNoRaise(inter.get_feature_by_name, 'DeviceCount')
|
||||
self.assertRaises(VimbaFeatureError, inter.get_feature_by_name, 'Invalid Name')
|
||||
|
||||
def test_interface_context_manager_reentrancy(self):
|
||||
# Expectation: Implemented Context Manager must be reentrant, not causing
|
||||
# multiple interface openings (would cause C-Errors)
|
||||
with self.vimba.get_all_interfaces()[0] as inter:
|
||||
with inter:
|
||||
with inter:
|
||||
pass
|
||||
|
||||
def test_interface_api_context_sensitivity_inside_context(self):
|
||||
# Expectation: Interface has functions that shall only be callable inside the Context,
|
||||
# calling outside must cause a runtime error. This test check only if the RuntimeErrors
|
||||
# are triggered then called Outside of the with block.
|
||||
inter = self.vimba.get_all_interfaces()[0]
|
||||
|
||||
self.assertRaises(RuntimeError, inter.read_memory, 0, 0)
|
||||
self.assertRaises(RuntimeError, inter.write_memory, 0, b'foo')
|
||||
self.assertRaises(RuntimeError, inter.read_registers, ())
|
||||
self.assertRaises(RuntimeError, inter.write_registers, {0: 0})
|
||||
self.assertRaises(RuntimeError, inter.get_all_features)
|
||||
|
||||
# Enter scope to get handle on Features as valid parameters for the test:
|
||||
# Don't to this in production code because the features will be invalid if used.
|
||||
with inter:
|
||||
feat = inter.get_all_features()[0]
|
||||
|
||||
self.assertRaises(RuntimeError, inter.get_features_affected_by, feat)
|
||||
self.assertRaises(RuntimeError, inter.get_features_selected_by, feat)
|
||||
self.assertRaises(RuntimeError, inter.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, inter.get_features_by_category, 'foo')
|
||||
self.assertRaises(RuntimeError, inter.get_feature_by_name, 'foo')
|
||||
@@ -0,0 +1,84 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from vimba.util import *
|
||||
|
||||
|
||||
class TestObj:
|
||||
@LeaveContextOnCall()
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@EnterContextOnCall()
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
@LeaveContextOnCall()
|
||||
def __exit__(self, _1, _2, _3):
|
||||
pass
|
||||
|
||||
@RaiseIfOutsideContext()
|
||||
def works_inside_context(self):
|
||||
pass
|
||||
|
||||
@RaiseIfInsideContext()
|
||||
def works_outside_context(self):
|
||||
pass
|
||||
|
||||
|
||||
class ContextDecoratorTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.test_obj = TestObj()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_raise_if_inside_context(self):
|
||||
# Expectation: a decorated method must raise a RuntimeError if a
|
||||
# Decorated function is called within a with - statement and
|
||||
# run properly outside of the context.
|
||||
|
||||
self.assertNoRaise(self.test_obj.works_outside_context)
|
||||
|
||||
with self.test_obj:
|
||||
self.assertRaises(RuntimeError, self.test_obj.works_outside_context)
|
||||
|
||||
self.assertNoRaise(self.test_obj.works_outside_context)
|
||||
|
||||
def test_raise_if_outside_context(self):
|
||||
# Expectation: a decorated method must raise a RuntimeError if a
|
||||
# Decorated function is called outside a with - statement and
|
||||
# run properly inside of the context.
|
||||
|
||||
self.assertRaises(RuntimeError, self.test_obj.works_inside_context)
|
||||
|
||||
with self.test_obj:
|
||||
self.assertNoRaise(self.test_obj.works_inside_context)
|
||||
|
||||
self.assertRaises(RuntimeError, self.test_obj.works_inside_context)
|
||||
@@ -0,0 +1,256 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from typing import Union, Optional, Tuple, Callable, Dict, Type
|
||||
from vimba.util import *
|
||||
|
||||
|
||||
class RuntimeTypeCheckTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_func_mixed_args_kwargs_and_defaults(self):
|
||||
# Expectation: The typecheck must be able to deal with a valid mixture of args, kwargs
|
||||
# and default values.
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def test_func(a: int, b: str, c: float = 11.0 / 7.0):
|
||||
pass
|
||||
|
||||
self.assertNoRaise(test_func, 1, '2', 0.0)
|
||||
self.assertNoRaise(test_func, c=0.0, b='str', a=1)
|
||||
self.assertNoRaise(test_func, 1, c=0.0, b='str')
|
||||
self.assertNoRaise(test_func, 1, b='str')
|
||||
self.assertNoRaise(test_func, 1, 'str')
|
||||
|
||||
self.assertRaises(TypeError, test_func, c=0.0, b='str', a=0.0)
|
||||
self.assertRaises(TypeError, test_func, c='invalid type', b='str', a=0.0)
|
||||
|
||||
def test_func_no_hints(self):
|
||||
# Expectation: Functions without type hints
|
||||
# should not throw any type errors
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def test_func(arg1, arg2):
|
||||
return str()
|
||||
|
||||
self.assertNoRaise(test_func, 'str', 0)
|
||||
|
||||
def test_func_some_hints(self):
|
||||
# Expectation: Type checks are only enforced on Arguments with hint.
|
||||
# Argument without hints should be accepted
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def test_func(arg1, arg2: int):
|
||||
return str()
|
||||
|
||||
self.assertNoRaise(test_func, 'str', 0)
|
||||
self.assertNoRaise(test_func, 0.5, 0)
|
||||
self.assertRaises(TypeError, test_func, 'str', 0.0)
|
||||
|
||||
def test_object(self):
|
||||
# Expectation: The runtime checker must work on Objects just as on
|
||||
# functions.
|
||||
|
||||
class TestObject:
|
||||
@RuntimeTypeCheckEnable()
|
||||
def __init__(self, arg1: str, arg2: int):
|
||||
pass
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def __call__(self, arg: str) -> str:
|
||||
return arg
|
||||
|
||||
# Invalid construction
|
||||
self.assertRaises(TypeError, TestObject, 0.0, 0)
|
||||
|
||||
obj = TestObject('str', 0)
|
||||
self.assertNoRaise(obj, 'arg')
|
||||
|
||||
self.assertRaises(TypeError, obj, 0.0)
|
||||
|
||||
def test_type(self):
|
||||
# Expectation: types as parameters must be detected like any other values.
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Type[int]):
|
||||
pass
|
||||
|
||||
self.assertNoRaise(func, int)
|
||||
self.assertRaises(TypeError, func, str)
|
||||
self.assertRaises(TypeError, func, 0)
|
||||
|
||||
def test_union(self):
|
||||
# Expectation: int and string are valid parameters. Everything else must throw
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Union[int, str]) -> Union[int, str]:
|
||||
return arg
|
||||
|
||||
self.assertNoRaise(func, 0)
|
||||
self.assertNoRaise(func, 'str')
|
||||
self.assertRaises(TypeError, func, 0.0)
|
||||
|
||||
def test_optional(self):
|
||||
# Expectation: For optionals the check must accept the given type or None.
|
||||
# Anything else must lead to an TypeError
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Optional[int]) -> Optional[str]:
|
||||
return str(arg)
|
||||
|
||||
self.assertNoRaise(func, 0)
|
||||
self.assertNoRaise(func, None)
|
||||
self.assertRaises(TypeError, func, 'str')
|
||||
|
||||
def test_tuple(self):
|
||||
# Expectation: Fixed size tuples checking must verify that size and type order is
|
||||
# enforced.
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Tuple[int, str, float]) -> Tuple[float, int, str]:
|
||||
i, s, f = arg
|
||||
return (f, i, s)
|
||||
|
||||
self.assertNoRaise(func, (1, 'str', 0.1))
|
||||
|
||||
self.assertRaises(TypeError, func, (1, 'str'))
|
||||
self.assertRaises(TypeError, func, (1, 'str', 0.0, 'extra'))
|
||||
self.assertRaises(TypeError, func, ('str1', 'str', 0.0))
|
||||
|
||||
def test_tuple_var_length(self):
|
||||
# Expectation: Var length tuples checking must verify that contained type is enforced.
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Tuple[int, ...]) -> Tuple[str, ...]:
|
||||
return tuple([str(i) for i in arg])
|
||||
|
||||
self.assertNoRaise(func, ())
|
||||
self.assertNoRaise(func, (1,))
|
||||
self.assertNoRaise(func, (1, 2, 3, 4, 5, 6))
|
||||
self.assertRaises(TypeError, func, ('str', ))
|
||||
self.assertRaises(TypeError, func, (1, 'str'))
|
||||
|
||||
def test_tuple_empty(self):
|
||||
# Empty Tuples must satisfy the requirements to Tuple types as argument and results
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Tuple[int, ...]) -> Tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
self.assertNoRaise(func, ())
|
||||
self.assertEqual(func(()), ())
|
||||
|
||||
def test_tuple_union(self):
|
||||
# Tuples of union types must be detected correctly
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Tuple[Union[int, str], ...]):
|
||||
return arg
|
||||
|
||||
self.assertNoRaise(func, (0,))
|
||||
self.assertNoRaise(func, ('1',))
|
||||
self.assertNoRaise(func, (2, 3))
|
||||
self.assertNoRaise(func, ('4', '5'))
|
||||
self.assertNoRaise(func, (6, '7'))
|
||||
self.assertNoRaise(func, ('8', 9))
|
||||
self.assertRaises(TypeError, func, (2, 0.0))
|
||||
|
||||
def test_dict(self):
|
||||
# Expectation: Dictionaries must be detected correctly.
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(arg: Dict[int, str]):
|
||||
pass
|
||||
|
||||
self.assertNoRaise(func, {0: 'ok'})
|
||||
self.assertRaises(TypeError, func, None)
|
||||
self.assertRaises(TypeError, func, 0)
|
||||
self.assertRaises(TypeError, func, 'No Dict')
|
||||
self.assertRaises(TypeError, func, {0.0: 'Err'})
|
||||
self.assertRaises(TypeError, func, {0: b'bytes'})
|
||||
|
||||
def test_callable_no_func(self):
|
||||
# Expectation: The Callable verification shall fail if given Parameter is no callable.
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(fn: Callable[[], None]):
|
||||
fn()
|
||||
|
||||
self.assertRaises(TypeError, func, 'no_callable')
|
||||
|
||||
def test_callable_func(self):
|
||||
# Expectation: A Callable without any hints must comply as long as the number of parameters
|
||||
# matches to given hints. The Return Type doesn't matter if not given.
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(fn: Callable[[str, float], int], arg1: str, arg2: float) -> int:
|
||||
return fn(arg1, arg2)
|
||||
|
||||
def ok(arg1, arg2):
|
||||
return 0.0
|
||||
|
||||
def err1(arg1):
|
||||
return 'str'
|
||||
|
||||
def err2(arg1, arg2, arg3):
|
||||
return 23
|
||||
|
||||
self.assertNoRaise(func, ok, 'str', 0.0)
|
||||
self.assertRaises(TypeError, func, err1, 'str', 0.0)
|
||||
self.assertRaises(TypeError, func, err2, 'str', 0.0)
|
||||
|
||||
def test_callable_obj(self):
|
||||
# Expectation: A Object that is callable must pass the runtime check
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(fn: Callable[[str], None], arg: str) -> str:
|
||||
return fn(arg)
|
||||
|
||||
class Ok:
|
||||
def __call__(self, arg: str) -> str:
|
||||
return str
|
||||
|
||||
class Err1:
|
||||
def __call__(self) -> str:
|
||||
return 'Err1'
|
||||
|
||||
class Err2:
|
||||
def __call__(self, arg1: str, arg2: str) -> str:
|
||||
return arg1 + arg2
|
||||
|
||||
self.assertNoRaise(func, Ok(), 'str')
|
||||
self.assertRaises(TypeError, func, Err1(), 'str')
|
||||
self.assertRaises(TypeError, func, Err2(), 'str')
|
||||
|
||||
def test_callable_lambda(self):
|
||||
# Expectation: RuntimeTypeCheck must behave with lambas as with functions
|
||||
|
||||
@RuntimeTypeCheckEnable()
|
||||
def func(fn: Callable[[str, float], int], arg1: str, arg2: float) -> int:
|
||||
return fn(arg1, arg2)
|
||||
|
||||
self.assertNoRaise(func, lambda a1, a2: 0.0, 'str', 0.0)
|
||||
self.assertRaises(TypeError, func, lambda a1: 'foo', 'str', 0.0)
|
||||
self.assertRaises(TypeError, func, lambda a1, a2, a3: 23, 'str', 0.0)
|
||||
@@ -0,0 +1,157 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from vimba.util import *
|
||||
|
||||
|
||||
class TracerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Enable logging and setup hidden buffer
|
||||
self.log = Log.get_instance()
|
||||
self.log._test_buffer = []
|
||||
|
||||
self.log.enable(LOG_CONFIG_CRITICAL_CONSOLE_ONLY)
|
||||
|
||||
def tearDown(self):
|
||||
# Disable logging and clear hidden buffer
|
||||
self.log.disable()
|
||||
|
||||
self.log._test_buffer = None
|
||||
|
||||
def test_trace_inactive(self):
|
||||
# Expectation: A disabled log must not contain any trace entries.
|
||||
|
||||
@TraceEnable()
|
||||
def test_func(arg):
|
||||
return str(arg)
|
||||
|
||||
self.log.disable()
|
||||
|
||||
self.assertEqual(test_func(1), '1')
|
||||
self.assertFalse(self.log._test_buffer)
|
||||
|
||||
self.assertEqual(test_func('test'), 'test')
|
||||
self.assertFalse(self.log._test_buffer)
|
||||
|
||||
self.assertEqual(test_func(2.0), '2.0')
|
||||
self.assertFalse(self.log._test_buffer)
|
||||
|
||||
def test_trace_normal_exit(self):
|
||||
# Expectation: Must not throw on call normal func.
|
||||
# Each call traced call must add two Log entries:
|
||||
|
||||
@TraceEnable()
|
||||
def test_func(arg):
|
||||
return str(arg)
|
||||
|
||||
self.assertEqual(test_func(1), '1')
|
||||
self.assertEqual(len(self.log._test_buffer), 2)
|
||||
|
||||
self.assertEqual(test_func('test'), 'test')
|
||||
self.assertEqual(len(self.log._test_buffer), 4)
|
||||
|
||||
self.assertEqual(test_func(2.0), '2.0')
|
||||
self.assertEqual(len(self.log._test_buffer), 6)
|
||||
|
||||
def test_trace_raised_exit(self):
|
||||
# Expectation: Throws internally thrown exception and adds two log entries
|
||||
# Each call traced call must add two Log entries:
|
||||
|
||||
@TraceEnable()
|
||||
def test_func(arg):
|
||||
raise TypeError('my error')
|
||||
|
||||
self.assertRaises(TypeError, test_func, 1)
|
||||
self.assertEqual(len(self.log._test_buffer), 2)
|
||||
|
||||
self.assertRaises(TypeError, test_func, 'test')
|
||||
self.assertEqual(len(self.log._test_buffer), 4)
|
||||
|
||||
self.assertRaises(TypeError, test_func, 2.0)
|
||||
self.assertEqual(len(self.log._test_buffer), 6)
|
||||
|
||||
def test_trace_function(self):
|
||||
# Expectation: Normal functions must be traceable
|
||||
@TraceEnable()
|
||||
def test_func():
|
||||
pass
|
||||
|
||||
test_func()
|
||||
self.assertEqual(len(self.log._test_buffer), 2)
|
||||
|
||||
test_func()
|
||||
self.assertEqual(len(self.log._test_buffer), 4)
|
||||
|
||||
test_func()
|
||||
self.assertEqual(len(self.log._test_buffer), 6)
|
||||
|
||||
def test_trace_lambda(self):
|
||||
# Expectation: Lambdas must be traceable
|
||||
|
||||
test_lambda = TraceEnable()(lambda: 0)
|
||||
|
||||
test_lambda()
|
||||
self.assertEqual(len(self.log._test_buffer), 2)
|
||||
|
||||
test_lambda()
|
||||
self.assertEqual(len(self.log._test_buffer), 4)
|
||||
|
||||
test_lambda()
|
||||
self.assertEqual(len(self.log._test_buffer), 6)
|
||||
|
||||
def test_trace_object(self):
|
||||
# Expectation: Objects must be traceable including constructors.
|
||||
class TestObj:
|
||||
@TraceEnable()
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
||||
|
||||
@TraceEnable()
|
||||
def __str__(self):
|
||||
return 'TestObj({})'.format(str(self.arg))
|
||||
|
||||
@TraceEnable()
|
||||
def __repr__(self):
|
||||
return 'TestObj({})'.format(repr(self.arg))
|
||||
|
||||
@TraceEnable()
|
||||
def __call__(self):
|
||||
pass
|
||||
|
||||
test_obj = TestObj('test')
|
||||
self.assertEqual(len(self.log._test_buffer), 2)
|
||||
|
||||
str(test_obj)
|
||||
self.assertEqual(len(self.log._test_buffer), 4)
|
||||
|
||||
repr(test_obj)
|
||||
self.assertEqual(len(self.log._test_buffer), 6)
|
||||
|
||||
test_obj()
|
||||
self.assertEqual(len(self.log._test_buffer), 8)
|
||||
@@ -0,0 +1,89 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from vimba.c_binding import _select_vimba_home
|
||||
from vimba.error import VimbaSystemError
|
||||
|
||||
|
||||
class RankVimbaHomeCandidatesTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_empty_gentl_path(self):
|
||||
candidates = []
|
||||
with self.assertRaises(VimbaSystemError):
|
||||
_select_vimba_home(candidates)
|
||||
|
||||
def test_empty_string(self):
|
||||
candidates = ['']
|
||||
with self.assertRaises(VimbaSystemError):
|
||||
_select_vimba_home(candidates)
|
||||
|
||||
def test_single_bad_vimba_home_candidate(self):
|
||||
candidates = ['/some/path']
|
||||
with self.assertRaises(VimbaSystemError):
|
||||
_select_vimba_home(candidates)
|
||||
|
||||
def test_single_good_vimba_home_candidate(self):
|
||||
candidates = ['/opt/Vimba_3_1']
|
||||
expected = '/opt/Vimba_3_1'
|
||||
self.assertEquals(expected, _select_vimba_home(candidates))
|
||||
|
||||
def test_presorted_vimba_home_candidates(self):
|
||||
candidates = ['/home/username/Vimba_4_0', '/opt/some/other/gentl/provider']
|
||||
expected = '/home/username/Vimba_4_0'
|
||||
self.assertEqual(expected, _select_vimba_home(candidates))
|
||||
|
||||
def test_unsorted_vimba_home_candidates(self):
|
||||
candidates = ['/opt/some/other/gentl/provider', '/home/username/Vimba_4_0']
|
||||
expected = '/home/username/Vimba_4_0'
|
||||
self.assertEqual(expected, _select_vimba_home(candidates))
|
||||
|
||||
def test_many_vimba_home_candidates(self):
|
||||
candidates = ['/some/random/path',
|
||||
'/opt/some/gentl/provider',
|
||||
'/opt/Vimba_4_0', # This should be selected
|
||||
'/opt/another/gentl/provider',
|
||||
'/another/incorrect/path']
|
||||
expected = '/opt/Vimba_4_0'
|
||||
self.assertEqual(expected, _select_vimba_home(candidates))
|
||||
|
||||
def test_multiple_vimba_home_directories(self):
|
||||
# If multiple VIMBA_HOME directories are found an error should be raised
|
||||
candidates = ['/some/random/path',
|
||||
'/opt/some/gentl/provider',
|
||||
'/opt/Vimba_4_0', # first installation
|
||||
'/home/username/Vimba_4_0', # second installation
|
||||
'/opt/another/gentl/provider',
|
||||
'/another/incorrect/path']
|
||||
with self.assertRaises(VimbaSystemError):
|
||||
_select_vimba_home(candidates)
|
||||
126
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/vimba_test.py
Normal file
126
Vimba_6_0/VimbaPython/Source/Tests/basic_tests/vimba_test.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from vimba import *
|
||||
|
||||
|
||||
class VimbaTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_singleton(self):
|
||||
# Expected behavior: Multiple calls to Vimba.get_instance() return the same object.
|
||||
self.assertEqual(self.vimba, Vimba.get_instance())
|
||||
|
||||
def test_get_version(self):
|
||||
# Expectation: Returned Version is not empty and does not raise any exceptions.
|
||||
self.assertNotEqual(self.vimba.get_version(), "")
|
||||
|
||||
def test_get_camera_by_id_failure(self):
|
||||
# Expected behavior: Lookup of a currently unavailable camera must throw an
|
||||
# VimbaCameraError
|
||||
with self.vimba:
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, 'Invalid ID')
|
||||
|
||||
def test_get_interface_by_id_failure(self):
|
||||
# Expected behavior: Lookup of a currently unavailable interface must throw an
|
||||
# VimbaInterfaceError
|
||||
with self.vimba:
|
||||
self.assertRaises(VimbaInterfaceError, self.vimba.get_interface_by_id, 'Invalid ID')
|
||||
|
||||
def test_get_feature_by_name_failure(self):
|
||||
# Expected behavior: Lookup of a currently unavailable feature must throw an
|
||||
# VimbaFeatureError
|
||||
with self.vimba:
|
||||
self.assertRaises(VimbaFeatureError, self.vimba.get_feature_by_name, 'Invalid ID')
|
||||
|
||||
def test_runtime_check_failure(self):
|
||||
self.assertRaises(TypeError, self.vimba.set_network_discovery, 0.0)
|
||||
|
||||
with self.vimba:
|
||||
# All functions with RuntimeTypeCheckEnable must return a TypeError on Failure
|
||||
self.assertRaises(TypeError, self.vimba.get_camera_by_id, 0)
|
||||
self.assertRaises(TypeError, self.vimba.get_interface_by_id, 1)
|
||||
self.assertRaises(TypeError, self.vimba.get_feature_by_name, 0)
|
||||
self.assertRaises(TypeError, self.vimba.enable_log, '-1')
|
||||
|
||||
self.assertRaises(TypeError, self.vimba.get_features_affected_by, '-1')
|
||||
self.assertRaises(TypeError, self.vimba.get_features_selected_by, '-1')
|
||||
self.assertRaises(TypeError, self.vimba.get_features_by_type, [])
|
||||
self.assertRaises(TypeError, self.vimba.register_camera_change_handler, 0)
|
||||
self.assertRaises(TypeError, self.vimba.unregister_camera_change_handler, 0)
|
||||
self.assertRaises(TypeError, self.vimba.register_interface_change_handler, 0)
|
||||
self.assertRaises(TypeError, self.vimba.unregister_interface_change_handler, 0)
|
||||
|
||||
def test_vimba_context_manager_reentrancy(self):
|
||||
# Expectation: Implemented Context Manager must be reentrant, not causing
|
||||
# multiple starts of the Vimba API (would cause C-Errors)
|
||||
|
||||
with self.vimba:
|
||||
with self.vimba:
|
||||
with self.vimba:
|
||||
pass
|
||||
|
||||
def test_vimba_api_context_sensitity_outside_context(self):
|
||||
# Expectation: Vimba has functions that shall only be callable outside the Context and
|
||||
# calling within the context must cause a runtime error.
|
||||
|
||||
self.assertNoRaise(self.vimba.set_network_discovery, True)
|
||||
|
||||
with self.vimba:
|
||||
self.assertRaises(RuntimeError, self.vimba.set_network_discovery, True)
|
||||
|
||||
self.assertNoRaise(self.vimba.set_network_discovery, True)
|
||||
|
||||
def test_vimba_api_context_sensitity_inside_context(self):
|
||||
# Expectation: Vimba has functions that shall only be callable inside the Context and
|
||||
# calling outside must cause a runtime error. This test check only if the RuntimeErrors
|
||||
# are triggered then called Outside of the with block.
|
||||
self.assertRaises(RuntimeError, self.vimba.read_memory, 0, 0)
|
||||
self.assertRaises(RuntimeError, self.vimba.write_memory, 0, b'foo')
|
||||
self.assertRaises(RuntimeError, self.vimba.read_registers, ())
|
||||
self.assertRaises(RuntimeError, self.vimba.write_registers, {0: 0})
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_interface_by_id, 'id')
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_camera_by_id, 'id')
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_features)
|
||||
|
||||
# Enter scope to get handle on Features as valid parameters for the test:
|
||||
# Don't to this in production code because the feature will be invalid if use.
|
||||
with self.vimba:
|
||||
feat = self.vimba.get_all_features()[0]
|
||||
|
||||
self.assertRaises(RuntimeError, self.vimba.get_features_affected_by, feat)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_features_selected_by, feat)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_features_by_category, 'foo')
|
||||
self.assertRaises(RuntimeError, self.vimba.get_feature_by_name, 'foo')
|
||||
@@ -0,0 +1,155 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from vimba import *
|
||||
|
||||
|
||||
class CamAncillaryDataTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.chunk_mode = self.cam.get_feature_by_name('ChunkModeActive')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ChunkModeActive\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_ancillary_data_access(self):
|
||||
# Expectation: Ancillary Data is None if ChunkMode is disable.
|
||||
# If ChunkMode is enabled Ancillary Data shall not be None.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
# Disable ChunkMode, acquire frame: Ancillary Data must be None
|
||||
self.chunk_mode.set(False)
|
||||
self.assertIsNone(self.cam.get_frame().get_ancillary_data())
|
||||
|
||||
# Enable ChunkMode, acquire frame: Ancillary Data must not be None
|
||||
self.chunk_mode.set(True)
|
||||
self.assertIsNotNone(self.cam.get_frame().get_ancillary_data())
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_context_manager_reentrancy(self):
|
||||
# Expectation: Ancillary Data Context Manager must be reentrant.
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
with anc_data:
|
||||
with anc_data:
|
||||
with anc_data:
|
||||
pass
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_api_context_sensitity(self):
|
||||
# Expectation: Ancillary Data implements a Context Manager, outside of with-scope
|
||||
# a runtime error should be raised on all feature related methods accessed outside of the
|
||||
# context.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
# Check Access Outside Context
|
||||
self.assertRaises(RuntimeError, anc_data.get_all_features)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertRaises(RuntimeError, anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
with anc_data:
|
||||
# Check Access after Context entry
|
||||
self.assertNoRaise(anc_data.get_all_features)
|
||||
self.assertNoRaise(anc_data.get_features_by_type, IntFeature)
|
||||
self.assertNoRaise(anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertNoRaise(anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
# Check Access after Context leaving
|
||||
self.assertRaises(RuntimeError, anc_data.get_all_features)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertRaises(RuntimeError, anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_removed_attrs(self):
|
||||
# Expectation: Ancillary Data are lightweight features. Calling most Feature-Methods that
|
||||
# call VimbaC Features would cause an internal error. Those error prone methods
|
||||
# shall raise a RuntimeError on call.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
with anc_data:
|
||||
for feat in anc_data.get_all_features():
|
||||
self.assertRaises(RuntimeError, feat.get_access_mode)
|
||||
self.assertRaises(RuntimeError, feat.is_readable)
|
||||
self.assertRaises(RuntimeError, feat.is_writeable)
|
||||
self.assertRaises(RuntimeError, feat.register_change_handler)
|
||||
self.assertRaises(RuntimeError, feat.get_range)
|
||||
self.assertRaises(RuntimeError, feat.get_increment)
|
||||
self.assertRaises(RuntimeError, feat.set)
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
422
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/camera_test.py
Normal file
422
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/camera_test.py
Normal file
@@ -0,0 +1,422 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import threading
|
||||
import os
|
||||
|
||||
from vimba import *
|
||||
from vimba.frame import *
|
||||
|
||||
|
||||
def dummy_frame_handler(cam: Camera, frame: Frame):
|
||||
pass
|
||||
|
||||
|
||||
class CamCameraTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
|
||||
def tearDown(self):
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_camera_context_manager_access_mode(self):
|
||||
# Expectation: Entering Context must not throw in cases where the current access mode is
|
||||
# within get_permitted_access_modes()
|
||||
|
||||
permitted_modes = self.cam.get_permitted_access_modes()
|
||||
|
||||
for mode in permitted_modes:
|
||||
self.cam.set_access_mode(mode)
|
||||
|
||||
try:
|
||||
with self.cam:
|
||||
pass
|
||||
|
||||
except BaseException:
|
||||
self.fail()
|
||||
|
||||
def test_camera_context_manager_feature_discovery(self):
|
||||
# Expectation: Outside of context, all features must be cleared,
|
||||
# inside of context all features must be detected.
|
||||
with self.cam:
|
||||
self.assertNotEqual(self.cam.get_all_features(), ())
|
||||
|
||||
def test_camera_access_mode(self):
|
||||
# Expectation: set/get access mode
|
||||
self.cam.set_access_mode(AccessMode.None_)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.None_)
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.Full)
|
||||
self.cam.set_access_mode(AccessMode.Read)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.Read)
|
||||
|
||||
def test_camera_get_id(self):
|
||||
# Expectation: get decoded camera id
|
||||
self.assertTrue(self.cam.get_id())
|
||||
|
||||
def test_camera_get_name(self):
|
||||
# Expectation: get decoded camera name
|
||||
self.assertTrue(self.cam.get_name())
|
||||
|
||||
def test_camera_get_model(self):
|
||||
# Expectation: get decoded camera model
|
||||
self.assertTrue(self.cam.get_model())
|
||||
|
||||
def test_camera_get_serial(self):
|
||||
# Expectation: get decoded camera serial
|
||||
self.assertTrue(self.cam.get_serial())
|
||||
|
||||
def test_camera_get_permitted_access_modes(self):
|
||||
# Expectation: get currently permitted access modes
|
||||
expected = (AccessMode.None_, AccessMode.Full, AccessMode.Read, AccessMode.Config)
|
||||
|
||||
for mode in self.cam.get_permitted_access_modes():
|
||||
self.assertIn(mode, expected)
|
||||
|
||||
def test_camera_get_interface_id(self):
|
||||
# Expectation: get interface Id this camera is connected to
|
||||
self.assertTrue(self.cam.get_interface_id())
|
||||
|
||||
def test_camera_get_features_affected(self):
|
||||
# Expectation: Features that affect other features shall return a set of affected feature
|
||||
# Features that don't affect other features shall return (). If a Feature is supplied that
|
||||
# is not associated with that camera, a TypeError must be raised.
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
affect = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature Height') from e
|
||||
|
||||
try:
|
||||
not_affect = self.cam.get_feature_by_name('AcquisitionFrameCount')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature AcquisitionFrameCount') from e
|
||||
|
||||
self.assertEqual(self.cam.get_features_affected_by(not_affect), ())
|
||||
|
||||
try:
|
||||
payload_size = self.cam.get_feature_by_name('PayloadSize')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature PayloadSize') from e
|
||||
|
||||
self.assertIn(payload_size, self.cam.get_features_affected_by(affect))
|
||||
|
||||
def test_camera_frame_generator_limit_set(self):
|
||||
# Expectation: The Frame generator fetches the given number of images.
|
||||
with self.cam:
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(0)]), 0)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(1)]), 1)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(7)]), 7)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(11)]), 11)
|
||||
|
||||
def test_camera_frame_generator_error(self):
|
||||
# Expectation: The Frame generator raises a ValueError on a
|
||||
# negative limit and the camera raises an ValueError
|
||||
# if the camera is not opened.
|
||||
|
||||
# generator execution must throw if streaming is enabled
|
||||
with self.cam:
|
||||
# Check limits
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, -1)
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, 1, 0)
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, 1, -1)
|
||||
|
||||
self.cam.start_streaming(dummy_frame_handler, 5)
|
||||
|
||||
self.assertRaises(VimbaCameraError, self.cam.get_frame)
|
||||
self.assertRaises(VimbaCameraError, next, self.cam.get_frame_generator(1))
|
||||
|
||||
# Stop Streaming: Everything should be fine.
|
||||
self.cam.stop_streaming()
|
||||
self.assertNoRaise(self.cam.get_frame)
|
||||
self.assertNoRaise(next, self.cam.get_frame_generator(1))
|
||||
|
||||
def test_camera_get_frame(self):
|
||||
# Expectation: Gets single Frame without any exception. Image data must be set.
|
||||
# If a zero or negative timeouts must lead to a ValueError.
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.get_frame, 0)
|
||||
self.assertRaises(ValueError, self.cam.get_frame, -1)
|
||||
|
||||
self.assertNoRaise(self.cam.get_frame)
|
||||
self.assertEqual(type(self.cam.get_frame()), Frame)
|
||||
|
||||
def test_camera_capture_error_outside_vimba_scope(self):
|
||||
# Expectation: Camera access outside of Vimba scope must lead to a RuntimeError
|
||||
gener = None
|
||||
|
||||
with self.cam:
|
||||
gener = self.cam.get_frame_generator(1)
|
||||
|
||||
# Shutdown API
|
||||
self.vimba._shutdown()
|
||||
|
||||
# Access invalid Iterator
|
||||
self.assertRaises(RuntimeError, next, gener)
|
||||
|
||||
def test_camera_capture_error_outside_camera_scope(self):
|
||||
# Expectation: Camera access outside of Camera scope must lead to a RuntimeError
|
||||
gener = None
|
||||
|
||||
with self.cam:
|
||||
gener = self.cam.get_frame_generator(1)
|
||||
|
||||
self.assertRaises(RuntimeError, next, gener)
|
||||
|
||||
def test_camera_capture_timeout(self):
|
||||
# Expectation: Camera access outside of Camera scope must lead to a VimbaTimeout
|
||||
with self.cam:
|
||||
self.assertRaises(VimbaTimeout, self.cam.get_frame, 1)
|
||||
|
||||
def test_camera_is_streaming(self):
|
||||
# Expectation: After start_streaming() is_streaming() must return true. After stop it must
|
||||
# return false. If the camera context is left without stop_streaming(), leaving
|
||||
# the context must stop streaming.
|
||||
|
||||
# Normal Operation
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
with self.cam:
|
||||
self.cam.start_streaming(dummy_frame_handler)
|
||||
self.assertEqual(self.cam.is_streaming(), True)
|
||||
|
||||
self.cam.stop_streaming()
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
|
||||
# Missing the stream stop. Close must stop streaming
|
||||
with self.cam:
|
||||
self.cam.start_streaming(dummy_frame_handler, 5)
|
||||
self.assertEqual(self.cam.is_streaming(), True)
|
||||
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
|
||||
def test_camera_streaming_error_frame_count(self):
|
||||
# Expectation: A negative or zero frame_count must lead to an value error
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.start_streaming, dummy_frame_handler, 0)
|
||||
self.assertRaises(ValueError, self.cam.start_streaming, dummy_frame_handler, -1)
|
||||
|
||||
def test_camera_streaming(self):
|
||||
# Expectation: A given frame_handler must be executed for each buffered frame.
|
||||
|
||||
class FrameHandler:
|
||||
def __init__(self, frame_count):
|
||||
self.cnt = 0
|
||||
self.frame_count = frame_count
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, cam: Camera, frame: Frame):
|
||||
self.cnt += 1
|
||||
|
||||
if self.cnt == self.frame_count:
|
||||
self.event.set()
|
||||
|
||||
timeout = 5.0
|
||||
frame_count = 10
|
||||
handler = FrameHandler(frame_count)
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
self.cam.start_streaming(handler, frame_count)
|
||||
|
||||
# Wait until the FrameHandler has been executed for each queued frame
|
||||
self.assertTrue(handler.event.wait(timeout))
|
||||
|
||||
finally:
|
||||
self.cam.stop_streaming()
|
||||
|
||||
def test_camera_streaming_queue(self):
|
||||
# Expectation: A given frame must be reused if it is enqueued again.
|
||||
|
||||
class FrameHandler:
|
||||
def __init__(self, frame_count):
|
||||
self.cnt = 0
|
||||
self.frame_count = frame_count
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, cam: Camera, frame: Frame):
|
||||
self.cnt += 1
|
||||
|
||||
if self.cnt == self.frame_count:
|
||||
self.event.set()
|
||||
|
||||
cam.queue_frame(frame)
|
||||
|
||||
timeout = 5.0
|
||||
frame_count = 5
|
||||
frame_reuse = 2
|
||||
handler = FrameHandler(frame_count * frame_reuse)
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
self.cam.start_streaming(handler, frame_count)
|
||||
|
||||
# Wait until the FrameHandler has been executed for each queued frame
|
||||
self.assertTrue(handler.event.wait(timeout))
|
||||
|
||||
finally:
|
||||
self.cam.stop_streaming()
|
||||
|
||||
def test_camera_runtime_type_check(self):
|
||||
def valid_handler(cam, frame):
|
||||
pass
|
||||
|
||||
def invalid_handler_1(cam):
|
||||
pass
|
||||
|
||||
def invalid_handler_2(cam, frame, extra):
|
||||
pass
|
||||
|
||||
self.assertRaises(TypeError, self.cam.set_access_mode, -1)
|
||||
|
||||
with self.cam:
|
||||
# Expectation: raise TypeError on passing invalid parameters
|
||||
self.assertRaises(TypeError, self.cam.get_frame, 'hi')
|
||||
self.assertRaises(TypeError, self.cam.get_features_affected_by, 'No Feature')
|
||||
self.assertRaises(TypeError, self.cam.get_features_selected_by, 'No Feature')
|
||||
self.assertRaises(TypeError, self.cam.get_features_by_type, 0.0)
|
||||
self.assertRaises(TypeError, self.cam.get_feature_by_name, 0)
|
||||
self.assertRaises(TypeError, self.cam.get_frame_generator, '3')
|
||||
self.assertRaises(TypeError, self.cam.get_frame_generator, 0, 'foo')
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, valid_handler, 'no int')
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, invalid_handler_1)
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, invalid_handler_2)
|
||||
self.assertRaises(TypeError, self.cam.save_settings, 0, PersistType.All)
|
||||
self.assertRaises(TypeError, self.cam.save_settings, 'foo.xml', 'false type')
|
||||
|
||||
def test_camera_save_load_settings(self):
|
||||
# Expectation: After settings export a settings change must be reverted by loading a
|
||||
# Previously saved configuration.
|
||||
|
||||
file_name = 'test_save_load_settings.xml'
|
||||
|
||||
with self.cam:
|
||||
feat_height = self.cam.get_feature_by_name('Height')
|
||||
old_val = feat_height.get()
|
||||
|
||||
self.cam.save_settings(file_name, PersistType.All)
|
||||
|
||||
min_, max_ = feat_height.get_range()
|
||||
inc = feat_height.get_increment()
|
||||
|
||||
feat_height.set(max_ - min_ - inc)
|
||||
|
||||
self.cam.load_settings(file_name, PersistType.All)
|
||||
os.remove(file_name)
|
||||
|
||||
self.assertEqual(old_val, feat_height.get())
|
||||
|
||||
def test_camera_save_settings_verify_path(self):
|
||||
# Expectation: Valid files end with .xml and can be either a absolute path or relative
|
||||
# path to the given File. Everything else is a ValueError.
|
||||
|
||||
valid_paths = (
|
||||
'valid1.xml',
|
||||
os.path.join('.', 'valid2.xml'),
|
||||
os.path.join('Tests', 'valid3.xml'),
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'valid4.xml'),
|
||||
)
|
||||
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.save_settings, 'inval.xm', PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.assertNoRaise(self.cam.save_settings, path, PersistType.All)
|
||||
os.remove(path)
|
||||
|
||||
def test_camera_load_settings_verify_path(self):
|
||||
# Expectation: Valid files end with .xml and must exist before before any execution.
|
||||
valid_paths = (
|
||||
'valid1.xml',
|
||||
os.path.join('.', 'valid2.xml'),
|
||||
os.path.join('Tests', 'valid3.xml'),
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'valid4.xml'),
|
||||
)
|
||||
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.load_settings, 'inval.xm', PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.assertRaises(ValueError, self.cam.load_settings, path, PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.cam.save_settings(path, PersistType.All)
|
||||
|
||||
self.assertNoRaise(self.cam.load_settings, path, PersistType.All)
|
||||
os.remove(path)
|
||||
|
||||
def test_camera_context_manager_reentrancy(self):
|
||||
# Expectation: Camera Context Manager must be reentrant. Multiple calls to _open
|
||||
# must be prevented (would cause VimbaC - Error)
|
||||
with self.cam:
|
||||
with self.cam:
|
||||
with self.cam:
|
||||
pass
|
||||
|
||||
def test_camera_api_context_sensitity_outside_context(self):
|
||||
# Expectation: Call set_access_mode withing with scope must raise a RuntimeError
|
||||
with self.cam:
|
||||
self.assertRaises(RuntimeError, self.cam.set_access_mode)
|
||||
|
||||
def test_camera_api_context_sensitity_inside_context(self):
|
||||
# Expectation: Most Camera related functions are only valid then called within the given
|
||||
# Context. If called from Outside a runtime error must be raised.
|
||||
self.assertRaises(RuntimeError, self.cam.read_memory)
|
||||
self.assertRaises(RuntimeError, self.cam.write_memory)
|
||||
self.assertRaises(RuntimeError, self.cam.read_registers)
|
||||
self.assertRaises(RuntimeError, self.cam.write_registers)
|
||||
self.assertRaises(RuntimeError, self.cam.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_affected_by)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_selected_by)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_by_type)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_by_category)
|
||||
self.assertRaises(RuntimeError, self.cam.get_feature_by_name)
|
||||
self.assertRaises(RuntimeError, self.cam.get_frame_generator)
|
||||
self.assertRaises(RuntimeError, self.cam.get_frame)
|
||||
self.assertRaises(RuntimeError, self.cam.start_streaming)
|
||||
self.assertRaises(RuntimeError, self.cam.stop_streaming)
|
||||
self.assertRaises(RuntimeError, self.cam.queue_frame)
|
||||
self.assertRaises(RuntimeError, self.cam.get_pixel_formats)
|
||||
self.assertRaises(RuntimeError, self.cam.get_pixel_format)
|
||||
self.assertRaises(RuntimeError, self.cam.set_pixel_format)
|
||||
self.assertRaises(RuntimeError, self.cam.save_settings)
|
||||
self.assertRaises(RuntimeError, self.cam.load_settings)
|
||||
@@ -0,0 +1,831 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import threading
|
||||
|
||||
from vimba import *
|
||||
from vimba.feature import *
|
||||
|
||||
|
||||
class CamBaseFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.height = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaCameraError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Height\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_name(self):
|
||||
# Expectation: Return decoded FeatureName
|
||||
self.assertEqual(self.height.get_name(), 'Height')
|
||||
|
||||
def test_get_flags(self):
|
||||
# Expectation: Return decoded FeatureFlags
|
||||
self.assertEqual(self.height.get_flags(), (FeatureFlags.Read, FeatureFlags.Write))
|
||||
|
||||
def test_get_category(self):
|
||||
# Expectation: Return decoded category
|
||||
self.assertNotEqual(self.height.get_category(), '')
|
||||
|
||||
def test_get_display_name(self):
|
||||
# Expectation: Return decoded category
|
||||
self.assertEqual(self.height.get_display_name(), 'Height')
|
||||
|
||||
def test_get_polling_time(self):
|
||||
# Expectation: Return polling time. Only volatile features return
|
||||
# anything other than zero.
|
||||
self.assertEqual(self.height.get_polling_time(), 0)
|
||||
|
||||
def test_get_unit(self):
|
||||
# Expectation: If Unit exists, return unit else return ''
|
||||
self.assertEqual(self.height.get_unit(), '')
|
||||
|
||||
def test_get_representation(self):
|
||||
# Expectation: Get numeric representation if existing else ''
|
||||
self.assertEqual(self.height.get_representation(), '')
|
||||
|
||||
def test_get_visibility(self):
|
||||
# Expectation: Get UI Visibility
|
||||
self.assertEqual(self.height.get_visibility(), FeatureVisibility.Beginner)
|
||||
|
||||
def test_get_tooltip(self):
|
||||
# Expectation: Shall not raise anything
|
||||
self.assertNoRaise(self.height.get_tooltip)
|
||||
|
||||
def test_get_description(self):
|
||||
# Expectation: Get decoded description
|
||||
self.assertNotEqual(self.height.get_description(), '')
|
||||
|
||||
def test_get_sfnc_namespace(self):
|
||||
# Expectation: Get decoded sfnc namespace
|
||||
self.assertNotEqual(self.height.get_sfnc_namespace(), '')
|
||||
|
||||
def test_is_streamable(self):
|
||||
# Expectation: Streamable features shall return True, others False
|
||||
self.assertNoRaise(self.height.is_streamable)
|
||||
|
||||
def test_has_affected_features(self):
|
||||
# Expectation:Features that affect features shall return True, others False
|
||||
self.assertTrue(self.height.has_affected_features())
|
||||
|
||||
def test_has_selected_features(self):
|
||||
# Expectation:Features that select features shall return True, others False
|
||||
self.assertFalse(self.height.has_selected_features())
|
||||
|
||||
def test_get_access_mode(self):
|
||||
# Expectation: Read/Write Features return (True, True), ReadOnly return (True, False)
|
||||
self.assertEqual(self.height.get_access_mode(), (True, True))
|
||||
|
||||
def test_is_readable(self):
|
||||
# Expectation: True if feature grant read access else False
|
||||
self.assertTrue(self.height.is_readable())
|
||||
|
||||
def test_is_writeable(self):
|
||||
# Expectation: True if feature grant write access else False
|
||||
self.assertTrue(self.height.is_writeable())
|
||||
|
||||
def test_change_handler(self):
|
||||
# Expectation: A given change handler is executed on value change.
|
||||
# Adding the same handler multiple times shall not lead to multiple executions.
|
||||
# The same goes for double unregister.
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.event = threading.Event()
|
||||
self.call_cnt = 0
|
||||
|
||||
def __call__(self, feat):
|
||||
self.call_cnt += 1
|
||||
self.event.set()
|
||||
|
||||
handler = Handler()
|
||||
|
||||
self.height.register_change_handler(handler)
|
||||
self.height.register_change_handler(handler)
|
||||
|
||||
tmp = self.height.get()
|
||||
|
||||
min_, _ = self.height.get_range()
|
||||
inc = self.height.get_increment()
|
||||
|
||||
if min_ <= tmp - inc:
|
||||
self.height.set(tmp - inc)
|
||||
|
||||
else:
|
||||
self.height.set(tmp + inc)
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.height.unregister_change_handler(handler)
|
||||
self.height.unregister_change_handler(handler)
|
||||
|
||||
self.height.set(tmp)
|
||||
|
||||
self.assertEqual(handler.call_cnt, 1)
|
||||
|
||||
def test_stringify_features(self):
|
||||
# Expectation: Each Feature must have a __str__ method. Depending on the Feature
|
||||
# current Values are queried, this can fail. In those cases, all exceptions are
|
||||
# fetched -> all features must be strinify able without raising any exception
|
||||
for feat in self.vimba.get_all_features():
|
||||
self.assertNoRaise(str, feat)
|
||||
|
||||
for feat in self.cam.get_all_features():
|
||||
self.assertNoRaise(str, feat)
|
||||
|
||||
|
||||
class CamBoolFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.feat = self.vimba.get_feature_by_name('UsbTLIsPresent')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'UsbTLIsPresent\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: BoolFeature must return BoolFeature on get_type
|
||||
self.assertEqual(self.feat.get_type(), BoolFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: returns current boolean value.
|
||||
self.assertNoRaise(self.feat.get)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Raises invalid Access on non-writeable features.
|
||||
self.assertRaises(VimbaFeatureError, self.feat.set, True)
|
||||
|
||||
|
||||
class CamCommandFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.feat = self.vimba.get_feature_by_name('ActionCommand')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ActionCommand\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: CommandFeature must return CommandFeature on get_type
|
||||
self.assertEqual(self.feat.get_type(), CommandFeature)
|
||||
|
||||
|
||||
class CamEnumFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.cam.get_feature_by_name('DeviceScanType')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'DeviceScanType\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('AcquisitionMode')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'AcquisitionMode\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: EnumFeature must return EnumFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), EnumFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), EnumFeature)
|
||||
|
||||
def test_entry_as_bytes(self):
|
||||
# Expectation: Get EnumEntry as encoded byte sequence
|
||||
expected = b'MultiFrame'
|
||||
entry = self.feat_rw.get_entry('MultiFrame')
|
||||
|
||||
self.assertEqual(bytes(entry), expected)
|
||||
|
||||
def test_entry_as_tuple(self):
|
||||
# Expectation: Get EnumEntry as (str, int)
|
||||
entry = self.feat_rw.get_entry('MultiFrame')
|
||||
self.assertEqual(entry.as_tuple(), self.feat_rw.get_entry(int(entry)).as_tuple())
|
||||
|
||||
def test_get_all_entries(self):
|
||||
# Expectation: Get all possible enum entries regardless of the availability
|
||||
expected = (self.feat_r.get_entry('Areascan'),)
|
||||
|
||||
for e in expected:
|
||||
self.assertIn(e, self.feat_r.get_all_entries())
|
||||
|
||||
expected = (
|
||||
self.feat_rw.get_entry('SingleFrame'),
|
||||
self.feat_rw.get_entry('MultiFrame'),
|
||||
self.feat_rw.get_entry('Continuous')
|
||||
)
|
||||
|
||||
for e in expected:
|
||||
self.assertIn(e, self.feat_rw.get_all_entries())
|
||||
|
||||
def test_get_avail_entries(self):
|
||||
# Expectation: All returned enum entries must be available
|
||||
for e in self.feat_r.get_available_entries():
|
||||
self.assertTrue(e.is_available())
|
||||
|
||||
for e in self.feat_rw.get_available_entries():
|
||||
self.assertTrue(e.is_available())
|
||||
|
||||
def test_get_entry_int(self):
|
||||
# Expectation: Lookup a given entry by using an int as key.
|
||||
# Invalid keys must return VimbaFeatureError.
|
||||
|
||||
expected = self.feat_r.get_all_entries()[0]
|
||||
self.assertEqual(self.feat_r.get_entry(int(expected)), expected)
|
||||
|
||||
expected = self.feat_rw.get_all_entries()[1]
|
||||
self.assertEqual(self.feat_rw.get_entry(int(expected)), expected)
|
||||
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.get_entry, -1)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.get_entry, -1)
|
||||
|
||||
def test_get_entry_str(self):
|
||||
# Expectation: Lookup a given entry by using a str as key.
|
||||
# Invalid keys must return VimbaFeatureError.
|
||||
|
||||
expected = self.feat_r.get_all_entries()[0]
|
||||
self.assertEqual(self.feat_r.get_entry(str(expected)), expected)
|
||||
|
||||
expected = self.feat_rw.get_all_entries()[1]
|
||||
self.assertEqual(self.feat_rw.get_entry(str(expected)), expected)
|
||||
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.get_entry, 'Should be invalid')
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.get_entry, 'Should be invalid')
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get must return the current value.
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_set_entry(self):
|
||||
# Expectation: Set given enum entry if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if enum entry is from other enum feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
entry = self.feat_r.get_all_entries()[0]
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, entry)
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, self.feat_rw.get_entry(2))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by setting the feature from the ReadOnly entry.
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, entry)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_str(self):
|
||||
# Expectation: Set given enum entry string value if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if given string is not associated with this feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, str(self.feat_r.get_entry(0)))
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, str(self.feat_rw.get_entry(2)))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by an invalid enum value
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, 'Hopefully invalid')
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_int(self):
|
||||
# Expectation: Set given enum entry int value if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if given int is not associated with this feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, int(self.feat_r.get_entry(0)))
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, int(self.feat_rw.get_entry(2)))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by an invalid enum value
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, -23)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expected behavior: A set operation within a change handler must
|
||||
# Raise a VimbaFeatureError to prevent an endless handler execution.
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamFloatFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.vimba.get_feature_by_name('Elapsed')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Elapsed\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('ExposureTime')
|
||||
|
||||
except VimbaFeatureError:
|
||||
# Some Cameras name ExposureTime as ExposureTimeAbs
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('ExposureTimeAbs')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ExposureTime\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: FloatFeature returns FloatFeature on get_type.
|
||||
self.assertEqual(self.feat_r.get_type(), FloatFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), FloatFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value.
|
||||
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_range(self):
|
||||
# Expectation: Get value range. Raise VimbaFeatureError on non-read access.
|
||||
self.assertNoRaise(self.feat_r.get_range)
|
||||
self.assertNoRaise(self.feat_rw.get_range)
|
||||
|
||||
def test_get_increment(self):
|
||||
# Expectation: Get value increment if existing. If this Feature has no
|
||||
# increment, None is returned.
|
||||
|
||||
self.assertNoRaise(self.feat_r.get_increment)
|
||||
self.assertNoRaise(self.feat_rw.get_increment)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Set value. Errors:
|
||||
# VimbaFeatureError if access right are not writable
|
||||
# VimbaFeatureError if value is out of bounds
|
||||
|
||||
# Read only feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, 0.0)
|
||||
|
||||
# Read/Write Feature
|
||||
old_value = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
delta = 0.1
|
||||
|
||||
# Range test
|
||||
min_, max_ = self.feat_rw.get_range()
|
||||
|
||||
# Within bounds (no error)
|
||||
self.assertNoRaise(self.feat_rw.set, min_)
|
||||
self.assertAlmostEqual(self.feat_rw.get(), min_)
|
||||
self.assertNoRaise(self.feat_rw.set, max_)
|
||||
self.assertAlmostEqual(self.feat_rw.get(), max_)
|
||||
|
||||
# Out of bounds (must raise)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, min_ - delta)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, max_ + delta)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_value)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Calling set within change_handler must raise an VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamIntFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.cam.get_feature_by_name('HeightMax')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'HeightMax\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Height\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: IntFeature must return IntFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), IntFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), IntFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value
|
||||
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_range(self):
|
||||
# Expectation: Get range of accepted values
|
||||
self.assertNoRaise(self.feat_r.get_range)
|
||||
self.assertNoRaise(self.feat_rw.get_range)
|
||||
|
||||
def test_get_increment(self):
|
||||
# Expectation: Get step between valid values
|
||||
self.assertNoRaise(self.feat_r.get_increment)
|
||||
self.assertNoRaise(self.feat_rw.get_increment)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Set value or raise VimbaFeatureError under the following conditions.
|
||||
# 1) Invalid Access Rights
|
||||
# 2) Misaligned value.
|
||||
# 3) Out-of-bounds Access
|
||||
|
||||
# Read only feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, 0)
|
||||
|
||||
# Writable feature
|
||||
old_value = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
inc = self.feat_rw.get_increment()
|
||||
min_, max_ = self.feat_rw.get_range()
|
||||
|
||||
# Normal usage
|
||||
self.assertNoRaise(self.feat_rw.set, min_)
|
||||
self.assertEqual(self.feat_rw.get(), min_)
|
||||
self.assertNoRaise(self.feat_rw.set, max_)
|
||||
self.assertEqual(self.feat_rw.get(), max_)
|
||||
|
||||
# Out of bounds access.
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, min_ - inc)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, max_ + inc)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_value)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Setting a value within a Callback must raise a VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
min_, _ = self.feat_rw.get_range()
|
||||
inc = self.feat_rw.get_increment()
|
||||
|
||||
if min_ <= (old_entry - inc):
|
||||
self.feat_rw.set(old_entry - inc)
|
||||
|
||||
else:
|
||||
self.feat_rw.set(old_entry + inc)
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamStringFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
self.feat_r = None
|
||||
feats = self.cam.get_features_by_type(StringFeature)
|
||||
|
||||
for feat in feats:
|
||||
if feat.get_access_mode() == (True, False):
|
||||
self.feat_r = feat
|
||||
|
||||
if self.feat_r is None:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Test requires read only StringFeature.')
|
||||
|
||||
self.feat_rw = None
|
||||
feats = self.cam.get_features_by_type(StringFeature)
|
||||
|
||||
for feat in feats:
|
||||
if feat.get_access_mode() == (True, True):
|
||||
self.feat_rw = feat
|
||||
|
||||
if self.feat_rw is None:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Test requires read/write StringFeature.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: StringFeature must return StringFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), StringFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), StringFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value without raising an exception
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_max_length(self):
|
||||
# Expectation: Get maximum string length
|
||||
self.assertNoRaise(self.feat_r.get_max_length)
|
||||
self.assertNoRaise(self.feat_rw.get_max_length)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation:
|
||||
# 1) Setting a read only feature must raise a VimbaFeatureError
|
||||
# 2) Setting a read/wrtie must raise VimbaFeatureError if the string is
|
||||
# longer than max length
|
||||
# 3) Setting a read/write feature must work if string is long enough
|
||||
|
||||
# Ensure Expectation 1
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, self.feat_r.get())
|
||||
self.assertNoRaise(self.feat_rw.set, self.feat_rw.get())
|
||||
|
||||
# Ensure Expectation 2
|
||||
old_val = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
invalid = 'a' * self.feat_rw.get_max_length()
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, invalid)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_val)
|
||||
|
||||
# Ensure Expectation 3
|
||||
try:
|
||||
valid = 'a' * (self.feat_rw.get_max_length() - 1)
|
||||
self.assertNoRaise(self.feat_rw.set, valid)
|
||||
self.assertEqual(valid, self.feat_rw.get())
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_val)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Setting a value within a Callback must raise a VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
206
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/frame_test.py
Normal file
206
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/frame_test.py
Normal file
@@ -0,0 +1,206 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import copy
|
||||
import ctypes
|
||||
|
||||
from vimba import *
|
||||
from vimba.frame import *
|
||||
|
||||
|
||||
class CamFrameTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_verify_buffer(self):
|
||||
# Expectation: A Frame buffer shall have exactly the specified size on construction.
|
||||
# Allocation is performed by VimbaPython
|
||||
self.assertEqual(Frame(0, AllocationMode.AnnounceFrame).get_buffer_size(), 0)
|
||||
self.assertEqual(Frame(1024, AllocationMode.AnnounceFrame).get_buffer_size(), 1024)
|
||||
self.assertEqual(Frame(1024 * 1024, AllocationMode.AnnounceFrame).get_buffer_size(),
|
||||
1024 * 1024)
|
||||
|
||||
def test_verify_no_copy_empty_buffer_access(self):
|
||||
# Expectation: Accessing the internal buffer must not create a copy
|
||||
# frame._buffer is only set on construction if buffer is allocated by VimbaPython
|
||||
frame = Frame(10, AllocationMode.AnnounceFrame)
|
||||
self.assertEqual(id(frame._buffer), id(frame.get_buffer()))
|
||||
|
||||
def test_verify_no_copy_filled_buffer_access(self):
|
||||
# Expectation: Accessing the internal buffer must not create a copy
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertEqual(id(frame._buffer), id(frame.get_buffer()))
|
||||
|
||||
def test_get_id(self):
|
||||
# Expectation: get_id() must return None if Its locally constructed
|
||||
# else it must return the frame id.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_id())
|
||||
|
||||
with self.cam:
|
||||
self.assertIsNotNone(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_id())
|
||||
|
||||
def test_get_timestamp(self):
|
||||
# Expectation: get_timestamp() must return None if Its locally constructed
|
||||
# else it must return the timestamp.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_timestamp())
|
||||
|
||||
with self.cam:
|
||||
self.assertIsNotNone(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_timestamp())
|
||||
|
||||
def test_get_offset(self):
|
||||
# Expectation: get_offset_x() must return None if Its locally constructed
|
||||
# else it must return the offset as int. Same goes for get_offset_y()
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_offset_x())
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_offset_y())
|
||||
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertIsNotNone(frame.get_offset_x())
|
||||
self.assertIsNotNone(frame.get_offset_y())
|
||||
|
||||
def test_get_dimension(self):
|
||||
# Expectation: get_width() must return None if Its locally constructed
|
||||
# else it must return the offset as int. Same goes for get_height()
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_width())
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_height())
|
||||
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertIsNotNone(frame.get_width())
|
||||
self.assertIsNotNone(frame.get_height())
|
||||
|
||||
def test_get_image_size(self):
|
||||
# Expectation: get_image_size() must return 0 if locally constructed
|
||||
# else it must return the image_size as int.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertEquals(Frame(0, allocation_mode).get_image_size(), 0)
|
||||
|
||||
with self.cam:
|
||||
self.assertNotEquals(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_image_size(), 0)
|
||||
|
||||
def test_deepcopy(self):
|
||||
# Expectation: a deepcopy must clone the frame buffer with its contents an
|
||||
# update the internally store pointer in VmbFrame struct.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
|
||||
frame_cpy = copy.deepcopy(frame)
|
||||
|
||||
# Ensure frames and their members are not the same object
|
||||
self.assertNotEquals(id(frame), id(frame_cpy))
|
||||
self.assertNotEquals(id(frame._buffer), id(frame_cpy._buffer))
|
||||
self.assertNotEquals(id(frame._frame), id(frame_cpy._frame))
|
||||
|
||||
# Ensure that both buffers have the same size and contain the same data.
|
||||
self.assertEquals(frame.get_buffer_size(), frame_cpy.get_buffer_size())
|
||||
self.assertTrue(all(a == b for a, b in zip(frame.get_buffer(),
|
||||
frame_cpy.get_buffer())))
|
||||
|
||||
# Ensure that internal Frame Pointer points to correct buffer.
|
||||
self.assertEquals(frame._frame.buffer,
|
||||
ctypes.cast(frame._buffer, ctypes.c_void_p).value)
|
||||
|
||||
self.assertEquals(frame_cpy._frame.buffer,
|
||||
ctypes.cast(frame_cpy._buffer, ctypes.c_void_p).value)
|
||||
|
||||
self.assertEquals(frame._frame.bufferSize, frame_cpy._frame.bufferSize)
|
||||
|
||||
def test_get_pixel_format(self):
|
||||
# Expectation: Frames have an image format set after acquisition
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
self.assertNotEquals(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_pixel_format(), 0)
|
||||
|
||||
def test_incompatible_formats_value_error(self):
|
||||
# Expectation: Conversion into incompatible formats must lead to an value error
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
|
||||
current_fmt = frame.get_pixel_format()
|
||||
convertable_fmt = current_fmt.get_convertible_formats()
|
||||
|
||||
for fmt in PixelFormat.__members__.values():
|
||||
if (fmt != current_fmt) and (fmt not in convertable_fmt):
|
||||
self.assertRaises(ValueError, frame.convert_pixel_format, fmt)
|
||||
|
||||
def test_convert_to_all_given_formats(self):
|
||||
# Expectation: A Series of Frame, each acquired with a different Pixel format
|
||||
# Must be convertible to all formats the given format claims its convertible to without any
|
||||
# errors.
|
||||
|
||||
test_frames = []
|
||||
|
||||
with self.cam:
|
||||
for fmt in self.cam.get_pixel_formats():
|
||||
self.cam.set_pixel_format(fmt)
|
||||
|
||||
frame = self.cam.get_frame()
|
||||
|
||||
self.assertEqual(fmt, frame.get_pixel_format())
|
||||
test_frames.append(frame)
|
||||
|
||||
for frame in test_frames:
|
||||
|
||||
# The test shall work on a copy to keep the original Frame untouched
|
||||
for expected_fmt in frame.get_pixel_format().get_convertible_formats():
|
||||
cpy_frame = copy.deepcopy(frame)
|
||||
cpy_frame.convert_pixel_format(expected_fmt)
|
||||
|
||||
self.assertEquals(expected_fmt, cpy_frame.get_pixel_format())
|
||||
149
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/vimba_test.py
Normal file
149
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/vimba_test.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import ipaddress
|
||||
import struct
|
||||
|
||||
from vimba import *
|
||||
|
||||
|
||||
class CamVimbaTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_context_entry_exit(self):
|
||||
# Expected Behavior:
|
||||
# On entering the context features, cameras and interfaces shall
|
||||
# be detected and after leaving the context, everything should be reverted.
|
||||
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
with self.vimba:
|
||||
self.assertNotEqual(self.vimba.get_all_features(), ())
|
||||
self.assertNotEqual(self.vimba.get_all_interfaces(), ())
|
||||
self.assertNotEqual(self.vimba.get_all_cameras(), ())
|
||||
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
def test_get_all_interfaces(self):
|
||||
# Expected Behavior: get_all_interfaces() must raise an RuntimeError in closed state and
|
||||
# be non-empty then opened.
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
|
||||
with self.vimba:
|
||||
self.assertTrue(self.vimba.get_all_interfaces())
|
||||
|
||||
def test_get_interface_by_id(self):
|
||||
# Expected Behavior: All detected Interfaces must be lookup able by their Id.
|
||||
# If outside of given scope, an error must be returned
|
||||
with self.vimba:
|
||||
ids = [inter.get_id() for inter in self.vimba.get_all_interfaces()]
|
||||
|
||||
for id_ in ids:
|
||||
self.assertNoRaise(self.vimba.get_interface_by_id, id_)
|
||||
|
||||
for id_ in ids:
|
||||
self.assertRaises(RuntimeError, self.vimba.get_interface_by_id, id_)
|
||||
|
||||
def test_get_all_cameras(self):
|
||||
# Expected Behavior: get_all_cameras() must only return camera handles on a open camera.
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
with self.vimba:
|
||||
self.assertTrue(self.vimba.get_all_cameras())
|
||||
|
||||
def test_get_camera_by_id(self):
|
||||
# Expected Behavior: Lookup of test camera must not fail after system opening
|
||||
camera_id = self.get_test_camera_id()
|
||||
|
||||
with self.vimba:
|
||||
self.assertNoRaise(self.vimba.get_camera_by_id, camera_id)
|
||||
|
||||
def test_get_camera_by_ip(self):
|
||||
# Expected Behavior: get_camera_by_id() must work with a valid ipv4 address.
|
||||
# A with lookup of an invalid ipv4 address (no Camera attached)
|
||||
# must raise a VimbaCameraError, a lookup with an ipv6 address must raise a
|
||||
# VimbaCameraError in general (VimbaC doesn't support ipv6)
|
||||
with self.vimba:
|
||||
# Verify that the Test Camera is a GigE - Camera
|
||||
cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
inter = self.vimba.get_interface_by_id(cam.get_interface_id())
|
||||
|
||||
if inter.get_type() != InterfaceType.Ethernet:
|
||||
raise self.skipTest('Test requires GigE - Camera.')
|
||||
|
||||
# Lookup test cameras IP address.
|
||||
with cam:
|
||||
ip_as_number = cam.get_feature_by_name('GevCurrentIPAddress').get()
|
||||
|
||||
# Swap byte order, the raw value does not seem to follow network byte order.
|
||||
ip_as_number = struct.pack('<L', ip_as_number)
|
||||
|
||||
# Verify that lookup with IPv4 Address returns the same Camera Object
|
||||
ip_addr = str(ipaddress.IPv4Address(ip_as_number))
|
||||
self.assertEqual(self.vimba.get_camera_by_id(ip_addr), cam)
|
||||
|
||||
# Verify that a lookup with an invalid IPv4 Address raises a VimbaCameraError
|
||||
ip_addr = str(ipaddress.IPv4Address('127.0.0.1'))
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, ip_addr)
|
||||
|
||||
# Verify that a lookup with an IPv6 Address raises a VimbaCameraError
|
||||
ip_addr = str(ipaddress.IPv6Address('FD00::DEAD:BEEF'))
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, ip_addr)
|
||||
|
||||
def test_get_camera_by_mac(self):
|
||||
# Expected Behavior: get_feature_by_id must be usable with a given MAC Address.
|
||||
with self.vimba:
|
||||
# Verify that the Test Camera is a GigE - Camera
|
||||
cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
inter = self.vimba.get_interface_by_id(cam.get_interface_id())
|
||||
|
||||
if inter.get_type() != InterfaceType.Ethernet:
|
||||
raise self.skipTest('Test requires GigE - Camera.')
|
||||
|
||||
# Lookup test cameras MAC Address.
|
||||
with cam:
|
||||
# Construct MAC Address from raw value.
|
||||
mac_as_number = cam.get_feature_by_name('GevDeviceMACAddress').get()
|
||||
|
||||
mac_as_bytes = mac_as_number.to_bytes(6, byteorder='big')
|
||||
mac_as_str = ''.join(format(s, '02x') for s in mac_as_bytes).upper()
|
||||
|
||||
# Verify that lookup with MAC Address returns the same Camera Object
|
||||
self.assertEqual(self.vimba.get_camera_by_id(mac_as_str), cam)
|
||||
|
||||
# Verify that a lookup with an invalid MAC Address raises a VimbaCameraError
|
||||
invalid_mac = 'ffffffff'
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, invalid_mac)
|
||||
177
Vimba_6_0/VimbaPython/Source/Tests/runner.py
Normal file
177
Vimba_6_0/VimbaPython/Source/Tests/runner.py
Normal file
@@ -0,0 +1,177 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import docopt
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add local directory to search path for test module import in this script.
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
||||
|
||||
|
||||
# Add vimba module at the start of the search path. The tests should run against the
|
||||
# local VimbaPython sources regardless of any existing installations.
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
|
||||
# Inject 'assertNotRaise' to default test module. Tests are derived from this class.
|
||||
def _assertNoRaise(self, func, *args, **kwargs):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
|
||||
except BaseException as e:
|
||||
self.fail('Function raised: {}'.format(e))
|
||||
|
||||
|
||||
# Inject shared test camera id into the base TestCase
|
||||
def _get_test_camera_id(self) -> str:
|
||||
return unittest.TestCase.test_cam_id
|
||||
|
||||
|
||||
def _set_test_camera_id(test_cam_id) -> str:
|
||||
unittest.TestCase.test_cam_id = test_cam_id
|
||||
|
||||
|
||||
unittest.TestCase.assertNoRaise = _assertNoRaise
|
||||
unittest.TestCase.set_test_camera_id = _set_test_camera_id
|
||||
unittest.TestCase.get_test_camera_id = _get_test_camera_id
|
||||
|
||||
|
||||
def _blacklist_tests(test_suite, blacklist):
|
||||
for test in test_suite:
|
||||
# Process TestSuites recursively
|
||||
if type(test) == unittest.TestSuite:
|
||||
_blacklist_tests(test, blacklist)
|
||||
|
||||
# Test is actually a TestCase. Add skip decorator to test
|
||||
# function if the test is blacklisted.
|
||||
else:
|
||||
name = test._testMethodName
|
||||
if name in blacklist:
|
||||
setattr(test, name, unittest.skip('Blacklisted')(getattr(test, name)))
|
||||
|
||||
return test_suite
|
||||
|
||||
|
||||
def main():
|
||||
CLI = """VimbaPython test runner.
|
||||
Usage:
|
||||
runner.py -h
|
||||
runner.py -s basic -o console [BLACKLIST...]
|
||||
runner.py -s basic -o junit_xml REPORT_DIR [BLACKLIST...]
|
||||
runner.py -s (real_cam | all) -c CAMERA_ID -o console [BLACKLIST...]
|
||||
runner.py -s (real_cam | all) -c CAMERA_ID -o junit_xml REPORT_DIR [BLACKLIST...]
|
||||
|
||||
Arguments:
|
||||
CAMERA_ID Camera Id from Camera that shall be used during testing
|
||||
REPORT_DIR Directory used for junit_export.
|
||||
BLACKLIST Optional sequence of unittest functions to skip.
|
||||
|
||||
Options:
|
||||
-h Show this screen.
|
||||
-s Testsuite to execute. real_cam and all require a camera to
|
||||
run tests against, therefore -c is mandatory.
|
||||
-c Camera Id used while testing.
|
||||
-o Test output: Either console or junit_xml.
|
||||
"""
|
||||
|
||||
args = docopt.docopt(CLI)
|
||||
loader = unittest.TestLoader()
|
||||
|
||||
if args['CAMERA_ID']:
|
||||
unittest.TestCase.set_test_camera_id(args['CAMERA_ID'])
|
||||
|
||||
else:
|
||||
unittest.TestCase.set_test_camera_id(None)
|
||||
|
||||
# Select TestRunner
|
||||
if args['console']:
|
||||
runner = unittest.TextTestRunner(verbosity=2)
|
||||
|
||||
elif args['junit_xml']:
|
||||
import xmlrunner
|
||||
runner = xmlrunner.XMLTestRunner(output=args['REPORT_DIR'])
|
||||
|
||||
# Import tests cases
|
||||
import basic_tests.c_binding_test
|
||||
import basic_tests.util_runtime_type_check_test
|
||||
import basic_tests.util_tracer_test
|
||||
import basic_tests.util_context_decorator_test
|
||||
import basic_tests.vimba_common_test
|
||||
import basic_tests.vimba_test
|
||||
import basic_tests.interface_test
|
||||
|
||||
import real_cam_tests.vimba_test
|
||||
import real_cam_tests.feature_test
|
||||
import real_cam_tests.camera_test
|
||||
import real_cam_tests.frame_test
|
||||
import real_cam_tests.ancillary_data_test
|
||||
|
||||
# Assign test cases to test suites
|
||||
BASIC_TEST_MODS = [
|
||||
basic_tests.c_binding_test,
|
||||
basic_tests.util_runtime_type_check_test,
|
||||
basic_tests.util_tracer_test,
|
||||
basic_tests.util_context_decorator_test,
|
||||
basic_tests.vimba_common_test,
|
||||
basic_tests.vimba_test,
|
||||
basic_tests.interface_test
|
||||
]
|
||||
|
||||
REAL_CAM_TEST_MODS = [
|
||||
real_cam_tests.vimba_test,
|
||||
real_cam_tests.feature_test,
|
||||
real_cam_tests.camera_test,
|
||||
real_cam_tests.frame_test,
|
||||
real_cam_tests.ancillary_data_test
|
||||
]
|
||||
|
||||
# Prepare TestSuites
|
||||
suite_basic = unittest.TestSuite()
|
||||
suite_cam = unittest.TestSuite()
|
||||
|
||||
for mod in BASIC_TEST_MODS:
|
||||
suite_basic.addTests(_blacklist_tests(loader.loadTestsFromModule(mod), args['BLACKLIST']))
|
||||
|
||||
for mod in REAL_CAM_TEST_MODS:
|
||||
suite_cam.addTests(_blacklist_tests(loader.loadTestsFromModule(mod), args['BLACKLIST']))
|
||||
|
||||
# Execute TestSuites
|
||||
if args['basic']:
|
||||
runner.run(suite_basic)
|
||||
|
||||
elif args['real_cam']:
|
||||
runner.run(suite_cam)
|
||||
|
||||
elif args['all']:
|
||||
runner.run(suite_basic)
|
||||
runner.run(suite_cam)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user