/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.shrinkwrap.api.nio.file;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Tests to assert that the {@link SeekableInMemoryByteChannel} is working as contracted.
*
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
*/
public class SeekableInMemoryByteChannelTestCase {
@SuppressWarnings("unused")
private static final Logger log = Logger.getLogger(SeekableInMemoryByteChannelTestCase.class.getName());
private static final String CONTENTS_SMALLER_BUFFER = "Andrew Lee Rubinger";
private static final String CONTENTS_BIGGER_BUFFER = "Andrew Lee Rubinger, JBoss by Red Hat";
private static final String UTF8 = "UTF-8";
/**
* Instance under test
*/
private SeekableInMemoryByteChannel channel;
private ByteBuffer smallerBuffer;
private ByteBuffer biggerBuffer;
@Before
public void init() {
this.channel = new SeekableInMemoryByteChannel();
try {
smallerBuffer = ByteBuffer.wrap(CONTENTS_SMALLER_BUFFER.getBytes(UTF8));
biggerBuffer = ByteBuffer.wrap(CONTENTS_BIGGER_BUFFER.getBytes(UTF8));
} catch (final UnsupportedEncodingException uee) {
throw new RuntimeException(uee);
}
}
@After
public void closeChannel() throws IOException {
if (this.channel.isOpen()) {
this.channel.close();
}
}
@Test(expected = ClosedChannelException.class)
public void readAfterCloseThrowsException() throws IOException {
this.channel.close();
this.channel.read(ByteBuffer.wrap(new byte[] {}));
}
@Test(expected = ClosedChannelException.class)
public void writeAfterCloseThrowsException() throws IOException {
this.channel.close();
this.channel.write(ByteBuffer.wrap(new byte[] {}));
}
@Test
public void isOpenTrue() throws IOException {
Assert.assertTrue("Channel should report open before it's closed", this.channel.isOpen());
}
@Test
public void isOpenFalseAfterClose() throws IOException {
this.channel.close();
Assert.assertFalse("Channel should report not open after close", this.channel.isOpen());
}
@Test
public void positionInit0() throws IOException {
Assert.assertEquals("Channel should init to position 0", 0, this.channel.position());
}
@Test
public void sizeInit0() throws IOException {
Assert.assertEquals("Channel should init to size 0", 0, this.channel.size());
}
@Test(expected = IllegalArgumentException.class)
public void readRequiresBuffer() throws IOException {
this.channel.read(null);
}
@Test(expected = IllegalArgumentException.class)
public void writeRequiresBuffer() throws IOException {
this.channel.write(null);
}
@Test
public void read() throws IOException {
this.channel.write(smallerBuffer);
final int newPosition = 2;
final byte[] contents = new byte[2];
// Read 2 bytes from the new position
final int numBytesRead = this.channel.position(newPosition).read(ByteBuffer.wrap(contents));
final String expected = "dr";
final String contentsRead = new String(contents, UTF8);
Assert.assertEquals("Read should report correct number of bytes read", contents.length, numBytesRead);
Assert.assertEquals("Channel should respect explicit position during reads", expected, contentsRead);
}
@Test
public void getContents() throws IOException {
this.channel.write(smallerBuffer);
final BufferedReader reader = new BufferedReader(new InputStreamReader(this.channel.getContents()));
final String contents = reader.readLine();
Assert.assertEquals("Contents read were not as expected", CONTENTS_SMALLER_BUFFER, contents);
}
@Test
public void readDestinationBiggerThanChannel() throws IOException {
this.channel.write(smallerBuffer);
final ByteBuffer destination = biggerBuffer;
Assert.assertTrue("Test setup incorrect, should be trying to read into a buffer greater than our size",
destination.remaining() > this.channel.size());
// Read more bytes than we currently have size
final int numBytesRead = this.channel.position(0).read(destination);
Assert.assertEquals("Read to a buffer greater than our size should read only up to our size",
this.channel.size(), numBytesRead);
}
@Test
public void nothingToRead() throws IOException {
this.channel.write(smallerBuffer);
// Read a byte from a position past the size
final int numBytesRead = this.channel.position(this.channel.size() + 3).read(ByteBuffer.wrap(new byte[1]));
Assert.assertEquals("Read on position > size should return -1", -1, numBytesRead);
}
@Test
public void write() throws IOException {
this.channel.write(smallerBuffer);
final int newPosition = 2;
final int numBytesWritten = this.channel.position(newPosition).write(ByteBuffer.wrap("DR".getBytes(UTF8)));
// Read 3 bytes from the new position
final byte[] contents = new byte[3];
this.channel.position(newPosition).read(ByteBuffer.wrap(contents));
final String expected = "DRe";
final String read = new String(contents, UTF8);
Assert.assertEquals("Write should report correct number of bytes written", 2, numBytesWritten);
Assert.assertEquals("Channel should respect explicit position during writes", expected, read);
}
@Test
public void writeWithPositionPastSize() throws IOException {
this.channel.write(smallerBuffer);
smallerBuffer.clear();
final int gap = 5;
// Write again, after a gap past the current size
this.channel.position(this.channel.size() + gap).write(smallerBuffer);
smallerBuffer.clear();
Assert.assertEquals("Channel size should be equal to the size of the writes we put in, plus "
+ "the gap when we set the position tpo be greater than the size", smallerBuffer.remaining() * 2 + gap,
this.channel.size());
}
@Test
public void positionSetPastSize() throws IOException {
final int newPosition = 30;
this.channel.position(newPosition);
Assert.assertEquals("Channel should be able to be set past size", newPosition, this.channel.position());
}
@Test(expected = IllegalArgumentException.class)
public void negativePositionProhibited() throws IOException {
this.channel.position(-1);
}
@Test(expected = IllegalArgumentException.class)
public void exceedMaxIntegerPositionProhibited() throws IOException {
final long newPosition = Integer.MAX_VALUE + 1L;
Assert.assertTrue("Didn't set up new position to be out of int bounds", newPosition > Integer.MAX_VALUE);
this.channel.position(newPosition); // Exception expected
}
@Test(expected = IllegalArgumentException.class)
public void negativeTruncateProhibited() throws IOException {
this.channel.truncate(-1);
}
@Test(expected = IllegalArgumentException.class)
public void exceedMaxIntegerTruncateProhibited() throws IOException {
final long truncateValue = Integer.MAX_VALUE + 1L;
Assert.assertTrue("Didn't set up new truncate to be out of int bounds", truncateValue > Integer.MAX_VALUE);
this.channel.truncate(truncateValue); // Exception expected
}
@Test
public void size() throws IOException {
this.channel.write(smallerBuffer);
Assert.assertEquals("Channel should report correct size", this.smallerBuffer.clear().remaining(),
this.channel.size());
}
@Test
public void truncate() throws IOException {
this.channel.write(smallerBuffer);
final int newSize = (int) this.channel.size() - 3;
this.channel.truncate(newSize);
// Correct size?
Assert.assertEquals("Channel should report correct size after truncate", newSize, this.channel.size());
// Correct position?
Assert.assertEquals("Channel should report adjusted position after truncate", newSize, this.channel.position());
}
@Test
public void truncateLargerThanSizeRepositions() throws IOException {
this.channel.write(smallerBuffer);
final int oldSize = (int) this.channel.size();
final int newSize = oldSize + 3;
this.channel.truncate(newSize);
// Size unchanged?
Assert.assertEquals("Channel should report unchanged size after truncate to bigger value", oldSize,
this.channel.size());
// Correct position, beyond size?
Assert.assertEquals("Channel should report unchanged position after truncate to bigger value", oldSize,
this.channel.position());
}
}