54 def handle(self, command):
55 if command.startswith(b
"echo "):
56 self.in_buffer.write(command[5:] + self.
eol)
57 elif command
in [b
"foo", b
"bar"]:
60 raise RuntimeError(
"unknown command '%s'" % command.decode())
64 patcher = unittest.mock.patch.object(
67 self.addCleanup(patcher.stop)
68 self.mock = patcher.start()
70 def test_simple_commands(self):
71 self.serial.write(b
"foo\r\n")
72 self.mock.assert_called_once_with(b
"foo")
74 def test_partial_commands(self):
75 self.serial.write(b
"fo")
76 self.serial.write(b
"o")
77 self.serial.write(b
"\r\n")
78 self.serial.handle.assert_called_once_with(b
"foo")
80 def test_multiple_commands(self):
81 self.serial.write(b
"foo\r\nbar\r\n")
82 calls = [unittest.mock.call(x)
for x
in [b
"foo", b
"bar"]]
83 self.assertEqual(self.serial.handle.mock_calls, calls)
85 def test_unix_eol(self):
86 self.serial.eol = b
"\n"
87 self.serial.write(b
"foo\nbar\n")
88 calls = [unittest.mock.call(x)
for x
in [b
"foo", b
"bar"]]
89 self.assertEqual(self.serial.handle.mock_calls, calls)
92 self.serial.write(b
"echo qux\r\n")
93 self.assertEqual(self.serial.readline(), b
"qux\r\n")
150 def test_connection_defaults(self):
151 self.assertEqual(self.device.connection.baudrate, self.fake.baudrate)
152 self.assertEqual(self.device.connection.parity, self.fake.parity)
153 self.assertEqual(self.device.connection.bytesize, self.fake.bytesize)
154 self.assertEqual(self.device.connection.stopbits, self.fake.stopbits)
155 self.assertEqual(self.device.connection.rtscts, self.fake.rtscts)
156 self.assertEqual(self.device.connection.dsrdtr, self.fake.dsrdtr)
160 """Base class for :class:`LightSource` tests.
162 This class implements all the general laser tests and is meant to
163 be mixed with :class:`unittest.TestCase`. Subclasses must
164 implement the `setUp` method which must add two properties:
167 Instance of the :class:`LightSource` implementation being
171 Object with a multiple attributes that specify the hardware
172 and control the tests, such as the device max and min power
173 values. Such attributes may as well be attributes in the
174 class that fakes the hardware.
178 def assertEqualMW(self, first, second, msg=None):
181 self.assertEqual(round(first), round(second), msg)
183 def test_get_is_on(self):
184 self.assertEqual(self.device.connection.light, self.device.get_is_on())
186 self.assertEqual(self.device.connection.light, self.device.get_is_on())
187 self.device.disable()
188 self.assertEqual(self.device.connection.light, self.device.get_is_on())
190 def test_off_after_constructor(self):
195 self.assertFalse(self.device.get_is_on())
197 def test_turning_on_and_off(self):
199 self.assertTrue(self.device.get_is_on())
200 self.device.disable()
201 self.assertFalse(self.device.get_is_on())
203 def test_shutdown(self):
205 self.device.disable()
206 self.device.shutdown()
208 def test_power_when_off(self):
209 self.device.disable()
210 self.assertIsInstance(self.device.power, float)
211 self.assertEqual(self.device.power, 0.0)
213 def test_setting_power(self):
215 self.assertIsInstance(self.device.power, float)
216 power_mw = self.device.power * self.fake.max_power
218 self.
assertEqualMW(self.device.power, self.device.get_set_power())
221 new_power_mw = new_power * self.fake.max_power
222 self.device.power = new_power
224 self.device.power * self.fake.max_power, new_power_mw
228 def test_setting_power_outside_limit(self):
230 self.device.power = -0.1
233 self.fake.min_power / self.fake.max_power,
234 "clip setting power below 0",
236 self.device.power = 1.1
237 self.assertEqual(self.device.power, 1.0,
"clip setting power above 1")
239 def test_status(self):
240 status = self.device.get_status()
241 self.assertIsInstance(status, list)
243 self.assertIsInstance(msg, str)
255 def test_get_and_set_position(self):
256 self.assertEqual(self.device.position, 0)
257 max_pos = self.device.n_positions - 1
258 self.device.position = max_pos
259 self.assertEqual(self.device.position, max_pos)
261 def test_set_position_to_negative(self):
262 with self.assertRaisesRegex(Exception,
"can't move to position"):
263 self.device.position = -1
265 def test_set_position_above_limit(self):
266 with self.assertRaisesRegex(Exception,
"can't move to position"):
267 self.device.position = self.device.n_positions
271 """Collection of test cases for deformable mirrors.
273 Should have the following properties defined during `setUp`:
274 `planned_n_actuators` (int): number of actuators
275 `device` (DeformableMirror): the microscope device instance
276 `fake`: an object with the method `get_current_pattern`
279 def assertCurrentPattern(self, expected_pattern, msg=""):
280 numpy.testing.assert_array_equal(
281 self.fake.get_current_pattern(), expected_pattern, msg
284 def test_get_number_of_actuators(self):
285 self.assertIsInstance(self.device.n_actuators, int)
286 self.assertGreater(self.device.n_actuators, 0)
289 def test_applying_pattern(self):
291 self.device.apply_pattern(pattern)
294 def test_out_of_range_pattern(self):
298 for v
in [-1000, -1, 0, 1, 3]:
300 self.device.apply_pattern(pattern)
303 def test_software_triggering(self):
306 self.device.queue_patterns(patterns)
307 for i
in range(n_patterns):
308 self.device.next_pattern()
311 def test_validate_pattern_too_long(self):
313 with self.assertRaisesRegex(Exception,
"length of second dimension"):
314 self.device.apply_pattern(patterns)
316 def test_validate_pattern_swapped_dimensions(self):
318 with self.assertRaisesRegex(Exception,
"length of second dimension"):
319 self.device.apply_pattern(patterns)
321 def test_validate_pattern_with_extra_dimension(self):
323 with self.assertRaisesRegex(
324 Exception,
"dimensions \\(must be 1 or 2\\)"
326 self.device.apply_pattern(patterns)
353class TestCoherentSapphireLaser(
354 unittest.TestCase, LightSourceTests, SerialDeviceTests
360 with unittest.mock.patch(
361 "microscope.lights.sapphire.serial.Serial",
362 new=CoherentSapphireLaserMock,
364 self.device = SapphireLaser(
"/dev/null")
365 self.device.initialize()
367 self.fake = CoherentSapphireLaserMock
385 unittest.TestCase, LightSourceTests, SerialDeviceTests
391 with unittest.mock.patch(
392 "microscope.lights.deepstar.serial.Serial",
393 new=OmicronDeepstarLaserMock,
395 self.
device = DeepstarLaser(
"/dev/null")
398 self.
fake = OmicronDeepstarLaserMock
400 def test_weird_initial_state(self):
405 self.
device.connection.internal_peak_power =
False
406 self.
device.connection.bias_modulation =
True
407 self.
device.connection.digital_modulation =
True
408 self.
device.connection.analog2digital =
True
411 self.assertTrue(self.
device.get_is_on())
413 self.assertTrue(self.
device.connection.internal_peak_power)
414 self.assertFalse(self.
device.connection.bias_modulation)
415 self.assertFalse(self.
device.connection.digital_modulation)
416 self.assertFalse(self.
device.connection.analog2digital)
425 def test_non_square_patterns_shape(self):
432 patterns = list(generator.get_methods())
433 for i, pattern
in enumerate(patterns):
434 with self.subTest(pattern):
435 generator.set_method(i)
436 array = generator.get_image(width, height, 0, 255)
439 self.assertEqual(array.shape, (height, width))