/** * Copyright 2014 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ package com.jogamp.common.nio; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import org.junit.Assert; import org.junit.Test; import com.jogamp.junit.util.SingletonTestCase; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** * Testing {@link MappedByteBufferInputStream} and {@link MappedByteBufferOutputStream} editing functionality. */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestByteBufferOutputStream extends SingletonTestCase { static void testImpl(final String fname, final byte[] payLoad, final long payLoadOffset, final long postPayLoadFiller, final byte[] endBytes, final int sliceShift) throws IOException { testImpl(fname, payLoad, payLoadOffset, postPayLoadFiller, endBytes, sliceShift, false); testImpl(fname, payLoad, payLoadOffset, postPayLoadFiller, endBytes, sliceShift, true); } static void testImpl(final String fname, final byte[] payLoad, final long payLoadOffset, final long postPayLoadFiller, final byte[] endBytes, final int sliceShift, final boolean synchronous) throws IOException { final File file = new File(fname); file.delete(); file.createNewFile(); file.deleteOnExit(); try { final RandomAccessFile out = new RandomAccessFile(file, "rw"); final MappedByteBufferInputStream.FileResizeOp szOp = new MappedByteBufferInputStream.FileResizeOp() { @Override public void setLength(final long newSize) throws IOException { out.setLength(newSize); } }; final MappedByteBufferInputStream mis = new MappedByteBufferInputStream(out.getChannel(), FileChannel.MapMode.READ_WRITE, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, sliceShift); final MappedByteBufferOutputStream mos = mis.getOutputStream(szOp); mos.setSynchronous(synchronous); try { // resize to payLoad start and position to it mos.setLength(payLoadOffset); Assert.assertEquals(payLoadOffset, out.length()); Assert.assertEquals(payLoadOffset, mos.length()); Assert.assertEquals(0, mos.position()); // no change mos.position(payLoadOffset); Assert.assertEquals(payLoadOffset, mos.position()); // mark, write-expand payLoad mis.mark(1); mos.write(payLoad); Assert.assertEquals(payLoadOffset+payLoad.length, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); // expand + 1 mos.setLength(payLoadOffset+payLoad.length+1); Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); // no change // expand up-to very end, ahead of write - position to endBytes start mos.setLength(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length); Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); // no change mos.skip(postPayLoadFiller); Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller, mos.position()); // write endBytes (no resize) mos.write(endBytes); Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.position()); // Reset to payLoad, read it and verify mis.reset(); Assert.assertEquals(payLoadOffset, mos.position()); Assert.assertEquals(payLoadOffset, mis.position()); final byte[] tmp = new byte[payLoad.length]; Assert.assertEquals(payLoad.length, mis.read(tmp)); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertEquals(payLoadOffset+payLoad.length, mis.position()); Assert.assertArrayEquals(payLoad, tmp); // Shrink to end of payLoad, mark, read >= 0, reset .. redo Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.length()); mos.setLength(payLoadOffset+payLoad.length+1); Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); mis.mark(1); Assert.assertTrue(mis.read()>=0); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); mis.reset(); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertTrue(mis.read()>=0); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); // Shrink -1, read EOS mos.setLength(payLoadOffset+payLoad.length); Assert.assertEquals(payLoadOffset+payLoad.length, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertEquals(-1, mis.read()); // Expand + 1, mark, read >= 0, reset .. redo mos.setLength(payLoadOffset+payLoad.length+1); Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); mis.mark(1); Assert.assertTrue(mis.read()>=0); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); mis.reset(); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertTrue(mis.read()>=0); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); // Shrink -1, read EOS, write-expand, reset and verify mos.setLength(payLoadOffset+payLoad.length); Assert.assertEquals(payLoadOffset+payLoad.length, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertEquals(-1, mis.read()); mos.write('Z'); // expand while writing .. Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); mis.reset(); Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); Assert.assertEquals(payLoadOffset+payLoad.length, mis.position()); Assert.assertEquals('Z', mis.read()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position()); Assert.assertEquals(payLoadOffset+payLoad.length+1, mis.position()); // Shrink -2, shall clear mark, test reset failure mos.setLength(payLoadOffset+payLoad.length-1); Assert.assertEquals(payLoadOffset+payLoad.length-1, out.length()); Assert.assertEquals(payLoadOffset+payLoad.length-1, mos.length()); Assert.assertEquals(payLoadOffset+payLoad.length-1, mos.position()); try { mis.reset(); Assert.assertTrue(false); // shall not reach } catch( final IOException ioe ) { Assert.assertNotNull(ioe); } mis.mark(1); // ZERO file, test reset failure, read EOS, write-expand mos.setLength(0); Assert.assertEquals(0, out.length()); Assert.assertEquals(0, mos.length()); Assert.assertEquals(0, mos.position()); try { mis.reset(); Assert.assertTrue(false); // shall not reach } catch( final IOException ioe ) { Assert.assertNotNull(ioe); } Assert.assertEquals(-1, mis.read()); mos.write('Z'); // expand while writing .. Assert.assertEquals(1, out.length()); Assert.assertEquals(1, mos.length()); Assert.assertEquals(1, mos.position()); mis.position(0); Assert.assertEquals(0, mos.position()); Assert.assertEquals(0, mis.position()); Assert.assertEquals('Z', mis.read()); } finally { mos.close(); mis.close(); out.close(); } } finally { file.delete(); } } @Test public void test00() throws IOException { final int sliceShift = 13; // 8192 bytes per slice testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 0L, 0L, "EOF".getBytes(), sliceShift); } @Test public void test01() throws IOException { final int sliceShift = 13; // 8192 bytes per slice testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 9000L, 100L, "EOF".getBytes(), sliceShift); } @Test public void test02() throws IOException { final int sliceShift = 13; // 8192 bytes per slice testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 8189L, 9001L, "EOF".getBytes(), sliceShift); } @Test public void test03() throws IOException { final int sliceShift = 13; // 8192 bytes per slice testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 58189L, 109001L, "EOF".getBytes(), sliceShift); } @Test public void test10() throws IOException { final int sliceShift = 10; // 1024 bytes per slice final byte[] payLoad = new byte[4096]; for(int i=0; i