def test_processExtendedGcodeEntry_EXCLUDE_MERGE_hasPendingArgs_cmdHasArgs( self): """Test processExtendedGcodeEntry / EXCLUDE_MERGE if pending args and command with args.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.pendingCommands = OrderedDict([("G1", { "X": 10, "Z": 20 }), ("M117", "M117 Test")]) # Use upper and lower case args to test case-sensitivity result = unit._processExtendedGcodeEntry( # pylint: disable=protected-access EXCLUDE_MERGE, "G1 x1 Y2", "G1") # Order of elements and parameter values should be updated self.assertEqual( unit.pendingCommands, OrderedDict([("M117", "M117 Test"), ("G1", { "X": 1, "Y": 2, "Z": 20 })]), "pendingCommands should be updated with new argument values.") self.assertEqual( result, (None, ), "The result should indicate to drop/ignore the command")
def test_recoverRetractionIfNeeded_lastRetraction_notExcluding(self): """Test recoverRetractionIfNeeded with a lastRetraction and NOT excluding.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) with mock.patch.multiple(unit, _recoverRetraction=mock.DEFAULT, lastRetraction=mock.DEFAULT) as mocks: unit.excluding = False unit.lastRetraction.recoverExcluded = False unit.lastRetraction.allowCombine = True mocks["_recoverRetraction"].return_value = ["expectedCommand"] result = unit.recoverRetractionIfNeeded("G11", True) mocks["_recoverRetraction"].assert_called_with("G11", True) self.assertEqual(unit.lastRetraction, mocks["lastRetraction"], "The lastRetraction should not be updated") self.assertFalse(unit.lastRetraction.allowCombine, "allowCombine should be set to False") self.assertFalse(unit.lastRetraction.recoverExcluded, "recoverExcluded should not be updated") self.assertEqual( result, ["expectedCommand"], "The result should match the list of commands returned by _recoverRetraction" )
def test_isExclusionEnabled_enabled(self): """Test the isExclusionEnabled method when exclusion is enabled.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) self.assertTrue(unit.isExclusionEnabled(), "isExclusionEnabled should report True")
def test_replaceRegion_found_middle(self): """Test the replaceRegion method when the matched region not first nor last in the list.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) firstRegion = RectangularRegion(x1=20, y1=20, x2=30, y2=30, id="firstId") regionToMatch = RectangularRegion(x1=10, y1=10, x2=20, y2=20, id="matchId") lastRegion = RectangularRegion(x1=30, y1=30, x2=40, y2=40, id="lastId") newRegion = RectangularRegion(x1=0, y1=0, x2=100, y2=100, id="matchId") unit.addRegion(firstRegion) unit.addRegion(regionToMatch) unit.addRegion(lastRegion) unit.replaceRegion(newRegion) self.assertEqual( unit.excludedRegions, [firstRegion, newRegion, lastRegion], "The excluded regions should be updated by replaceRegion if the ID is found (last)" )
def test_recordRetraction_recoverExcluded_firmwareRetract(self): """Test recordRetraction with recoverExcluded=True and a firmware retract.""" mockRetractionState = mock.Mock() mockRetractionState.originalCommand = "retractionCommand" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) with mock.patch.object(unit, 'lastRetraction'): unit.feedRate = 20 unit.lastRetraction.recoverExcluded = True unit.lastRetraction.firmwareRetract = True unit.lastRetraction.feedRate = None returnCommands = unit.recordRetraction(mockRetractionState) self.assertFalse( unit.lastRetraction.recoverExcluded, "lastRetraction.recoverExcluded should be set to False") self.assertIsNone( unit.lastRetraction.feedRate, "The retraction feedRate should not be modified.") self.assertEqual(returnCommands, [], "The result should be an empty list.")
def test_recoverRetractionIfNeeded_lastRetraction_excluding_notRecoveryCommand( self): """Test recoverRetractionIfNeeded with lastRetraction, excluding and NO recoveryCommand.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) with mock.patch.multiple(unit, _recoverRetraction=mock.DEFAULT, lastRetraction=mock.DEFAULT) as mocks: unit.excluding = True unit.lastRetraction.recoverExcluded = False unit.lastRetraction.allowCombine = True result = unit.recoverRetractionIfNeeded("G1 X1 Y2 E3", False) # The test against this mock covers both cases where returnCommands None and when it is # a list of commands since the final result is built from the _recoverRetraction result # which is mocked anyway mocks["_recoverRetraction"].assert_not_called() self.assertEqual(unit.lastRetraction, mocks["lastRetraction"], "The lastRetraction should not be updated") self.assertFalse(unit.lastRetraction.allowCombine, "allowCombine should be set to False") self.assertFalse(unit.lastRetraction.recoverExcluded, "recoverExcluded should not be updated") self.assertEqual(result, [], "The result should be an empty list.")
def test_getRegion_notExists(self): """Test the getRegion method when no such region is defined.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) self.assertIsNone( unit.getRegion("someId"), "getRegion return None when the region isn't defined")
def test_isExclusionEnabled_disabled(self): """Test the isExclusionEnabled method when exclusion is disabled.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.disableExclusion("Disable for test") self.assertFalse(unit.isExclusionEnabled(), "isExclusionEnabled should report False")
def test_isAnyPointExcluded_lastExcluded(self): """Test the isAnyPointExcluded method when only the last point is excluded.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) aRegion = RectangularRegion(x1=0, y1=0, x2=5, y2=5) unit.addRegion(aRegion) self.assertTrue(unit.isAnyPointExcluded(10, 10, 0, 0), "(0,0) should be excluded (last)")
def test_deleteRegion_noRegions(self): """Test the deleteRegion method when no regions are defined.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) self.assertFalse( unit.deleteRegion("notFound"), "deleteRegion should return False when the region is not found (no regions defined)" )
def test_replaceRegion_noRegions(self): """Test the replaceRegion method when no regions are defined.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) newRegion = RectangularRegion(x1=0, y1=0, x2=100, y2=100, id="someId") with self.assertRaises(ValueError): unit.replaceRegion(newRegion)
def test_isAnyPointExcluded_middleExcluded(self): """Test the isAnyPointExcluded method a point other than the first or last is excluded.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) aRegion = RectangularRegion(x1=0, y1=0, x2=5, y2=5) unit.addRegion(aRegion) self.assertTrue(unit.isAnyPointExcluded(10, 10, 0, 0, 20, 20), "(0,0) should be excluded (middle)")
def test_isAnyPointExcluded_noArguments(self): """Test the isAnyPointExcluded method when no arguments are provided.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) aRegion = RectangularRegion(x1=0, y1=0, x2=5, y2=5) unit.addRegion(aRegion) self.assertFalse( unit.isAnyPointExcluded(), "isAnyPointExcluded should return false when passed no arguments")
def test_replaceRegion_missingId(self): """Test the replaceRegion method when the region procided doesn't have an assigned ID.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) newRegion = RectangularRegion(x1=0, y1=0, x2=100, y2=100) newRegion.id = None with self.assertRaises(ValueError): unit.replaceRegion(newRegion)
def test_exitExcludedRegion_zIncreased(self): """Test exitExcludedRegion when the final Z is greater than the initial Z.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.excluding = True unit.excludeStartTime = time.time() unit.feedRate = 1000 unit.feedRateUnitMultiplier = 1 unit.lastPosition = create_position(x=1, y=2, z=3, extruderPosition=4) unit.position = create_position(x=10, y=20, z=30, extruderPosition=40) with mock.patch.object( unit, '_processPendingCommands') as mockProcessPendingCommands: mockProcessPendingCommands.return_value = ["pendingCommand"] result = unit.exitExcludedRegion("G1 X1 Y2") mockProcessPendingCommands.assert_called_with() self.assertEqual( result, [ "pendingCommand", "G92 E40", "G0 F1000 Z30", "G0 F1000 X10 Y20" ], "The result should be a list of the expected commands.") self.assertFalse(unit.excluding, "The excluding flag should be cleared.")
def _test_enterExcludedRegion_common(self, enteringExcludedRegionGcode): """Test common functionality of enterExcludedRegion when exclusion is enabled.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.excluding = False unit.excludeStartTime = "oldStartTime" unit.numExcludedCommands = 42 unit.numCommands = 84 unit.lastPosition = "oldPosition" unit.enteringExcludedRegionGcode = enteringExcludedRegionGcode result = unit.enterExcludedRegion("G1 X1 Y2") self.assertTrue(unit.excluding, "The excluding flag should be True") self.assertNotEqual(unit.excludeStartTime, "oldStartTime", "The excludeStartTime should be updated") self.assertEqual(unit.numExcludedCommands, 0, "The numExcludedCommands should be reset to 0") self.assertEqual(unit.numCommands, 0, "The numCommands should be reset to 0") self.assertNotEqual(unit.lastPosition, "oldPosition", "The position should be updated") return result
def test_isPointExcluded_noRegions(self): """Test the isPointExcluded method when no regions are defined.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) self.assertFalse( unit.isPointExcluded(0, 0), "(0,0) should NOT be excluded when no regions are defined") self.assertFalse( unit.isPointExcluded(10, 10), "(10,10) should NOT be excluded when no regions are defined")
def test_setAbsoluteMode_False_g90InfluencesExtruder(self): """Test the setAbsoluteMode method when passed False and g90InfluencesExtruder is True.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.g90InfluencesExtruder = True unit.position.setPositionAbsoluteMode(True) unit.position.setExtruderAbsoluteMode(True) unit.setAbsoluteMode(False) self._assertAbsoluteMode(unit, False, False)
def test_enableExclusion_exclusionEnabled(self): """Test the enableExclusion method when exclusion is already enabled.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.enableExclusion("Redundant enable for test") mockLogger.debug.assert_called_with( RegexMatcher("^Exclusion already enabled"), mock.ANY) self.assertTrue(unit.isExclusionEnabled(), "isExclusionEnabled should report True")
def test_processPendingCommands_noPendingCommands_noExitScript(self): """Test _processPendingCommands if no pending commands and no exit script.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.pendingCommands = OrderedDict() unit.exitingExcludedRegionGcode = None result = unit._processPendingCommands() # pylint: disable=protected-access self.assertEqual(unit.pendingCommands, OrderedDict(), "The pendingCommands should be an empty dict") self.assertEqual(result, [], "The result should be an empty list.")
def test_processExtendedGcode_noGcode_notExcluding(self): """Test processExtendedGcode when not excluding and no gcode provided.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) with mock.patch.object( unit, 'extendedExcludeGcodes') as mockExtendedExcludeGcodes: unit.excluding = False result = unit.processExtendedGcode("someCommand", None, None) mockExtendedExcludeGcodes.get.assert_not_called() self.assertIsNone(result, "The return value should be None")
def test_exitExcludedRegion_excluding(self): """Test exitExcludedRegion when already excluding.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.excluding = True unit.numCommands = 10 result = unit.enterExcludedRegion("G1 X1 Y2") self.assertEqual(unit.numCommands, 10, "The numCommands should not be updated.") self.assertEqual(result, [], "An empty list should be returned.")
def test_exitExcludedRegion_notExcluding(self): """Test exitExcludedRegion when not currently excluding.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.excluding = False with mock.patch.object( unit, '_processPendingCommands') as mockProcessPendingCommands: result = unit.exitExcludedRegion("G1 X1 Y2") mockProcessPendingCommands.assert_not_called() self.assertEqual(result, [], "An empty list should be returned.")
def test_ignoreGcodeCommand(self): """Test the ignoreGcodeCommand method.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.numExcludedCommands = 10 result = unit.ignoreGcodeCommand() self.assertEqual(result, IGNORE_GCODE_CMD, "ignoreGcodeCommand should return IGNORE_GCODE_CMD") self.assertEqual( unit.numExcludedCommands, 11, "ignoreGcodeCommand should increment numExcludedCommands")
def test_disableExclusion_exclusionEnabled_notExcluding( self, mockExitExcludedRegion): """Test the disableExclusion method when exclusion is enabled and not excluding.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) returnedCommands = unit.disableExclusion("Disable for test") self.assertFalse(unit.isExclusionEnabled(), "isExclusionEnabled should report False") mockExitExcludedRegion.assert_not_called() self.assertEqual(returnedCommands, [], "An empty list of commands should be returned")
def test_processExcludedMove_excluding_nonRetract(self): """Test _processExcludedMove with a non-retraction move and excluding=True.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.excluding = True with mock.patch.multiple(unit, enterExcludedRegion=mock.DEFAULT, _processNonMove=mock.DEFAULT) as mocks: result = unit._processExcludedMove("G1 X10 Y20", 0) # pylint: disable=protected-access mocks["enterExcludedRegion"].assert_not_called() mocks["_processNonMove"].assert_not_called() self.assertEqual(result, [], "The result should be an empty list")
def test_processExtendedGcodeEntry_EXCLUDE_ALL(self): """Test processExtendedGcodeEntry when the mode is EXCLUDE_ALL.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) unit.pendingCommands = OrderedDict() result = unit._processExtendedGcodeEntry( # pylint: disable=protected-access EXCLUDE_ALL, "G1 X1 Y2", "G1") self.assertEqual(unit.pendingCommands, OrderedDict(), "pendingCommands should not be updated.") self.assertEqual( result, (None, ), "The result should indicate to drop/ignore the command")
def test_recoverRetraction_noRecoverExcluded(self): """Test _recoverRetraction with recoverExcluded=False.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) with mock.patch.object(unit, 'lastRetraction') as lastRetractionMock: unit.lastRetraction.recoverExcluded = False result = unit._recoverRetraction("G11", True) # pylint: disable=protected-access lastRetractionMock.generateRecoverCommands.assert_not_called() self.assertIsNone(unit.lastRetraction, "The lastRetraction should be set to None") self.assertEqual(result, ["G11"], "The result should contain one item")
def test_replaceRegion_found_last(self): """Test the replaceRegion method when the region matches the last in the list.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) regionToMatch = RectangularRegion(x1=10, y1=10, x2=20, y2=20, id="matchId") otherRegion = RectangularRegion(x1=20, y1=20, x2=30, y2=30, id="otherId") newRegion = RectangularRegion(x1=0, y1=0, x2=100, y2=100, id="matchId") unit.addRegion(otherRegion) unit.addRegion(regionToMatch) unit.replaceRegion(newRegion) self.assertEqual( unit.excludedRegions, [otherRegion, newRegion], "The excluded regions should be updated by replaceRegion if the ID is found (last)" )
def test_deleteRegion_notFound(self): """Test the deleteRegion method when the specified region is not found.""" mockLogger = mock.Mock() unit = ExcludeRegionState(mockLogger) aRegion = RectangularRegion(x1=0, y1=0, x2=100, y2=100, id="anId") unit.addRegion(aRegion) self.assertFalse( unit.deleteRegion("notFound"), "deleteRegion should return False when the region is not found") self.assertEqual( unit.excludedRegions, [aRegion], "The excluded regions should not be modified by deleteRegion if the ID was not found" )