Java tutorial
/* Copyright 2013-2018 Will Winder This file is part of Universal Gcode Sender (UGS). UGS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. UGS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with UGS. If not, see <http://www.gnu.org/licenses/>. */ package com.willwinder.universalgcodesender; import com.willwinder.universalgcodesender.AbstractController.UnexpectedCommand; import com.willwinder.universalgcodesender.listeners.ControllerListener; import com.willwinder.universalgcodesender.listeners.MessageType; import com.willwinder.universalgcodesender.mockobjects.MockGrblCommunicator; import com.willwinder.universalgcodesender.model.UGSEvent.ControlState; import com.willwinder.universalgcodesender.model.UnitUtils; import com.willwinder.universalgcodesender.services.MessageService; import com.willwinder.universalgcodesender.types.GcodeCommand; import com.willwinder.universalgcodesender.utils.GUIHelpers; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import com.willwinder.universalgcodesender.utils.GcodeStreamReader; import com.willwinder.universalgcodesender.utils.GcodeStreamWriter; import com.willwinder.universalgcodesender.utils.Settings; import org.junit.After; import org.junit.Assert; import org.junit.Ignore; import static com.willwinder.universalgcodesender.GrblUtils.GRBL_PAUSE_COMMAND; import static com.willwinder.universalgcodesender.model.UGSEvent.ControlState.*; import com.willwinder.universalgcodesender.utils.GcodeStreamTest; import org.apache.commons.io.FileUtils; import org.junit.AfterClass; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** * * @author wwinder */ public class GrblControllerTest { private MockGrblCommunicator mgc; private static File tempDir; private Settings settings = new Settings(); public GrblControllerTest() { } @BeforeClass static public void setup() throws IOException { tempDir = GcodeStreamTest.createTempDirectory(); } @AfterClass static public void teardown() throws IOException { FileUtils.forceDeleteOnExit(tempDir); } @Before public void setUp() throws Exception { this.mgc = new MockGrblCommunicator(); // Initialize private variable. Field f = GUIHelpers.class.getDeclaredField("unitTestMode"); f.setAccessible(true); f.set(null, true); } @After public void tearDown() throws Exception { // Initialize private variable. Field f = GUIHelpers.class.getDeclaredField("unitTestMode"); f.setAccessible(true); f.set(null, false); } private static void setState(GrblController gc, ControlState state) { try { Method m = AbstractController.class.getDeclaredMethod("setCurrentState", ControlState.class); m.setAccessible(true); m.invoke(gc, state); } catch (Exception e) { Assert.fail(); } } private Settings getSettings() { return settings; } @Test public void testGetGrblVersion() throws Exception { System.out.println("getGrblVersion"); GrblController instance = new GrblController(mgc); String result; String expResult; expResult = "<Not connected>"; result = instance.getGrblVersion(); assertEquals(expResult, result); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); expResult = "Grbl 0.5b"; instance.rawResponseHandler(expResult); result = instance.getGrblVersion(); assertEquals(expResult, result); expResult = "Grbl 0.57"; instance.rawResponseHandler(expResult); result = instance.getGrblVersion(); assertEquals(expResult, result); expResult = "Grbl 0.8"; instance.rawResponseHandler(expResult); result = instance.getGrblVersion(); assertEquals(expResult, result); expResult = "Grbl 0.8c"; instance.rawResponseHandler(expResult); result = instance.getGrblVersion(); assertEquals(expResult, result); } /** * Test of numOpenCommPortCalls method, of class GrblController. */ @Test public void testOpenCommPort() { System.out.println("openCommPort/isCommOpen"); String port = "serialPort"; int portRate = 12345; GrblController instance = new GrblController(mgc); Boolean expResult = true; Boolean result = false; try { result = instance.openCommPort(getSettings().getConnectionDriver(), port, portRate); } catch (Exception e) { fail("Unexpected exception from GrblController: " + e.getMessage()); } assertEquals(expResult, result); assertEquals(expResult, instance.isCommOpen()); assertEquals(port, mgc.portName); assertEquals(portRate, mgc.portRate); String exception = ""; // Check exception trying to open the comm port twice. try { instance.openCommPort(getSettings().getConnectionDriver(), port, portRate); } catch (Exception e) { exception = e.getMessage(); } assertEquals("Comm port is already open.", exception); } /** * Test of numCloseCommPortCalls method, of class GrblController. */ @Test public void testCloseCommPort() { System.out.println("closeCommPort/isCommOpen"); GrblController instance = new GrblController(mgc); // Make sure comm is closed assertEquals(false, instance.isCommOpen()); Boolean result = false; try { // Test closing while already closed. result = instance.closeCommPort(); assertEquals(true, result); assertEquals(false, instance.isCommOpen()); // Test closed after opening thenc losing. instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); result = instance.closeCommPort(); } catch (Exception e) { fail("Unexpected exception from GrblController: " + e.getMessage()); } assertEquals(true, result); assertEquals(false, instance.isCommOpen()); } @Test public void testPerformHomingCycle() throws Exception { System.out.println("performHomingCycle"); String expResult; GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); boolean hitIt = false; try { instance.performHomingCycle(); } catch (Exception e) { hitIt = true; assert (e.getMessage().startsWith("No supported homing method for ")); } assertEquals(true, hitIt); instance.rawResponseHandler("Grbl 0.7"); assertEquals(2, mgc.numStreamCommandsCalls); hitIt = false; try { instance.performHomingCycle(); } catch (Exception e) { hitIt = true; assert (e.getMessage().startsWith("No supported homing method for this version.")); } assertEquals(true, hitIt); instance.rawResponseHandler("Grbl 0.8"); assertEquals(4, mgc.numStreamCommandsCalls); instance.performHomingCycle(); assertEquals(5, mgc.numStreamCommandsCalls); expResult = GrblUtils.GCODE_PERFORM_HOMING_CYCLE_V8 + "\n"; assertEquals(expResult, mgc.queuedString); instance.rawResponseHandler("Grbl 0.8c"); assertEquals(7, mgc.numStreamCommandsCalls); instance.performHomingCycle(); assertEquals(8, mgc.numStreamCommandsCalls); expResult = GrblUtils.GCODE_PERFORM_HOMING_CYCLE_V8C + "\n"; assertEquals(expResult, mgc.queuedString); instance.rawResponseHandler("Grbl 0.9"); assertEquals(10, mgc.numStreamCommandsCalls); instance.performHomingCycle(); assertEquals(11, mgc.numStreamCommandsCalls); expResult = GrblUtils.GCODE_PERFORM_HOMING_CYCLE_V8C + "\n"; assertEquals(expResult, mgc.queuedString); } /** * Test of issueSoftReset method, of class GrblController. */ @Test public void testIssueSoftReset() throws IOException, Exception { System.out.println("issueSoftReset"); GrblController instance = new GrblController(mgc); // Noop if called while comm is closed. instance.issueSoftReset(); // Did not send reset command to communicator or issue reset. assertEquals(0, mgc.sentBytes.size()); assertEquals(0, mgc.numSoftResetCalls); try { instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); } catch (Exception e) { fail("Unexpected exception from GrblController: " + e.getMessage()); } // Automatic soft reset assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); assertEquals(0, mgc.numSoftResetCalls); // Enable real time mode by sending correct GRBL version: instance.rawResponseHandler("Grbl 0.8c"); instance.issueSoftReset(); // Sent reset command to communicator and issued reset. assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); assertEquals(1, mgc.numSoftResetCalls); // GRBL version that might not have the command but I send it to anyway: mgc.resetInputsAndFunctionCalls(); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); instance.rawResponseHandler("Grbl 0.8a"); instance.issueSoftReset(); // This version doesn't support soft reset. assertEquals(0, mgc.numSoftResetCalls); // GRBL version that should not be sent the command: mgc.resetInputsAndFunctionCalls(); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); mgc.sentBytes.clear(); instance.rawResponseHandler("Grbl 0.7"); instance.issueSoftReset(); // Sent reset command to communicator and issued reset. assertEquals(0, mgc.sentBytes.size()); assertEquals(0, mgc.numSoftResetCalls); } /** * Test of isStreamingmethod, of class GrblController. */ @Test public void testIsStreaming() throws Exception { System.out.println("isStreaming"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.rawResponseHandler("Grbl 0.8c"); //$G and $$ get queued on startup assertEquals(2, mgc.numQueueStringForCommCalls); assertEquals(2, mgc.numStreamCommandsCalls); // By default nothing is streaming. Boolean expResult = false; Boolean result = instance.isStreaming(); assertEquals(expResult, result); // Test begining stream with no data to stream. expResult = false; boolean threwException = false; try { // instance.openCommPort("blah", 123); instance.beginStreaming(); } catch (Exception ex) { assertEquals("There are no commands queued for streaming.", ex.getMessage()); threwException = true; } assertTrue(threwException); result = instance.isStreaming(); assertEquals(expResult, result); GcodeCommand cmd = instance.createCommand("G0X1"); instance.queueCommand(cmd); try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } result = instance.isStreaming(); expResult = true; assertEquals(expResult, result); assertEquals(3, mgc.numQueueStringForCommCalls); assertEquals(3, mgc.numStreamCommandsCalls); // Wrap up streaming and make sure isStreaming switches back. GcodeCommand command = new GcodeCommand("G0X1"); // Whitespace removed. command.setSent(true); command.setResponse("ok"); try { instance.commandSent(command); instance.commandComplete(command.getCommandString()); } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command complete: " + ex.getMessage()); } result = instance.isStreaming(); expResult = false; assertEquals(expResult, result); } /** * Test of getSendDuration method, of class GrblController. */ @Test public void testGetSendDuration() throws Exception { System.out.println("getSendDuration"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.rawResponseHandler("Grbl 0.8c"); // Test 1. // Result when not sending and nothing has been sent. long expResult = 0L; long result = instance.getSendDuration(); assertEquals(expResult, result); // Test 2. // Result when stream has begun but not completed. instance.queueCommand(instance.createCommand("G0X1")); try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } try { // Sleep for 2 seconds Thread.sleep(2000); } catch (InterruptedException ex) { fail("Unexpected exception from Thread.sleep: " + ex.getMessage()); } // Send duration should be around 2 seconds. expResult = 2000L; result = instance.getSendDuration(); System.out.println("result: " + result); // Assert that result is within 0.5 seconds of expected value. assert (expResult <= result); assert (result <= (expResult + 500)); try { // Sleep for 2 seconds Thread.sleep(2000); } catch (InterruptedException ex) { fail("Unexpected exception from Thread.sleep: " + ex.getMessage()); } // Test 3. // Wrap up the send and check the duration. GcodeCommand command = new GcodeCommand("G0X1"); // Whitespace removed. command.setSent(true); command.setResponse("ok"); try { instance.commandSent(command); instance.commandComplete(command.getCommandString()); } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command complete: " + ex.getMessage()); } expResult = 4000L; result = instance.getSendDuration(); // Assert that result is within 0.5 seconds of expected value. assert (expResult <= result); assert (result <= (expResult + 500)); // Test 4. // Make sure the duration is no longer increasing. try { // Sleep for 2 seconds Thread.sleep(2000); } catch (InterruptedException ex) { fail("Unexpected exception from Thread.sleep: " + ex.getMessage()); } result = instance.getSendDuration(); // Assert that result is within 0.5 seconds of expected value. assert (expResult <= result); assert (result <= (expResult + 500)); } private void assertCounts(GrblController instance, int total, int sent, int remaining) { assertEquals(total, instance.rowsInSend()); assertEquals(sent, instance.rowsSent()); assertEquals(remaining, instance.rowsRemaining()); } /** * Test of rowsInSend method, of class GrblController. */ @Test public void testRowsAsteriskMethods() throws Exception { System.out.println("testRowsAsteriskMethods"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.rawResponseHandler("Grbl 0.8c"); // Test 1. // When not sending, no commands queues, everything should be zero. assertCounts(instance, 0, 0, 0); // Add 30 commands. for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { // instance.openCommPort("blah", 123); instance.beginStreaming(); mgc.areActiveCommands = true; } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } // Test 2. // 30 Commands queued, zero sent, 30 completed. assertCounts(instance, 30, 0, 30); // Test 3. // Sent 15 of them, none completed. try { for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0 X1"); command.setSent(true); command.setResponse("ok"); instance.commandSent(command); } } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command sent: " + ex.getMessage()); } assertCounts(instance, 30, 15, 30); // Test 4. // Complete 15 of them. try { for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0X1"); // Whitespace removed. command.setSent(true); command.setResponse("ok"); instance.commandComplete(command.getCommandString()); } } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command complete: " + ex.getMessage()); } assertCounts(instance, 30, 15, 15); // Test 5. // Finish sending/completing the remaining 15 commands. try { for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0 X1"); command.setSent(true); command.setResponse("ok"); instance.commandSent(command); instance.commandComplete(command.getCommandString()); } } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command complete: " + ex.getMessage()); } mgc.areActiveCommands = false; assertCounts(instance, 30, 30, 0); } /** * Test of numQueueStringForCommCalls method, of class GrblController. */ @Test public void testSendCommandImmediately() throws Exception { System.out.println("queueStringForComm"); String str = "G0 X0 "; GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 123); instance.rawResponseHandler("Grbl 0.8c"); //$G and $$ get queued on startup assertEquals(2, mgc.numQueueStringForCommCalls); assertEquals(2, mgc.numStreamCommandsCalls); GcodeCommand command = instance.createCommand(str); instance.sendCommandImmediately(command); assertEquals(3, mgc.numQueueStringForCommCalls); assertEquals(3, mgc.numStreamCommandsCalls); assertEquals(str + "\n", mgc.queuedString); } /** * Test of isReadyToStreamFile method, of class GrblController. */ @Test public void testIsReadyToStreamFile() throws Exception { System.out.println("isReadyToStreamFile"); GrblController instance = new GrblController(mgc); boolean asserted; // Test 1. Grbl has not yet responded. try { asserted = false; instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.isReadyToStreamFile(); } catch (Exception e) { asserted = true; assertEquals("Grbl has not finished booting.", e.getMessage()); } assertTrue(asserted); // Test 2. No streaming if comm isn't open. instance.closeCommPort(); //Since the rawResponseHandler call can't execute without the port open, this section doesn't work any longer // instance.rawResponseHandler("Grbl 0.8c"); // try { // asserted = false; // instance.isReadyToStreamFile(); // } catch (Exception e) { // asserted = true; // assertEquals("Cannot begin streaming, comm port is not open.", e.getMessage()); // } // assertTrue(asserted); // Test 3. Grbl ready, ready for send. instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.rawResponseHandler("Grbl 0.8c"); Boolean result = instance.isReadyToStreamFile(); assertEquals(true, result); // Test 4. Can't send during active command. instance.queueCommand(instance.createCommand("G0X0")); try { mgc.areActiveCommands = true; asserted = false; instance.isReadyToStreamFile(); } catch (Exception e) { asserted = true; assertEquals("Cannot stream while there are active commands: ", e.getMessage()); } assertTrue(asserted); } /** * Test of preprocessAndAppendGcodeCommand method, of class GrblController. */ @Test public void testAppendGcodeCommand() { System.out.println("preprocessAndAppendGcodeCommand"); // This is fully tested by other tests. } /** * Test of appendGcodeFile method, of class GrblController. */ @Test public void testAppendGcodeFile() throws Exception { System.out.println("appendGcodeFile"); //File file = null; //GrblController instance = new GrblController(mgc); //instance.appendGcodeFile(file); // Not testing file inputs now. } /** * Test of beginStreaming method, of class GrblController. */ @Test public void testBeginStreaming() throws Exception { System.out.println("beginStreaming"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); instance.rawResponseHandler("Grbl 0.8c"); //$G and $$ get queued on startup assertEquals(2, mgc.numQueueStringForCommCalls); // Test 1. No commands to stream. boolean caughtException = false; try { instance.beginStreaming(); } catch (Exception e) { caughtException = true; assertEquals("There are no commands queued for streaming.", e.getMessage()); } assertTrue(caughtException); // Test 2. Command already streaming. instance.queueCommand(instance.createCommand("G0X1")); caughtException = false; try { // Trigger the error. instance.beginStreaming(); } catch (Exception ex) { caughtException = true; assertEquals("Cannot stream while there are active commands (controller).", ex.getMessage()); } assertFalse(caughtException); assertEquals(3, mgc.numQueueStringForCommCalls); // Wrap up test 2. GcodeCommand command = new GcodeCommand("G0X1"); // Whitespace removed. command.setSent(true); command.setResponse("ok"); instance.commandSent(command); instance.commandComplete(command.getCommandString()); // Test 3. Stream some commands and make sure they get sent. for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { // Trigger the error. instance.beginStreaming(); } catch (Exception ex) { caughtException = true; assertEquals("Cannot stream while there are active commands (controller).", ex.getMessage()); } assertFalse(caughtException); assertEquals(30, instance.rowsRemaining()); assertEquals(33, mgc.numQueueStringForCommCalls); // Wrap up test 3. for (int i = 0; i < 30; i++) { command.setCommand("G0X" + i); instance.commandSent(command); instance.commandComplete(command.getCommandString()); } } /** * Test of pauseStreaming method, of class GrblController. */ @Test public void testPauseStreaming() throws Exception { System.out.println("pauseStreaming"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); instance.pauseStreaming(); assertEquals(1, mgc.numPauseSendCalls); mgc.sentBytes.clear(); instance.rawResponseHandler("Grbl 0.7"); instance.pauseStreaming(); assertEquals(2, mgc.numPauseSendCalls); assertEquals(0, mgc.sentBytes.size()); instance.rawResponseHandler("Grbl 0.8c"); instance.pauseStreaming(); assertEquals(3, mgc.numPauseSendCalls); assertEquals(new Byte(GrblUtils.GRBL_PAUSE_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); } /** * Test of resumeStreaming method, of class GrblController. */ @Test public void testResumeStreaming() throws Exception { System.out.println("resumeStreaming"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); instance.resumeStreaming(); assertEquals(1, mgc.numResumeSendCalls); instance.rawResponseHandler("Grbl 0.7"); instance.resumeStreaming(); assertEquals(2, mgc.numResumeSendCalls); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); instance.rawResponseHandler("Grbl 0.8c"); instance.resumeStreaming(); assertEquals(3, mgc.numResumeSendCalls); assertEquals(new Byte(GrblUtils.GRBL_RESUME_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); } private static void wrapUp(GrblController gc, int numCommands) { // wrap up try { GcodeCommand command = new GcodeCommand("blah"); command.setSent(true); command.setResponse("ok"); for (int i = 0; i < numCommands; i++) { gc.commandComplete(command.getCommandString()); } } catch (Exception ex) { fail("Unexpected exception testing cancelSend: " + ex.getMessage()); } } /** * Test of numCancelSendCalls method, of class GrblController. */ @Test public void testCancelSend() throws Exception { System.out.println("cancelSend"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); // 0. Test GRBL not returning to idle during cancel. instance.rawResponseHandler("Grbl 0.8c"); instance.cancelSend(); for (int i = 0; i < 50; i++) { instance.rawResponseHandler("<Running,MPos:1.0,2.0,3.0>"); } assertEquals(1, mgc.numPauseSendCalls); assertEquals(1, mgc.numCancelSendCalls); assertEquals(0, mgc.numSoftResetCalls); instance.resumeStreaming(); setState(instance, COMM_IDLE); // Test 1.1 Cancel when nothing is running (Grbl 0.7). instance.rawResponseHandler("Grbl 0.7"); instance.cancelSend(); assertEquals(2, mgc.numCancelSendCalls); assertEquals(0, mgc.numSoftResetCalls); // Test 1.2 Cancel when nothing is running (Grbl 0.8c). // Check for soft reset. instance.rawResponseHandler("Grbl 0.8c"); instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(3, mgc.numCancelSendCalls); assertEquals(2, mgc.numPauseSendCalls); assertEquals(1, mgc.numSoftResetCalls); instance.resumeStreaming(); // Test 2.1 // Add 30 commands, start send, cancel before any sending. (Grbl 0.7) instance.rawResponseHandler("Grbl 0.7"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } instance.cancelSend(); assertEquals(4, mgc.numCancelSendCalls); assertEquals(2, mgc.numPauseSendCalls); assertEquals(1, mgc.numSoftResetCalls); assertEquals(30, instance.rowsInSend()); assertEquals(30, instance.rowsRemaining()); // Test 2.2 // Add 30 commands, start send, cancel before any sending. (Grbl 0.8c) //setUp(); //instance = new GrblController(mgc); instance.rawResponseHandler("Grbl 0.8c"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(0, instance.rowsInSend()); assertEquals(0, instance.rowsRemaining()); assertEquals(5, mgc.numCancelSendCalls); assertEquals(3, mgc.numPauseSendCalls); assertEquals(2, mgc.numSoftResetCalls); instance.resumeStreaming(); // Test 3.1 // Add 30 commands, start send, cancel after sending 15. (Grbl 0.7) instance.rawResponseHandler("Grbl 0.7"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X0")); } try { instance.beginStreaming(); for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0X0"); command.setSent(true); command.setResponse("ok"); instance.commandSent(command); } } catch (Exception ex) { fail("Unexpected exception from command sent: " + ex.getMessage()); } instance.cancelSend(); assertEquals(6, mgc.numCancelSendCalls); assertEquals(3, mgc.numPauseSendCalls); assertEquals(2, mgc.numSoftResetCalls); assertEquals(30, instance.rowsInSend()); assertEquals(30, instance.rowsRemaining()); // wrap up wrapUp(instance, 15); // Test 3.2 // Add 30 commands, start send, cancel after sending 15. (Grbl 0.8c) instance.rawResponseHandler("Grbl 0.8c"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0 X1"); command.setSent(true); command.setResponse("ok"); instance.commandSent(command); } } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command sent: " + ex.getMessage()); } instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(15, instance.rowsSent()); assertEquals(0, instance.rowsInSend()); assertEquals(0, instance.rowsRemaining()); assertEquals(7, mgc.numCancelSendCalls); assertEquals(4, mgc.numPauseSendCalls); assertEquals(3, mgc.numSoftResetCalls); assertEquals(new Byte(GrblUtils.GRBL_RESET_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); instance.resumeStreaming(); } @Test public void testPauseAndCancelSend() throws Exception { System.out.println("Pause + cancelSend"); GrblController instance = new GrblController(mgc); setState(instance, COMM_SENDING); instance.openCommPort(getSettings().getConnectionDriver(), "blah", 1234); // Test 1.1 cancel throws an exception (Grbl 0.7). instance.rawResponseHandler("Grbl 0.7"); boolean threwException = false; try { instance.pauseStreaming(); instance.cancelSend(); } catch (Exception ex) { threwException = true; } assertTrue(threwException); assertEquals(0, mgc.numCancelSendCalls); instance.resumeStreaming(); // Test 1.2 Cancel when nothing is running (Grbl 0.8c). // Check for soft reset. instance.rawResponseHandler("Grbl 0.8c"); instance.pauseStreaming(); instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(1, mgc.numCancelSendCalls); assertEquals(1, mgc.numSoftResetCalls); instance.resumeStreaming(); // Test 2.1 // Add 30 commands, start send, cancel before any sending. (Grbl 0.7) instance.rawResponseHandler("Grbl 0.7"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } instance.pauseStreaming(); boolean exceptionThrown = false; try { instance.cancelSend(); } catch (Exception e) { exceptionThrown = true; } assertTrue(exceptionThrown); assertEquals(30, instance.rowsInSend()); // Note: It is hoped that one day cancel will proactively clear out the // in progress commands. But that day is not today. assertEquals(30, instance.rowsRemaining()); instance.resumeStreaming(); instance.cancelSend(); // Test 2.2 // Add 30 commands, start send, cancel before any sending. (Grbl 0.8c) //setUp(); //instance = new GrblController(mgc); instance.rawResponseHandler("Grbl 0.8c"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); } catch (Exception ex) { fail("Unexpected exception from GrblController: " + ex.getMessage()); } instance.pauseStreaming(); instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(0, instance.rowsInSend()); assertEquals(0, instance.rowsRemaining()); instance.resumeStreaming(); // Test 3.1 - N/A, exception thrown. // Test 3.2 // Add 30 commands, start send, cancel after sending 15. (Grbl 0.8c) instance.rawResponseHandler("Grbl 0.8c"); for (int i = 0; i < 30; i++) { instance.queueCommand(instance.createCommand("G0X" + i)); } try { instance.beginStreaming(); for (int i = 0; i < 15; i++) { GcodeCommand command = new GcodeCommand("G0 X1"); command.setSent(true); command.setResponse("ok"); instance.commandSent(command); } } catch (Exception ex) { ex.printStackTrace(); fail("Unexpected exception from command sent: " + ex.getMessage()); } instance.pauseStreaming(); instance.cancelSend(); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); instance.rawResponseHandler("<Hold,MPos:1.0,2.0,3.0>"); assertEquals(15, instance.rowsSent()); assertEquals(0, instance.rowsInSend()); // Left this failing because it should be possible to make it work // this way someday. assertEquals(0, instance.rowsRemaining()); } /** * Test of commandComplete method, of class GrblController. */ @Test public void testCommandComplete() { System.out.println("commandComplete"); GcodeCommand command = null; GrblController instance = new GrblController(mgc); // Test 1. Complete a command that was marked as sent but never declared // within commandSent(command). command = new GcodeCommand("blah"); command.setSent(true); boolean hitException = false; try { instance.commandComplete(command.getCommandString()); } catch (UnexpectedCommand ex) { hitException = true; } assertEquals(true, hitException); // TODO: Test that command complete triggers a listener event. // TODO: Test that command complete triggers fileStreamComplete. } /** * Test of messageForConsole method, of class GrblController. */ @Test public void testDispatchConsoleInfoMessage() { String msg = "test message"; GrblController instance = new GrblController(mgc); MessageService messageService = mock(MessageService.class); instance.setMessageService(messageService); instance.dispatchConsoleMessage(MessageType.INFO, msg); verify(messageService, times(1)).dispatchMessage(MessageType.INFO, msg); } /** * Test of verboseMessageForConsole method, of class GrblController. */ @Test public void testDispatchConsoleVerboseMessage() { String msg = "test message"; GrblController instance = new GrblController(mgc); MessageService messageService = mock(MessageService.class); instance.setMessageService(messageService); instance.dispatchConsoleMessage(MessageType.VERBOSE, msg); verify(messageService, times(1)).dispatchMessage(MessageType.VERBOSE, msg); } /** * Test of rawResponseListener method, of class GrblController. */ @Test public void testRawResponseListener() throws Exception { System.out.println("rawResponseListener"); GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 0.8c"); // TODO: Test that ok/error trigger listener events. // TODO: Test that version strings update versions. // TODO: Test that status strings trigger both listener events // (verbose console and position event) } /** * Test of rawResponseListener method, of class GrblController. */ @Ignore("This has problems on the CI server.") public void testPolling() { System.out.println("testPolling (via rawResponseListener)"); GrblController instance = new GrblController(mgc); // Test 1. Check that polling works. (Grbl 0.8c) instance.rawResponseHandler("Grbl 0.8c"); try { // Enough time for a few polling callsthe next poll to be sent. Thread.sleep(600); } catch (InterruptedException ex) { fail("Unexpected exception while testing rawResponseListener: " + ex.getMessage()); } assertTrue(1 <= mgc.numSendByteImmediatelyCalls); //assertEquals(1, mgc.numSendByteImmediatelyCalls); assertEquals(new Byte(GrblUtils.GRBL_STATUS_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); // Test 2. Check that another poll is sent shortly after receiving a // status message. instance.rawResponseHandler("<blah blah blah>"); try { // Enough time for a few polling callsthe next poll to be sent. Thread.sleep(1000); } catch (InterruptedException ex) { fail("Unexpected exception while testing rawResponseListener: " + ex.getMessage()); } assertEquals(2, mgc.numSendByteImmediatelyCalls); assertEquals(new Byte(GrblUtils.GRBL_STATUS_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); // Test 3. Check that after a long enough delay, additional polls are // sent even without responses. try { // Enough time for a few polling callsthe next poll to be sent. Thread.sleep(5000); } catch (InterruptedException ex) { fail("Unexpected exception while testing rawResponseListener: " + ex.getMessage()); } assert (2 < mgc.numSendByteImmediatelyCalls); assertEquals(new Byte(GrblUtils.GRBL_STATUS_COMMAND), mgc.sentBytes.get(mgc.sentBytes.size() - 1)); } /** * Test of jogMachine method, of class AbstractController. */ @Test public void testJogMachine() throws Exception { System.out.println("jogMachine"); GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); // Abstract controller should be used when grbl jog mode is disabled. instance.rawResponseHandler("Grbl 0.8c"); instance.jogMachine(-1, 0, 1, 10, 11, UnitUtils.Units.INCH); assertEquals(mgc.queuedStrings.get(2), "G20G91G1X-10Z10F11\n"); assertEquals(mgc.queuedStrings.get(3), "G90 G21 \n"); instance.jogMachine(0, 1, 0, 10, 11, UnitUtils.Units.MM); assertEquals(mgc.queuedStrings.get(4), "G21G91G1Y10F11\n"); assertEquals(mgc.queuedStrings.get(5), "G90 G21 \n"); instance.rawResponseHandler("Grbl 1.1a"); instance.jogMachine(-1, 0, 1, 10, 11, UnitUtils.Units.INCH); assertEquals(mgc.queuedStrings.get(8), "$J=G20G91X-10Z10F11\n"); instance.jogMachine(0, 1, 0, 10, 11, UnitUtils.Units.MM); assertEquals(mgc.queuedStrings.get(9), "$J=G21G91Y10F11\n"); } /** * Test of addListener method, of class GrblController. */ @Test public void testAddListener() { System.out.println("addListener"); ControllerListener cl = null; GrblController instance = new GrblController(mgc); instance.addListener(cl); // TODO: Test that (multiple?) listener events work. } @Test public void testReturnToHomeWhenZIsPositive() throws Exception { // Set up GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 0.8c"); instance.rawResponseHandler("<Idle,MPos:1.000,1.000,1.000,WPos:0.0,0.0,0.0>"); // Test the function for going home instance.returnToHome(); assertEquals(4, mgc.queuedStrings.size()); assertEquals("View all grbl settings", "$$\n", mgc.queuedStrings.get(0)); assertEquals("View gcode parser state", "$G\n", mgc.queuedStrings.get(1)); assertEquals("Go to XY-zero", "G90 G0 X0 Y0\n", mgc.queuedStrings.get(2)); assertEquals("Go to Z-zero", "G90 G0 Z0\n", mgc.queuedStrings.get(3)); } @Test public void testReturnToHomeWhenWorkPositionZIsNegative() throws Exception { // Set up GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 0.8c"); instance.rawResponseHandler("<Idle,MPos:1.000,1.000,1.000,WPos:0.0,0.0,-1.0>"); // Test the function for going home instance.returnToHome(); assertEquals(5, mgc.queuedStrings.size()); assertEquals("View all grbl settings", "$$\n", mgc.queuedStrings.get(0)); assertEquals("View gcode parser state", "$G\n", mgc.queuedStrings.get(1)); assertEquals("The machine is in the material, go to zero with the Z axis first", "G90 G0 Z0\n", mgc.queuedStrings.get(2)); assertEquals("Go to XY-zero", "G90 G0 X0 Y0\n", mgc.queuedStrings.get(3)); assertEquals("Go to Z-zero", "G90 G0 Z0\n", mgc.queuedStrings.get(4)); } @Test public void rawResponseHandlerWithKnownErrorShouldWriteMessageToConsole() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.commandSent(new GcodeCommand("G0")); MessageService messageService = mock(MessageService.class); instance.setMessageService(messageService); // When instance.rawResponseHandler("error:1"); //Then String genericErrorMessage = "Error while processing response <error:1>\n"; verify(messageService, times(0)).dispatchMessage(MessageType.ERROR, genericErrorMessage); String errorMessage = "An error was detected while sending 'G0': (error:1) G-code words consist of a letter and a value. Letter was not found. Streaming has been paused.\n"; verify(messageService).dispatchMessage(MessageType.ERROR, errorMessage); verify(messageService, times(1)).dispatchMessage(any(), anyString()); assertFalse(instance.getActiveCommand().isPresent()); } @Test public void rawResponseHandlerWithUnknownErrorShouldWriteGenericMessageToConsole() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.commandSent(new GcodeCommand("G21")); MessageService messageService = mock(MessageService.class); instance.setMessageService(messageService); // When instance.rawResponseHandler("error:18"); // Then String genericErrorMessage = "An error was detected while sending 'G21': (error:18) An unknown error has occurred. Streaming has been paused.\n"; verify(messageService, times(1)).dispatchMessage(MessageType.ERROR, genericErrorMessage); verify(messageService, times(1)).dispatchMessage(any(), anyString()); assertFalse(instance.getActiveCommand().isPresent()); } @Test public void rawResponseHandlerOnErrorWithNoSentCommandsShouldSendMessageToConsole() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); MessageService messageService = mock(MessageService.class); instance.setMessageService(messageService); // When instance.rawResponseHandler("error:1"); // Then String genericErrorMessage = "An unexpected error was detected: (error:1) G-code words consist of a letter and a value. Letter was not found.\n"; verify(messageService, times(1)).dispatchMessage(MessageType.INFO, genericErrorMessage); verify(messageService, times(1)).dispatchMessage(any(), anyString()); assertFalse(instance.getActiveCommand().isPresent()); } @Test public void controllerShouldBeIdleWhenInCheckMode() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 1.1f"); // We will assume that we are using version Grbl 1.0 with streaming support instance.rawResponseHandler("<Hold|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); assertFalse("We should start with a non idle state", instance.isIdle()); // When instance.rawResponseHandler("<Check|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); // Then assertTrue(instance.isIdle()); assertTrue(instance.isIdleEvent()); assertEquals(COMM_CHECK, instance.getControlState()); } @Test public void versionStringShouldResetStatus() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 1.1f"); instance.rawResponseHandler("<Run|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); assertEquals("We should be in sending mode", COMM_SENDING, instance.getControlState()); // When instance.rawResponseHandler("Grbl 1.1f"); // Then assertEquals(COMM_IDLE, instance.getControlState()); } /** * When exiting check mode the controller does a soft reset and sends a new version string. The * default behavior is to reset the controller status. But we need it to determine if single * step mode is supposed to be activated. */ @Test public void versionStringShouldNotResetStatusWhenInCheckMode() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 1.1f"); instance.rawResponseHandler("<Check|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); assertEquals("We should be in check mode", COMM_CHECK, instance.getControlState()); // When instance.rawResponseHandler("Grbl 1.1f"); // Then assertEquals(COMM_CHECK, instance.getControlState()); } @Test public void controllerShouldHaveStateRunningWhenStreamingAndInCheckMode() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 1.1f"); // We will assume that we are using version Grbl 1.0 with streaming support instance.rawResponseHandler("<Check|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); assertTrue(instance.isIdle()); // Create a gcode file stream File gcodeFile = new File(tempDir, "gcodeFile"); GcodeStreamWriter gcodeStreamWriter = new GcodeStreamWriter(gcodeFile); gcodeStreamWriter.addLine("G0", "G0", null, 0); gcodeStreamWriter.addLine("G0", "G0", null, 0); gcodeStreamWriter.close(); // When instance.queueStream(new GcodeStreamReader(gcodeFile)); instance.beginStreaming(); // Then assertFalse(instance.isIdle()); assertFalse(instance.isPaused()); assertEquals(COMM_SENDING, instance.getControlState()); } @Test public void controllerShouldBeIdleWhenInCheckModeWithOldStatusFormat() throws Exception { // Given GrblController instance = new GrblController(mgc); instance.setDistanceModeCode("G90"); instance.setUnitsCode("G21"); instance.openCommPort(getSettings().getConnectionDriver(), "foo", 2400); instance.rawResponseHandler("Grbl 0.8c"); // We will assume that we are using version Grbl without streaming support instance.rawResponseHandler("<Hold,MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); assertFalse("We should start with a non idle state", instance.isIdle()); // When instance.rawResponseHandler("<Check,MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); // Then assertTrue(instance.isIdle()); assertTrue(instance.isIdleEvent()); assertEquals(COMM_CHECK, instance.getControlState()); } @Test public void errorInCheckModeNotSending() throws Exception { // Given AbstractCommunicator communicator = mock(AbstractCommunicator.class); GrblController gc = new GrblController(communicator); gc.rawResponseHandler("Grbl 1.1f"); // We will assume that we are using version Grbl 1.0 with streaming support gc.rawResponseHandler("<Check|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); // When gc.communicatorPausedOnError(); gc.rawResponseHandler("error:1"); // Then assertEquals(gc.getControlState(), COMM_CHECK); assertFalse(gc.isPaused()); verify(communicator, times(1)).resumeSend(); } @Test public void errorInCheckModeSending() throws Exception { // Given AbstractCommunicator communicator = mock(AbstractCommunicator.class); ControllerListener controllerListener = mock(ControllerListener.class); GrblController gc = new GrblController(communicator); gc.addListener(controllerListener); gc.rawResponseHandler("Grbl 1.1f"); // We will assume that we are using version Grbl 1.0 with streaming support gc.rawResponseHandler("<Check|MPos:0.000,0.000,0.000|FS:0,0|Pn:XYZ>"); doReturn(true).when(communicator).isCommOpen(); // When gc.queueCommand(new GcodeCommand("G0 X10")); gc.beginStreaming(); gc.communicatorPausedOnError(); gc.rawResponseHandler("error:1"); // Then assertEquals(COMM_SENDING, gc.getControlState()); assertFalse(gc.isPaused()); verify(communicator, times(1)).sendByteImmediately(GRBL_PAUSE_COMMAND); verify(controllerListener, times(1)).controlStateChange(COMM_SENDING_PAUSED); } }