def test_handleAtCommand_multipleHandlers_match(self): """Test handleAtCommand when multiple command handlers are defined and match.""" mockLogger = mock.Mock() mockState = mock.Mock() mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = False mockEntry1 = mock.Mock() mockEntry1.action = ENABLE_EXCLUSION mockEntry1.matches.return_value = True mockEntry2 = mock.Mock() mockEntry2.action = ENABLE_EXCLUSION mockEntry2.matches.return_value = True mockState.atCommandActions = mock.Mock( wraps={"DefinedCommand": [mockEntry1, mockEntry2]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "DefinedCommand", "params") mockState.atCommandActions.get.assert_called_with("DefinedCommand") mockEntry1.matches.assert_called_with("DefinedCommand", "params") mockEntry2.matches.assert_called_with("DefinedCommand", "params") self.assertEqual(mockState.enableExclusion.call_count, 2, "enableExclusion should be called twice") mockState.disableExclusion.assert_not_called() mockCommInstance.sendCommand.assert_not_called() self.assertTrue(result, "The result should be True")
def test_handleAtCommand_oneHandler_match_DISABLE_EXCLUSION(self): """Test handleAtCommand with one matching handler that disables exclusion.""" mockLogger = mock.Mock() mockState = mock.Mock() mockState.disableExclusion.return_value = ["Command1", "Command2"] mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = False mockEntry = mock.Mock() mockEntry.action = DISABLE_EXCLUSION mockEntry.matches.return_value = True mockState.atCommandActions = mock.Mock( wraps={"DefinedCommand": [mockEntry]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "DefinedCommand", "params") mockState.atCommandActions.get.assert_called_with("DefinedCommand") mockEntry.matches.assert_called_with("DefinedCommand", "params") mockState.enableExclusion.assert_not_called() mockState.disableExclusion.assert_called_once() mockCommInstance.sendCommand.assert_has_calls( [mock.call("Command1"), mock.call("Command2")]) self.assertTrue(result, "The result should be True")
def test_handleAtCommand_multipleHandlers_noParamMatch(self): """Test handleAtCommand when multiple command handlers defined, but no param matches.""" mockLogger = mock.Mock() mockState = mock.Mock() mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = False mockEntry1 = mock.Mock() mockEntry1.matches.return_value = None mockEntry2 = mock.Mock() mockEntry2.matches.return_value = None mockState.atCommandActions = mock.Mock( wraps={"DefinedCommand": [mockEntry1, mockEntry2]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "DefinedCommand", "params") mockState.atCommandActions.get.assert_called_with("DefinedCommand") mockEntry1.matches.assert_called_with("DefinedCommand", "params") mockEntry2.matches.assert_called_with("DefinedCommand", "params") mockState.enableExclusion.assert_not_called() mockState.disableExclusion.assert_not_called() mockCommInstance.sendCommand.assert_not_called() self.assertFalse(result, "The result should be False")
def test_handleAtCommand_oneHandler_match_unsupported_action(self): """Test handleAtCommand with one matching handler that specifies an unsupported action.""" mockLogger = mock.Mock() mockState = mock.Mock() mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = False mockEntry = mock.Mock() mockEntry.action = "unsupported" mockEntry.matches.return_value = True mockState.atCommandActions = mock.Mock( wraps={"DefinedCommand": [mockEntry]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "DefinedCommand", "params") mockState.atCommandActions.get.assert_called_with("DefinedCommand") mockEntry.matches.assert_called_with("DefinedCommand", "params") mockState.enableExclusion.assert_not_called() mockState.disableExclusion.assert_not_called() mockCommInstance.sendCommand.assert_not_called() mockLogger.warn.assert_called() self.assertTrue(result, "The result should be True")
def test_handleAtCommand_isSdStreaming(self): """Test handleAtCommand when the commInstance indicates SD streaming.""" mockLogger = mock.Mock() mockState = mock.Mock() mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = True # Mock a matching entry, which should not be invoked mockEntry = mock.Mock() mockEntry.action = ENABLE_EXCLUSION mockEntry.matches.return_value = True mockState.atCommandActions = mock.Mock( wraps={"DefinedCommand": [mockEntry]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "DefinedCommand", "params") mockState.atCommandActions.get.assert_not_called() mockEntry.matches.assert_not_called() mockState.enableExclusion.assert_not_called() mockState.disableExclusion.assert_not_called() mockCommInstance.sendCommand.assert_not_called() self.assertFalse(result, "The result should be False")
def test_computeArcCenterOffsets_zeroRadius(self): """Test the computeArcCenterOffsets method with a radius of zero.""" mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = 0 mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.computeArcCenterOffsets(10, 10, 0, True) self.assertEqual(result, (0, 0), "No offset should be computed when the radius is 0")
def test_computeArcCenterOffsets_counterClockwise_semicircle(self): """Test the computeArcCenterOffsets method with a CCW semicircular 100 unit arc.""" arcRadius = 50 mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = arcRadius mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.computeArcCenterOffsets(-arcRadius, 0, arcRadius, False) self.assertEqual( result, (-arcRadius, 0), "The computed center offset should be (%s, %s)" % (-arcRadius, 0))
def test_computeArcCenterOffsets_circle(self): """Test the computeArcCenterOffsets method when the start and end points are identical.""" arcRadius = 50 mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = 0 mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.computeArcCenterOffsets(0, 0, arcRadius, True) self.assertEqual( result, (0, 0), "No offset should be computed when the start and end points are the same" )
def test_computeArcCenterOffsets_radiusTooSmall(self): """Test computeArcCenterOffsets when the radius is less than half the chord length.""" mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = 0 mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) # Try chord length 10, radius 4 result = unit.computeArcCenterOffsets(10, 0, 4, True) self.assertEqual( result, (0, 0), "No offset should be computed if the radius is less than half the chord length." )
def test_handleAtCommand_noHandler(self): """Test handleAtCommand when no matching command handler is defined.""" mockLogger = mock.Mock() mockState = mock.Mock() mockCommInstance = mock.Mock() mockCommInstance.isStreaming.return_value = False mockEntry = mock.Mock() mockState.atCommandActions = mock.Mock(wraps={"NoMatch": [mockEntry]}) unit = GcodeHandlers(mockState, mockLogger) result = unit.handleAtCommand(mockCommInstance, "NotDefined", "params") mockState.atCommandActions.get.assert_called_with("NotDefined") mockEntry.matches.assert_not_called() mockState.enableExclusion.assert_not_called() mockState.disableExclusion.assert_not_called() mockCommInstance.sendCommand.assert_not_called() self.assertFalse(result, "The result should be False")
def test_planArc_counterClockwise_semicircle(self): """Tests the planArc method with a CCW semicircular 100 unit arc centered at (0,0).""" arcRadius = 50 mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = -arcRadius mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.planArc(arcRadius, 0, arcRadius, 0, False) self._assert_planArc_commonResultProperties(start=(-arcRadius, 0), end=(arcRadius, 0), center=(0, 0), radius=arcRadius, items=result) # y value comparisons # - the y component of each point should be below or equal to the y axis # - the y component direction must change one time self._assert_planArc_axisProperties( coordinateOffset=1, initialValue=0, initialDirection=-1, expectedReversals=1, items=result, filterFunc=lambda x, y, direction, index: (self.assertTrue( y <= 0, "Each y coordinate should be on or below the Y axis" + ": pt=(%s, %s) index=%s" % (x, y, index)))) # x value comparisons # - the x component of each point should increase for each point self._assert_planArc_axisProperties(coordinateOffset=0, initialValue=-arcRadius, initialDirection=1, expectedReversals=0, items=result)
def test_constructor(self): """Test the constructor when passed logger and state instances.""" # pylint: disable=protected-access mockState = mock.Mock(name="state") mockLogger = mock.Mock(name="_logger") unit = GcodeHandlers(mockState, mockLogger) self.assertIsInstance(unit, GcodeHandlers) self.assertProperties(unit, GcodeHandlersTests.expectedProperties) self.assertIs(unit._logger, mockLogger, "The logger should match the instance passed in") self.assertIs(unit.state, mockState, "The state should match the instance passed in")
def test_computeArcCenterOffsets_negativeRadius(self): """Test computeArcCenterOffsets method with a negative radius value.""" # Tests an arc with a chord length of 8 (half-width of 4) and a height (from chord to # center point on arc) of 3 arcRadius = -(4.0 + 1.0 / 6.0) mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = 0 mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.computeArcCenterOffsets(8, 0, arcRadius, True) self.assertEqual( result[0], 4, "The returned I value should match the expected value") self.assertAlmostEqual( result[1], arcRadius + 3, # Note addition here when radius is negative msg="The returned J value should match the expected value")
def test_constructor_missingLogger(self): """Test the constructor when passed a state, but no logger.""" mockState = mock.Mock(name="state") with self.assertRaises(AssertionError): GcodeHandlers(mockState, None)
def test_constructor_missingState(self): """Test the constructor when passed a logger, but no state.""" mockLogger = mock.Mock(name="_logger") with self.assertRaises(AssertionError): GcodeHandlers(None, mockLogger)
def _createInstance(): return GcodeHandlers(mock.Mock(name="state"), mock.Mock(name="_logger"))
def test_planArc_counterClockwise_circle(self): """Tests the planArc method with a CCW circular 100 unit arc centered at (0,0).""" arcRadius = 50 mockLogger = mock.Mock() mockState = mock.Mock() mockState.position.X_AXIS.nativeToLogical.return_value = -arcRadius mockState.position.Y_AXIS.nativeToLogical.return_value = 0 unit = GcodeHandlers(mockState, mockLogger) result = unit.planArc(-arcRadius, 0, arcRadius, 0, False) self._assert_planArc_commonResultProperties(start=(-arcRadius, 0), end=(-arcRadius, 0), center=(0, 0), radius=arcRadius, items=result) # y value comparisons # - the y component of each point to the left of x axis should have a negative direction # - the y component of each point to the right of x axis should have a positive direction # - the y component direction must change two times ignoredY = {"first": False} def filter_y(x, y, direction, index): if (x < 0): self.assertEqual( direction, -1, "The y direction should be negative for points to the left of the x axis" + ": pt=(%s, %s) index=%s" % (x, y, index)) elif (ignoredY["first"]): self.assertEqual( direction, 1, "The y direction should be positive for points to the right of the x axis" + ": pt=(%s, %s) index=%s" % (x, y, index)) else: # Ignore the first one, since it _could_ have the opposite direction at the boundary ignoredY["first"] = True self._assert_planArc_axisProperties(coordinateOffset=1, initialValue=0, initialDirection=-1, expectedReversals=2, items=result, filterFunc=filter_y) # x value comparisons # - the x component of each point above the y axis should have a negative direction # - the x component of each point below the y axis should have a positive direction # - the x component direction must change one time ignoredX = {"first": False} def filter_x(x, y, direction, index): if (y < 0): self.assertEqual( direction, 1, "The x direction should be positive for points below the y axis" + ": pt=(%s, %s) index=%s" % (x, y, index)) elif (ignoredX["first"]): self.assertEqual( direction, -1, "The x direction should be negative for points above the y axis" + ": pt=(%s, %s) index=%s" % (x, y, index)) else: # Ignore the first one, since it _could_ have the opposite direction at the boundary ignoredX["first"] = True self._assert_planArc_axisProperties(coordinateOffset=0, initialValue=-arcRadius, initialDirection=1, expectedReversals=1, items=result, filterFunc=filter_x)