forked from scream3r/java-simple-serial-connector
-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Mockito based unit tests for SerialPort
- Loading branch information
1 parent
83237ab
commit f7ab0e4
Showing
2 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package jssc; | ||
|
||
import junit.framework.TestCase; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.Mock; | ||
import org.powermock.api.mockito.PowerMockito; | ||
import org.powermock.core.classloader.annotations.PrepareForTest; | ||
import org.powermock.modules.junit4.PowerMockRunner; | ||
import org.powermock.reflect.Whitebox; | ||
|
||
import static org.mockito.Mockito.*; | ||
|
||
/** | ||
* Tests if Java logic around native invocations does not prevent | ||
* critical calls from happening when opening and closing ports | ||
*/ | ||
@RunWith(PowerMockRunner.class) | ||
@PrepareForTest(fullyQualifiedNames = "jssc.*") | ||
public class NativeMethodInvocationTest extends TestCase { | ||
|
||
@Mock(name = "serialInterface") | ||
private SerialNativeInterface serialInterface; | ||
|
||
private final long mockHandle = 0xDeadDeefL; | ||
|
||
@Test | ||
public void nativeMethodIsNotCalledWhenAttemptingToOpenAlreadyOpenPort() { | ||
// given | ||
SerialPort serialPort = newSerialPort(); | ||
|
||
// when | ||
try{ | ||
serialPort.openPort(); | ||
serialPort.openPort(); | ||
Assert.fail("Expected to throw a SerialPortException"); | ||
} catch (SerialPortException expected) { | ||
// TODO: Is it really expected or should this method return false as javadoc states? | ||
} | ||
|
||
// then | ||
verify(serialInterface, times(1)).openPort(anyString(), anyBoolean()); | ||
} | ||
|
||
@Test | ||
public void nativeMethodIsNotCalledWhenAttemptingToClosePortThatIsNotYetOpen() { | ||
// given | ||
SerialPort serialPort = newSerialPort(); | ||
|
||
// when | ||
try{ | ||
serialPort.closePort(); | ||
Assert.fail("Expected to throw a SerialPortException"); | ||
} catch (SerialPortException expected) { | ||
// TODO: Is it really expected or should this method return false as javadoc states? | ||
} | ||
|
||
// then | ||
verify(serialInterface, never()).setEventsMask(anyLong(), anyInt()); | ||
verify(serialInterface, never()).closePort(anyLong()); | ||
} | ||
|
||
@Test | ||
public void nativeMethodIsNotCalledWhenAttemptingCloseAlreadyClosedPort() { | ||
// given | ||
SerialPort serialPort = newSerialPort(); | ||
|
||
// when | ||
try{ | ||
serialPort.openPort(); | ||
serialPort.closePort(); | ||
serialPort.closePort(); | ||
Assert.fail("Expected to throw a SerialPortException"); | ||
} catch (SerialPortException expected) { | ||
// TODO: Is it really expected or should this method return false as javadoc states? | ||
} | ||
|
||
// then | ||
verify(serialInterface, times(1)).openPort(anyString(), anyBoolean()); | ||
verify(serialInterface, times(1)).closePort(anyLong()); | ||
} | ||
|
||
|
||
@Test | ||
public void nativeMethodIsCalledWhenClosingOpenAndReopeningClosedPort() throws SerialPortException { | ||
// given | ||
SerialPort serialPort = newSerialPort(); | ||
|
||
// when | ||
serialPort.openPort(); | ||
serialPort.closePort(); | ||
serialPort.openPort(); | ||
serialPort.closePort(); | ||
|
||
// then | ||
verify(serialInterface, times(2)).openPort(anyString(), anyBoolean()); | ||
verify(serialInterface, times(2)).closePort(mockHandle); | ||
} | ||
|
||
@Test | ||
public void nativeMethodIsCalledWhenClosingOpenPortWithEventListenerOnPosix() throws SerialPortException { | ||
// given | ||
setOs(SerialNativeInterface.OS_LINUX); | ||
SerialPort serialPort = newSerialPort(); | ||
when(serialInterface.setEventsMask(anyLong(), anyInt())).thenReturn(true); | ||
|
||
// when | ||
serialPort.openPort(); | ||
serialPort.addEventListener(someListener(), SerialPort.MASK_RXCHAR); | ||
serialPort.closePort(); | ||
|
||
// then | ||
verify(serialInterface, times(1)).openPort(anyString(), anyBoolean()); | ||
verify(serialInterface, never()).setEventsMask(anyLong(), anyInt()); | ||
verify(serialInterface, times(1)).closePort(mockHandle); | ||
} | ||
|
||
@Test | ||
public void nativeMethodIsCalledWhenClosingOpenPortWithEventListenerOnWindows() throws SerialPortException { | ||
// given | ||
setOs(SerialNativeInterface.OS_WINDOWS); | ||
SerialPort serialPort = newSerialPort(); | ||
when(serialInterface.setEventsMask(anyLong(), anyInt())).thenReturn(true); | ||
|
||
// when | ||
serialPort.openPort(); | ||
serialPort.addEventListener(someListener(), SerialPort.MASK_RXCHAR); | ||
serialPort.closePort(); | ||
|
||
// then | ||
verify(serialInterface, times(1)).openPort(anyString(), anyBoolean()); | ||
verify(serialInterface, times(1)).setEventsMask(mockHandle, SerialPort.MASK_RXCHAR); | ||
verify(serialInterface, times(1)).setEventsMask(mockHandle, 0); | ||
verify(serialInterface, times(1)).closePort(mockHandle); | ||
} | ||
|
||
/** | ||
* Simulates conditions as described in issue #107: user attempts to close the serial port that has been removed | ||
* from the system (e.g. unplugged usb serial adapter) without notifying the java code about it. | ||
*/ | ||
@Test | ||
public void nativeMethodIsCalledWhenClosingOpenPortWithEventListenerIfSetMaskFails() { | ||
// given | ||
setOs(SerialNativeInterface.OS_WINDOWS); | ||
SerialPort serialPort = newSerialPort(); | ||
when(serialInterface.setEventsMask(anyLong(), anyInt())).thenReturn(true); | ||
|
||
// when | ||
try { | ||
serialPort.openPort(); | ||
serialPort.addEventListener(someListener()); | ||
when(serialInterface.setEventsMask(anyLong(), anyInt())).thenReturn(false); | ||
serialPort.closePort(); | ||
} catch (SerialPortException expected) { | ||
// TODO: Is it really expected or should this method return false as javadoc states? | ||
} | ||
|
||
// then | ||
verify(serialInterface, times(1)).openPort(anyString(), anyBoolean()); | ||
verify(serialInterface, times(1)).setEventsMask(mockHandle, SerialPort.MASK_RXCHAR); | ||
verify(serialInterface, times(1)).setEventsMask(mockHandle, 0); | ||
verify(serialInterface, times(1)).closePort(mockHandle); | ||
} | ||
|
||
private void setOs(int os) { | ||
PowerMockito.mockStatic(SerialNativeInterface.class); | ||
when(SerialNativeInterface.getOsType()).thenReturn(os); | ||
} | ||
|
||
private SerialPort newSerialPort() { | ||
String portName = "dummy"; | ||
SerialPort serialPort = new SerialPort(portName); | ||
Whitebox.setInternalState(serialPort, "serialInterface", serialInterface); | ||
when(serialInterface.openPort(anyString(), anyBoolean())).thenReturn(mockHandle); | ||
when(serialInterface.closePort(anyLong())).thenReturn(true); | ||
when(serialInterface.waitEvents(anyLong())).thenReturn(new int[][]{}); | ||
return serialPort; | ||
} | ||
|
||
private SerialPortEventListener someListener() { | ||
return new SerialPortEventListener() { | ||
@Override | ||
public void serialEvent(SerialPortEvent serialPortEvent) { | ||
|
||
} | ||
}; | ||
} | ||
} |