1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.tests.java.nio;
19
20import java.io.File;
21import java.io.FileInputStream;
22import java.io.FileOutputStream;
23import java.io.IOException;
24import java.io.RandomAccessFile;
25import java.nio.BufferUnderflowException;
26import java.nio.ByteBuffer;
27import java.nio.IntBuffer;
28import java.nio.MappedByteBuffer;
29import java.nio.channels.FileChannel;
30import java.nio.channels.NonWritableChannelException;
31import java.nio.channels.FileChannel.MapMode;
32
33import junit.framework.TestCase;
34
35public class MappedByteBufferTest extends TestCase {
36
37    File tmpFile, emptyFile;
38
39    /**
40     * A regression test for failing to correctly set capacity of underlying
41     * wrapped buffer from a mapped byte buffer.
42     */
43    public void testasIntBuffer() throws IOException {
44        // Map file
45        FileInputStream fis = new FileInputStream(tmpFile);
46        FileChannel fc = fis.getChannel();
47        MappedByteBuffer mmb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc
48                .size());
49        int len = mmb.capacity();
50        assertEquals("Got wrong number of bytes", 46, len); //$NON-NLS-1$
51
52        // Read in our 26 bytes
53        for (int i = 0; i < 26; i++) {
54            byte b = mmb.get();
55            assertEquals("Got wrong byte value", (byte) 'A' + i, b); //$NON-NLS-1$
56        }
57
58        // Now convert to an IntBuffer to read our ints
59        IntBuffer ibuffer = mmb.asIntBuffer();
60        for (int i = 0; i < 5; i++) {
61            int val = ibuffer.get();
62            assertEquals("Got wrong int value", i + 1, val); //$NON-NLS-1$
63        }
64        fc.close();
65    }
66
67    /**
68     * Regression for HARMONY-6315 - FileChannel.map throws IOException
69     * when called with size 0
70     *
71     * @throws IOException
72     */
73    public void testEmptyBuffer() throws IOException {
74    	// Map empty file
75        FileInputStream fis = new FileInputStream(emptyFile);
76        FileChannel fc = fis.getChannel();
77        MappedByteBuffer mmb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
78
79        // check non-null
80        assertNotNull("MappedByteBuffer created from empty file should not be null",
81        		mmb);
82
83        // check capacity is 0
84        int len = mmb.capacity();
85        assertEquals("MappedByteBuffer created from empty file should have 0 capacity",
86        		0, len);
87
88        assertFalse("MappedByteBuffer from empty file shouldn't be backed by an array ",
89        		mmb.hasArray());
90
91        try
92        {
93        	byte b = mmb.get();
94        	fail("Calling MappedByteBuffer.get() on empty buffer should throw a BufferUnderflowException");
95        }
96        catch (BufferUnderflowException e)
97        {
98        	// expected behaviour
99        }
100
101        // test expected exceptions thrown
102        try
103        {
104        	mmb = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
105        	fail("Expected NonWritableChannelException to be thrown");
106        }
107        catch (NonWritableChannelException e)
108        {
109        	// expected behaviour
110        }
111        try
112        {
113        	mmb = fc.map(FileChannel.MapMode.PRIVATE, 0, fc.size());
114        	fail("Expected NonWritableChannelException to be thrown");
115        }
116        catch (NonWritableChannelException e)
117        {
118        	// expected behaviour
119        }
120        fc.close();
121    }
122
123    /**
124     * @tests {@link java.nio.MappedByteBuffer#force()}
125     */
126    public void test_force() throws IOException {
127        // buffer was not mapped in read/write mode
128        FileInputStream fileInputStream = new FileInputStream(tmpFile);
129        FileChannel fileChannelRead = fileInputStream.getChannel();
130        MappedByteBuffer mmbRead = fileChannelRead.map(MapMode.READ_ONLY, 0,
131                fileChannelRead.size());
132
133        mmbRead.force();
134
135        FileInputStream inputStream = new FileInputStream(tmpFile);
136        FileChannel fileChannelR = inputStream.getChannel();
137        MappedByteBuffer resultRead = fileChannelR.map(MapMode.READ_ONLY, 0,
138                fileChannelR.size());
139
140        //If this buffer was not mapped in read/write mode, then invoking this method has no effect.
141        assertEquals(
142                "Invoking force() should have no effect when this buffer was not mapped in read/write mode",
143                mmbRead, resultRead);
144
145        // Buffer was mapped in read/write mode
146        RandomAccessFile randomFile = new RandomAccessFile(tmpFile, "rw");
147        FileChannel fileChannelReadWrite = randomFile.getChannel();
148        MappedByteBuffer mmbReadWrite = fileChannelReadWrite.map(
149                FileChannel.MapMode.READ_WRITE, 0, fileChannelReadWrite.size());
150
151        mmbReadWrite.put((byte) 'o');
152        mmbReadWrite.force();
153
154        RandomAccessFile random = new RandomAccessFile(tmpFile, "rw");
155        FileChannel fileChannelRW = random.getChannel();
156        MappedByteBuffer resultReadWrite = fileChannelRW.map(
157                FileChannel.MapMode.READ_WRITE, 0, fileChannelRW.size());
158
159        // Invoking force() will change the buffer
160        assertFalse(mmbReadWrite.equals(resultReadWrite));
161
162        fileChannelRead.close();
163        fileChannelR.close();
164        fileChannelReadWrite.close();
165        fileChannelRW.close();
166    }
167
168    /**
169     * @tests {@link java.nio.MappedByteBuffer#load()}
170     */
171    public void test_load() throws IOException {
172        FileInputStream fileInputStream = new FileInputStream(tmpFile);
173        FileChannel fileChannelRead = fileInputStream.getChannel();
174        MappedByteBuffer mmbRead = fileChannelRead.map(MapMode.READ_ONLY, 0,
175                fileChannelRead.size());
176
177        assertEquals(mmbRead, mmbRead.load());
178
179        RandomAccessFile randomFile = new RandomAccessFile(tmpFile, "rw");
180        FileChannel fileChannelReadWrite = randomFile.getChannel();
181        MappedByteBuffer mmbReadWrite = fileChannelReadWrite.map(
182                FileChannel.MapMode.READ_WRITE, 0, fileChannelReadWrite.size());
183
184        assertEquals(mmbReadWrite, mmbReadWrite.load());
185
186        fileChannelRead.close();
187        fileChannelReadWrite.close();
188    }
189
190    protected void setUp() throws IOException {
191        // Create temp file with 26 bytes and 5 ints
192        tmpFile = File.createTempFile("harmony", "test");  //$NON-NLS-1$//$NON-NLS-2$
193        tmpFile.deleteOnExit();
194        FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
195        FileChannel fileChannel = fileOutputStream.getChannel();
196        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(26 + 20);
197        for (int i = 0; i < 26; i++) {
198            byteBuffer.put((byte) ('A' + i));
199        }
200        for (int i = 0; i < 5; i++) {
201            byteBuffer.putInt(i + 1);
202        }
203        byteBuffer.rewind();
204        fileChannel.write(byteBuffer);
205        fileChannel.close();
206        fileOutputStream.close();
207
208        emptyFile = File.createTempFile("harmony", "test");  //$NON-NLS-1$//$NON-NLS-2$
209        emptyFile.deleteOnExit();
210    }
211
212    public void test_position() throws IOException {
213        File tmp = File.createTempFile("hmy", "tmp");
214        tmp.deleteOnExit();
215        RandomAccessFile f = new RandomAccessFile(tmp, "rw");
216        FileChannel ch = f.getChannel();
217        MappedByteBuffer mbb = ch.map(MapMode.READ_WRITE, 0L, 100L);
218        ch.close();
219
220        mbb.putInt(1, 1);
221        mbb.position(50);
222        mbb.putInt(50);
223
224        mbb.flip();
225        mbb.get();
226        assertEquals(1, mbb.getInt());
227
228        mbb.position(50);
229        assertEquals(50, mbb.getInt());
230    }
231}
232