/*
Copywrite 2015-2016 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.gcode.GcodeCommandCreator;
import com.willwinder.universalgcodesender.listeners.ControllerListener;
import com.willwinder.universalgcodesender.model.UnitUtils;
import com.willwinder.universalgcodesender.types.GcodeCommand;
import com.willwinder.universalgcodesender.utils.GcodeStreamReader;
import com.willwinder.universalgcodesender.utils.GcodeStreamTest;
import com.willwinder.universalgcodesender.utils.GcodeStreamWriter;
import java.io.File;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import org.easymock.Capture;
import org.easymock.EasyMock;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.anyString;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.newCapture;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import org.easymock.IMockBuilder;
import org.hamcrest.CoreMatchers;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Ignore;
/**
*
* @author wwinder
*/
public class AbstractControllerTest {
public AbstractControllerTest() {
}
final static AbstractCommunicator mockCommunicator = EasyMock.createMock(AbstractCommunicator.class);
final static ControllerListener mockListener = EasyMock.createMock(ControllerListener.class);
final static GcodeCommandCreator gcodeCreator = new GcodeCommandCreator();
static AbstractController instance;
static AbstractController niceInstance;
static IMockBuilder<AbstractController> instanceBuilder;
static File tempDir = null;
//@BeforeClass
public static void init() throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, IOException {
instanceBuilder = EasyMock
.createMockBuilder(AbstractController.class)
.addMockedMethods(
"closeCommBeforeEvent",
"closeCommAfterEvent",
"openCommAfterEvent",
"cancelSendBeforeEvent",
"cancelSendAfterEvent",
"pauseStreamingEvent",
"resumeStreamingEvent",
"isReadyToStreamCommandsEvent",
"isReadyToSendCommandsEvent",
"rawResponseHandler",
"statusUpdatesEnabledValueChanged",
"statusUpdatesRateValueChanged",
"isCommOpen")
.withConstructor(AbstractCommunicator.class)
.withArgs(mockCommunicator);
instance = instanceBuilder.createMock();
niceInstance = instanceBuilder.createNiceMock();
// Initialize private variable.
Field f = AbstractController.class.getDeclaredField("commandCreator");
f.setAccessible(true);
f.set(instance, gcodeCreator);
f.set(niceInstance, gcodeCreator);
instance.addListener(mockListener);
}
@BeforeClass
static public void setup() throws IOException {
tempDir = GcodeStreamTest.createTempDirectory();
}
@AfterClass
static public void teardown() throws IOException {
FileUtils.forceDelete(tempDir);
}
@Before
public void setUp() throws Exception {
// AbstractCommunicator calls a function on mockCommunicator that I
// don't want to deal with.
EasyMock.reset(mockCommunicator, mockListener);
init();
EasyMock.reset(mockCommunicator, mockListener);
}
///////////////
// UTILITIES //
///////////////
public void openInstanceExpectUtility(String port, int portRate) throws Exception {
instance.openCommAfterEvent();
EasyMock.expect(EasyMock.expectLastCall()).anyTimes();
mockListener.messageForConsole(anyObject(), EasyMock.anyString());
EasyMock.expect(EasyMock.expectLastCall()).anyTimes();
EasyMock.expect(mockCommunicator.openCommPort(port, portRate)).andReturn(true).once();
EasyMock.expect(instance.isCommOpen()).andReturn(false).once();
EasyMock.expect(instance.isCommOpen()).andReturn(true).anyTimes();
}
private void streamInstanceExpectUtility() throws Exception {
EasyMock.expect(mockCommunicator.areActiveCommands()).andReturn(false).anyTimes();
instance.isReadyToStreamCommandsEvent();
EasyMock.expect(EasyMock.expectLastCall()).once();
mockCommunicator.streamCommands();
EasyMock.expect(EasyMock.expectLastCall()).once();
}
private void startStreamExpectation(String port, int rate, String command) throws Exception {
openInstanceExpectUtility(port, rate);
streamInstanceExpectUtility();
// Making sure the commands get queued.
mockCommunicator.queueStringForComm(command + "\n");
EasyMock.expect(EasyMock.expectLastCall()).times(2);
}
private void startStream(String port, int rate, String command) throws Exception {
// Open port, send some commands, make sure they are streamed.
instance.openCommPort(port, rate);
instance.queueCommand(instance.createCommand(command));
instance.queueCommand(instance.createCommand(command));
instance.beginStreaming();
}
/**
* Test of getCommandCreator method, of class AbstractController.
*/
@Test
public void testGetCommandCreator() {
System.out.println("getCommandCreator");
GcodeCommandCreator result = instance.getCommandCreator();
assertEquals(gcodeCreator, result);
}
/**
* Test of openCommPort method, of class AbstractController.
*/
@Test
@Ignore
public void testOpenCommPort() throws Exception {
System.out.println("openCommPort");
String port = "";
int portRate = 0;
instance.openCommAfterEvent();
EasyMock.expect(EasyMock.expectLastCall()).once();
mockListener.messageForConsole(anyObject(), anyString());
EasyMock.expect(EasyMock.expectLastCall()).once();
EasyMock.expect(mockCommunicator.openCommPort(port, portRate)).andReturn(true).once();
EasyMock.replay(instance, mockCommunicator, mockListener);
Boolean expResult = true;
Boolean result = instance.openCommPort(port, portRate);
assertEquals(expResult, result);
boolean threw = false;
try {
instance.openCommPort(port, portRate);
} catch (Exception e) {
threw = true;
}
assertEquals("Cannot open a comm port twice.", true, threw);
EasyMock.verify(instance, mockCommunicator, mockListener);
}
/**
* Test of closeCommPort method, of class AbstractController.
*/
@Test
@Ignore
public void testCloseCommPort() throws Exception {
System.out.println("closeCommPort");
String port = "/some/port";
int baud = 1234;
// Events
instance.openCommAfterEvent();
EasyMock.expect(EasyMock.expectLastCall()).once();
instance.closeCommBeforeEvent();
EasyMock.expect(EasyMock.expectLastCall()).once();
instance.closeCommAfterEvent();
EasyMock.expect(EasyMock.expectLastCall()).once();
// Message for open and close.
mockListener.messageForConsole(anyObject(), anyString());
EasyMock.expect(EasyMock.expectLastCall()).times(2);
EasyMock.expect(mockCommunicator.openCommPort(port, baud)).andReturn(true).once();
mockCommunicator.closeCommPort();
EasyMock.expect(EasyMock.expectLastCall()).once();
EasyMock.replay(instance, mockCommunicator, mockListener);;
// Close a closed port.
Boolean result = instance.closeCommPort();
assertEquals(true, result);
// Open port to close it.
result = instance.openCommPort(port, baud);
assertEquals(result, result);
// Close an open port.
result = instance.closeCommPort();
assertEquals(true, result);
}
/**
* Test of isCommOpen method, of class AbstractController.
*/
@Test
@Ignore
public void testIsCommOpen() throws Exception {
System.out.println("isCommOpen");
EasyMock.expect(mockCommunicator.openCommPort("port", 1234)).andReturn(true);
mockCommunicator.closeCommPort();
EasyMock.expect(EasyMock.expectLastCall());
EasyMock.replay(mockCommunicator);
assertEquals(false, instance.isCommOpen());
instance.openCommPort("port", 1234);
assertEquals(true, instance.isCommOpen());
instance.closeCommPort();
assertEquals(false, instance.isCommOpen());
}
/**
* Test of setStatusUpdatesEnabled method, of class AbstractController.
*/
@Test
@Ignore
public void testStatusUpdates() {
System.out.println("testStatusUpdates");
boolean enabled = false;
instance.setStatusUpdatesEnabled(enabled);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
/**
* Test of isStreamingFile method, of class AbstractController.
*/
@Test
public void testIsStreaming() throws Exception {
System.out.println("isStreaming");
assertEquals(false, instance.isStreaming());
testQueueCommands();
assertEquals(true, instance.isStreaming());
}
/**
* Test of getSendDuration method, of class AbstractController.
*/
@Test
public void testGetSendDuration() throws Exception {
System.out.println("getSendDuration");
String command = "command";
String port = "/some/port";
int rate = 1234;
startStreamExpectation(port, rate, command);
EasyMock.replay(instance, mockCommunicator);
// Time starts at zero when nothing has been sent.
assertEquals(0L, instance.getSendDuration());
startStream(port, rate, command);
long start = System.currentTimeMillis();
Thread.sleep(1000);
long time = instance.getSendDuration();
long checkpoint = System.currentTimeMillis();
// Began streaming at least 1 second ago.
assertTrue( time > (start-checkpoint));
Thread.sleep(1000);
instance.commandSent(new GcodeCommand(command));
instance.commandSent(new GcodeCommand(command));
instance.commandComplete(command);
instance.commandComplete(command);
time = instance.getSendDuration();
checkpoint = System.currentTimeMillis();
// Completed commands after at least "checkpoint" milliseconds.
assertTrue( time > (start-checkpoint));
Thread.sleep(1000);
// Make sure the time stopped after the last command was completed.
long newtime = instance.getSendDuration();
assertEquals( time, newtime );
EasyMock.verify(mockCommunicator, instance);
}
/**
* Test of rowsInSend method, of class AbstractController.
*/
@Test
public void testRowStatFailure() throws Exception {
System.out.println("rowsStatExceptions");
testQueueRawStreamForComm();
Assert.assertThat(instance.rowsSent(), CoreMatchers.equalTo(-1));
Assert.assertThat(instance.rowsRemaining(), CoreMatchers.equalTo(-1));
Assert.assertThat(instance.rowsInSend(), CoreMatchers.equalTo(-1));
}
@Test
public void testRowStats() throws Exception {
testQueueStreamForComm();
Assert.assertThat(instance.rowsSent(), CoreMatchers.equalTo(0));
Assert.assertThat(instance.rowsRemaining(), CoreMatchers.equalTo(2));
Assert.assertThat(instance.rowsInSend(), CoreMatchers.equalTo(2));
}
/**
* Test of sendCommandImmediately method, of class AbstractController.
*/
@Test
@Ignore
public void testSendCommandImmediately() throws Exception {
System.out.println("sendCommandImmediately");
String str = "";
boolean threwException = false;
try {
instance.sendCommandImmediately(instance.createCommand(str));
} catch (Exception e) {
Assert.assertThat(e.getMessage(), CoreMatchers.startsWith("Cannot send command(s)"));
threwException = true;
}
Assert.assertTrue(threwException);
String command = "command";
String port = "/some/port";
int rate = 1234;
openInstanceExpectUtility(port, rate);
mockCommunicator.queueStringForComm(str + "\n");
expect(expectLastCall()).times(1);
mockCommunicator.streamCommands();
expect(expectLastCall()).times(1);
EasyMock.replay(instance, mockCommunicator);
instance.openCommPort(port, rate);
instance.sendCommandImmediately(instance.createCommand(str));
EasyMock.verify(mockCommunicator, instance);
}
/**
* Test of isReadyToStreamFile method, of class AbstractController.
*/
@Test
@Ignore
public void testIsReadyToStreamFile() throws Exception {
System.out.println("isReadyToStreamFile");
instance.isReadyToStreamCommandsEvent();
expect(expectLastCall()).times(3);
Boolean commPortNotOpen = false;
try {
Boolean result = instance.isReadyToStreamFile();
} catch (Exception e) {
assertTrue(e.getMessage().contains("comm port is not open"));
commPortNotOpen = true;
}
assertTrue(commPortNotOpen);
String command = "command";
String port = "/some/port";
int rate = 1234;
startStreamExpectation(port, rate, command);
replay(instance, mockCommunicator);
instance.openCommPort(port, rate);
assertEquals(true, instance.isReadyToStreamFile());
instance.queueCommand(instance.createCommand(command));
instance.queueCommand(instance.createCommand(command));
instance.beginStreaming();
Boolean alreadyStreaming = false;
try {
instance.isReadyToStreamFile();
} catch (Exception e) {
assertEquals("Already streaming.", e.getMessage());
alreadyStreaming = true;
}
assertTrue(alreadyStreaming);
}
/**
* Test of queueRawStream method, of class AbstractController.
*/
@Test
public void testQueueRawStreamForComm() throws Exception {
System.out.println("queueStream");
String command = "command";
Collection<String> commands = Arrays.asList(command, command);
String port = "/some/port";
int rate = 1234;
PipedReader in = new PipedReader();
PipedWriter out = new PipedWriter(in);
for(String i : commands) {
out.append(i);
}
openInstanceExpectUtility(port, rate);
streamInstanceExpectUtility();
// TODO Fix this
// Making sure the commands get queued.
mockCommunicator.queueRawStreamForComm(in);
EasyMock.expect(EasyMock.expectLastCall()).times(1);
EasyMock.replay(instance, mockCommunicator);
// Open port, send some commands, make sure they are streamed.
instance.openCommPort(port, rate);
instance.queueRawStream(in);
instance.beginStreaming();
EasyMock.verify(mockCommunicator, instance);
}
/**
* Test of queueStream method, of class AbstractController.
*/
@Test
public void testQueueStreamForComm() throws Exception {
System.out.println("queueStream");
String command = "command";
Collection<String> commands = Arrays.asList(command, command);
String port = "/some/port";
int rate = 1234;
File f = new File(tempDir,"gcodeFile");
try {
try (GcodeStreamWriter gsw = new GcodeStreamWriter(f)) {
for (String i : commands) {
gsw.addLine("blah", command, null, -1);
}
}
try (GcodeStreamReader gsr = new GcodeStreamReader(f)) {
openInstanceExpectUtility(port, rate);
streamInstanceExpectUtility();
// TODO Fix this
// Making sure the commands get queued.
mockCommunicator.queueStreamForComm(gsr);
EasyMock.expect(EasyMock.expectLastCall()).times(1);
EasyMock.replay(instance, mockCommunicator);
// Open port, send some commands, make sure they are streamed.
instance.openCommPort(port, rate);
instance.queueStream(gsr);
instance.beginStreaming();
}
EasyMock.verify(mockCommunicator, instance);
} finally {
FileUtils.forceDelete(f);
}
}
/**
* Test of queueCommand method, of class AbstractController.
*/
@Test
public void testQueueCommand() throws Exception {
System.out.println("queueCommand");
String command = "command";
String port = "/some/port";
int rate = 1234;
openInstanceExpectUtility(port, rate);
streamInstanceExpectUtility();
// Making sure the commands get queued.
mockCommunicator.queueStringForComm(command + "\n");
EasyMock.expect(EasyMock.expectLastCall()).times(2);
EasyMock.replay(instance, mockCommunicator);
// Open port, send some commands, make sure they are streamed.
instance.openCommPort(port, rate);
instance.queueCommand(instance.createCommand(command));
instance.queueCommand(instance.createCommand(command));
instance.beginStreaming();
EasyMock.verify(mockCommunicator, instance);
}
/**
* Test of queueCommands method, of class AbstractController.
*/
@Test
public void testQueueCommands() throws Exception {
System.out.println("queueCommands");
String command = "command";
String port = "/some/port";
int rate = 1234;
openInstanceExpectUtility(port, rate);
streamInstanceExpectUtility();
// Making sure the commands get queued.
mockCommunicator.queueStringForComm(command + "\n");
EasyMock.expect(EasyMock.expectLastCall()).times(2);
EasyMock.replay(instance, mockCommunicator);
// Open port, send some commands, make sure they are streamed.
instance.openCommPort(port, rate);
instance.queueCommand(instance.createCommand(command));
instance.queueCommand(instance.createCommand(command));
instance.beginStreaming();
EasyMock.verify(mockCommunicator, instance);
}
/**
* Test of beginStreaming method, of class AbstractController.
*/
@Test
public void testBeginStreaming() throws Exception {
System.out.println("beginStreaming");
System.out.println("-Covered by testQueueCommands-");
}
/**
* Test of pauseStreaming method, of class AbstractController.
*/
@Test
@Ignore
public void testPauseStreaming() throws Exception {
System.out.println("pauseStreaming");
instance.pauseStreaming();
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
/**
* Test of resumeStreaming method, of class AbstractController.
*/
@Test
@Ignore
public void testResumeStreaming() throws Exception {
System.out.println("resumeStreaming");
instance.resumeStreaming();
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
/**
* Test of cancelSend method, of class AbstractController.
*/
@Test
@Ignore
public void testCancelSend() throws Exception {
// This is covered pretty thoroughly in GrblControllerTest.
System.out.println("cancelSend");
instance.cancelSend();
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
/**
* Test of commandSent method, of class AbstractController.
*/
@Test
public void testCommandSent() throws Exception {
System.out.println("commandSent");
String port = "/some/port";
int baud = 1234;
String command = "command";
// Setup instance with commands buffered on the communicator.
startStreamExpectation(port, baud, command);
EasyMock.replay(instance, mockCommunicator);
startStream(port, baud, command);
EasyMock.reset(instance, mockCommunicator, mockListener);
// Make sure the events are triggered.
Capture<GcodeCommand> gc1 = EasyMock.newCapture();
Capture<GcodeCommand> gc2 = EasyMock.newCapture();
mockListener.commandSent(EasyMock.capture(gc1));
EasyMock.expect(EasyMock.expectLastCall());
mockListener.commandSent(EasyMock.capture(gc2));
EasyMock.expect(EasyMock.expectLastCall());
EasyMock.replay(instance, mockCommunicator, mockListener);
// Run test.
//assertEquals(0, instance.rowsSent());
instance.commandSent(new GcodeCommand(command));
//assertEquals(1, instance.rowsSent());
instance.commandSent(new GcodeCommand(command));
//assertEquals(2, instance.rowsSent());
assertTrue(gc1.getValue().isSent());
assertTrue(gc2.getValue().isSent());
EasyMock.verify(mockListener);
}
/**
* Test of commandComplete method, of class AbstractController.
*/
@Test
public void testCommandComplete() throws Exception {
System.out.println("commandComplete");
// Setup test with commands sent by communicator waiting on response.
testCommandSent();
reset(instance, mockCommunicator, mockListener);
// Make sure the events are triggered.
Capture<GcodeCommand> gc1 = newCapture();
Capture<GcodeCommand> gc2 = newCapture();
mockListener.commandComplete(capture(gc1));
expect(expectLastCall());
mockListener.commandComplete(capture(gc2));
expect(expectLastCall());
expect(expectLastCall());
mockListener.messageForConsole(anyObject(), anyString());
expect(expectLastCall());
mockListener.fileStreamComplete("queued commands", true);
expect(expectLastCall());
expect(mockCommunicator.areActiveCommands()).andReturn(true);
expect(mockCommunicator.areActiveCommands()).andReturn(false);
replay(instance, mockCommunicator, mockListener);
GcodeCommand first = instance.getActiveCommand();
instance.commandComplete("ok");
GcodeCommand second = instance.getActiveCommand();
instance.commandComplete("ok");
assertEquals(true, gc1.getValue().isDone());
assertEquals(true, gc2.getValue().isDone());
assertEquals("ok", gc1.getValue().getResponse());
assertEquals("ok", gc2.getValue().getResponse());
assertEquals(first, gc1.getValue());
assertEquals(second, gc2.getValue());
EasyMock.verify(mockListener);
}
// Exception tossing unimplemented methods.
/**
* Test of rawResponseHandler method, of class AbstractController.
*/
@Test
public void testRawResponseHandler() {
System.out.println("rawResponseHandler");
System.out.println("-N/A Abstract Function-");
}
/**
* Test of performHomingCycle method, of class AbstractController.
*/
@Test
public void testPerformHomingCycle() throws Exception {
System.out.println("performHomingCycle");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of returnToHome method, of class AbstractController.
*/
@Test
public void testReturnToHome() throws Exception {
System.out.println("returnToHome");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of resetCoordinatesToZero method, of class AbstractController.
*/
@Test
public void testResetCoordinatesToZero() throws Exception {
System.out.println("resetCoordinatesToZero");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of resetCoordinateToZero method, of class AbstractController.
*/
@Test
public void testResetCoordinateToZero() throws Exception {
System.out.println("resetCoordinateToZero");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of killAlarmLock method, of class AbstractController.
*/
@Test
public void testKillAlarmLock() throws Exception {
System.out.println("killAlarmLock");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of toggleCheckMode method, of class AbstractController.
*/
@Test
public void testToggleCheckMode() throws Exception {
System.out.println("toggleCheckMode");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of viewParserState method, of class AbstractController.
*/
@Test
public void testViewParserState() throws Exception {
System.out.println("viewParserState");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of issueSoftReset method, of class AbstractController.
*/
@Test
public void testIssueSoftReset() throws Exception {
System.out.println("issueSoftReset");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of softReset method, of class AbstractController.
*/
@Test
public void testSoftReset() throws Exception {
System.out.println("softReset");
System.out.println("-N/A Implementation Specific Function-");
}
/**
* Test of jogMachine method, of class AbstractController.
*/
@Test
public void testJogMachine() throws Exception {
System.out.println("jogMachine");
EasyMock.expect(niceInstance.isCommOpen()).andReturn(true).anyTimes();
mockCommunicator.streamCommands();
EasyMock.expect(expectLastCall()).anyTimes();
// Modal state should be restored.
mockCommunicator.queueStringForComm("G90 G21 \n");
EasyMock.expect(EasyMock.expectLastCall()).times(2);
// Making sure the commands get queued.
mockCommunicator.queueStringForComm("G20G91G0X-10Z10F11\n");
EasyMock.expect(EasyMock.expectLastCall()).times(1);
mockCommunicator.queueStringForComm("G21G91G0Y10F11\n");
EasyMock.expect(EasyMock.expectLastCall()).times(1);
EasyMock.replay(niceInstance, mockCommunicator);
niceInstance.setDistanceModeCode("G90");
niceInstance.setUnitsCode("G21");
niceInstance.jogMachine(-1, 0, 1, 10, 11, UnitUtils.Units.INCH);
niceInstance.jogMachine(0, 1, 0, 10, 11, UnitUtils.Units.MM);
}
/**
* Test of statusUpdatesEnabledValueChanged method, of class AbstractController.
*/
@Test
public void testStatusUpdatesEnabledValueChanged() {
System.out.println("statusUpdatesEnabledValueChanged");
System.out.println("-N/A Abstract Function-");
}
/**
* Test of statusUpdatesRateValueChanged method, of class AbstractController.
*/
@Test
public void testStatusUpdatesRateValueChanged() {
System.out.println("statusUpdatesRateValueChanged");
System.out.println("-N/A Abstract Function-");
}
}