/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit;
import java.io.*;
import java.nio.*;
import java.util.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.*;
import org.junit.runners.*;
public final class InstanceSpecificMockingTest
{
static class Collaborator
{
protected final int value;
Collaborator() { value = -1; }
Collaborator(int value) { this.value = value; }
int getValue() { return value; }
@SuppressWarnings("unused")
final boolean simpleOperation(int a, String b, Date c) { return true; }
@SuppressWarnings("unused")
static void doSomething(boolean b, String s) { throw new IllegalStateException(); }
}
final Collaborator previousInstance = new Collaborator();
@Injectable Collaborator mock;
@Test
public void exerciseInjectedInstanceDuringReplayOnly()
{
assertThatPreviouslyCreatedInstanceIsNotMocked();
assertEquals(0, mock.value);
assertEquals(0, mock.getValue());
assertFalse(mock.simpleOperation(1, "test", null));
assertThatNewlyCreatedInstanceIsNotMocked();
}
void assertThatPreviouslyCreatedInstanceIsNotMocked()
{
assertEquals(-1, previousInstance.value);
assertEquals(-1, previousInstance.getValue());
assertTrue(previousInstance.simpleOperation(1, "test", null));
}
void assertThatNewlyCreatedInstanceIsNotMocked()
{
Collaborator newInstance = new Collaborator();
assertEquals(-1, newInstance.value);
assertEquals(-1, newInstance.getValue());
assertTrue(newInstance.simpleOperation(1, "test", null));
}
@Test
public void mockSingleInstanceStrictly()
{
assertThatPreviouslyCreatedInstanceIsNotMocked();
new StrictExpectations() {{ mock.getValue(); result = 123; }};
assertEquals(123, mock.getValue());
assertThatNewlyCreatedInstanceIsNotMocked();
}
@Test
public void mockSpecificInstance()
{
new Expectations() {{
mock.simpleOperation(1, "", null); result = false;
mock.getValue(); result = 123; times = 1;
}};
assertFalse(mock.simpleOperation(1, "", null));
assertEquals(123, mock.getValue());
assertThatPreviouslyCreatedInstanceIsNotMocked();
assertThatNewlyCreatedInstanceIsNotMocked();
try {
Collaborator.doSomething(false, null);
fail();
}
catch (IllegalStateException ignore) {}
}
@Test
public void useASecondMockInstanceOfTheSameType(@Injectable final Collaborator mock2)
{
assertThatPreviouslyCreatedInstanceIsNotMocked();
new Expectations() {{
mock2.getValue(); result = 2;
mock.getValue(); returns(1, 3);
}};
assertEquals(1, mock.getValue());
assertEquals(2, mock2.getValue());
assertEquals(3, mock.getValue());
assertEquals(2, mock2.getValue());
assertEquals(3, mock.getValue());
assertThatPreviouslyCreatedInstanceIsNotMocked();
assertThatNewlyCreatedInstanceIsNotMocked();
}
// Injectable mocks of unusual types ///////////////////////////////////////////////////////////////////////////////
@Test
public void allowInjectableMockOfInterfaceType(@Injectable final Runnable runnable)
{
runnable.run();
runnable.run();
new Verifications() {{ runnable.run(); minTimes = 1; maxTimes = 2; }};
}
@Test
public void allowInjectableMockOfAnnotationType(@Injectable final RunWith runWith)
{
new Expectations() {{ runWith.value(); result = BlockJUnit4ClassRunner.class; }};
assertSame(BlockJUnit4ClassRunner.class, runWith.value());
}
// Mocking java.nio.ByteBuffer /////////////////////////////////////////////////////////////////////////////////////
@Test
public void mockByteBufferAsInjectable(@Injectable final ByteBuffer buf)
{
ByteBuffer realBuf = ByteBuffer.allocateDirect(10);
assertNotNull(realBuf);
assertEquals(10, realBuf.capacity());
new Expectations() {{
buf.isDirect(); result = true;
// Calling "getBytes()" here indirectly creates a new ByteBuffer, requiring use of @Injectable.
buf.put("Test".getBytes()); times = 1;
}};
assertTrue(buf.isDirect());
buf.put("Test".getBytes());
}
@Test
public void mockByteBufferRegularly(@Mocked ByteBuffer mockBuffer)
{
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
assertSame(mockBuffer, buffer);
new Verifications() {{ ByteBuffer.allocateDirect(anyInt); }};
}
@Test
public void mockByteBufferAsCascading(@Mocked ByteBuffer unused)
{
ByteBuffer cascadedBuf = ByteBuffer.allocateDirect(10);
assertNotNull(cascadedBuf);
assertEquals(0, cascadedBuf.capacity());
}
static class BufferFactory
{
ByteBuffer createBuffer() { return null; }
}
@Test
public void mockByteBufferAsCascadedMock(@Mocked BufferFactory cascadingMock)
{
ByteBuffer realBuf1 = ByteBuffer.allocateDirect(10);
assertEquals(10, realBuf1.capacity());
ByteBuffer cascadedBuf = cascadingMock.createBuffer();
assertEquals(0, cascadedBuf.capacity());
ByteBuffer realBuf2 = ByteBuffer.allocateDirect(20);
assertEquals(20, realBuf2.capacity());
}
// Mocking java.io.InputStream /////////////////////////////////////////////////////////////////////////////////////
public static final class ConcatenatingInputStream extends InputStream
{
private final Queue<InputStream> sequentialInputs;
private InputStream currentInput;
public ConcatenatingInputStream(InputStream... sequentialInputs)
{
this.sequentialInputs = new LinkedList<InputStream>(Arrays.asList(sequentialInputs));
currentInput = this.sequentialInputs.poll();
}
@Override
public int read() throws IOException
{
if (currentInput == null) return -1;
int nextByte = currentInput.read();
if (nextByte >= 0) {
return nextByte;
}
currentInput = sequentialInputs.poll();
//noinspection TailRecursion
return read();
}
}
@Test
public void concatenateInputStreams(@Injectable final InputStream input1, @Injectable final InputStream input2)
throws Exception
{
new Expectations() {{
input1.read(); returns(1, 2, -1);
input2.read(); returns(3, -1);
}};
InputStream concatenatedInput = new ConcatenatingInputStream(input1, input2);
byte[] buf = new byte[3];
concatenatedInput.read(buf);
assertArrayEquals(new byte[] {1, 2, 3}, buf);
}
}