mirror of
https://github.com/apache/poi.git
synced 2026-02-27 20:40:08 +08:00
JUnit5 test classes and methods should have default package visibility git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1885308 13f79535-47bb-0310-9956-ffa450edef68
411 lines
15 KiB
Java
411 lines
15 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You 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.apache.poi.poifs.filesystem;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Arrays;
|
|
|
|
import org.apache.poi.POIDataSamples;
|
|
import org.apache.poi.util.SuppressForbidden;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
/**
|
|
* Class to test DocumentInputStream functionality
|
|
*/
|
|
public final class TestDocumentInputStream {
|
|
private DocumentNode _workbook_n;
|
|
private byte[] _workbook_data;
|
|
private static final int _workbook_size = 5000;
|
|
|
|
// non-even division of _workbook_size, also non-even division of
|
|
// any block size
|
|
private static final int _buffer_size = 6;
|
|
|
|
@BeforeEach
|
|
void setUp() throws Exception {
|
|
int blocks = (_workbook_size + 511) / 512;
|
|
|
|
_workbook_data = new byte[512 * blocks];
|
|
Arrays.fill(_workbook_data, (byte) -1);
|
|
for (int j = 0; j < _workbook_size; j++) {
|
|
_workbook_data[j] = (byte) (j * j);
|
|
}
|
|
|
|
// Now create the POIFS Version
|
|
byte[] _workbook_data_only = Arrays.copyOf(_workbook_data, _workbook_size);
|
|
|
|
POIFSFileSystem poifs = new POIFSFileSystem();
|
|
// Make it easy when debugging to see what isn't the doc
|
|
byte[] minus1 = new byte[512];
|
|
Arrays.fill(minus1, (byte) -1);
|
|
poifs.getBlockAt(-1).put(minus1);
|
|
poifs.getBlockAt(0).put(minus1);
|
|
poifs.getBlockAt(1).put(minus1);
|
|
|
|
// Create the POIFS document
|
|
_workbook_n = (DocumentNode) poifs.createDocument(
|
|
new ByteArrayInputStream(_workbook_data_only),
|
|
"Workbook"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* test constructor
|
|
*/
|
|
@Test
|
|
void testConstructor() throws IOException {
|
|
try (DocumentInputStream nstream = new DocumentInputStream(_workbook_n)) {
|
|
assertEquals(_workbook_size, _workbook_n.getSize());
|
|
assertEquals(_workbook_size, available(nstream));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* test available() behavior
|
|
*/
|
|
@Test
|
|
void testAvailable() throws IOException {
|
|
DocumentInputStream nstream = new DocumentInputStream(_workbook_n);
|
|
assertEquals(_workbook_size, available(nstream));
|
|
nstream.close();
|
|
|
|
assertThrows(IllegalStateException.class, () -> available(nstream));
|
|
}
|
|
|
|
/**
|
|
* test mark/reset/markSupported.
|
|
*/
|
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
|
@Test
|
|
void testMarkFunctions() throws IOException {
|
|
byte[] buffer = new byte[_workbook_size / 5];
|
|
byte[] small_buffer = new byte[212];
|
|
|
|
DocumentInputStream stream = new DocumentInputStream(_workbook_n);
|
|
// Read a fifth of it, and check all's correct
|
|
stream.read(buffer);
|
|
for (int j = 0; j < buffer.length; j++) {
|
|
assertEquals(_workbook_data[j], buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size - buffer.length, available(stream));
|
|
|
|
// Reset, and check the available goes back to being the
|
|
// whole of the stream
|
|
stream.reset();
|
|
assertEquals(_workbook_size, available(stream));
|
|
|
|
|
|
// Read part of a block
|
|
stream.read(small_buffer);
|
|
for (int j = 0; j < small_buffer.length; j++) {
|
|
assertEquals(_workbook_data[j], small_buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size - small_buffer.length, available(stream));
|
|
stream.mark(0);
|
|
|
|
// Read the next part
|
|
stream.read(small_buffer);
|
|
for (int j = 0; j < small_buffer.length; j++) {
|
|
assertEquals(_workbook_data[j + small_buffer.length], small_buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size - 2 * small_buffer.length, available(stream));
|
|
|
|
// Reset, check it goes back to where it was
|
|
stream.reset();
|
|
assertEquals(_workbook_size - small_buffer.length, available(stream));
|
|
|
|
// Read
|
|
stream.read(small_buffer);
|
|
for (int j = 0; j < small_buffer.length; j++) {
|
|
assertEquals(_workbook_data[j + small_buffer.length], small_buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size - 2 * small_buffer.length, available(stream));
|
|
|
|
|
|
// Now read at various points
|
|
Arrays.fill(small_buffer, (byte) 0);
|
|
stream.read(small_buffer, 6, 8);
|
|
stream.read(small_buffer, 100, 10);
|
|
stream.read(small_buffer, 150, 12);
|
|
int pos = small_buffer.length * 2;
|
|
for (int j = 0; j < small_buffer.length; j++) {
|
|
byte exp = 0;
|
|
if (j >= 6 && j < 6 + 8) {
|
|
exp = _workbook_data[pos];
|
|
pos++;
|
|
}
|
|
if (j >= 100 && j < 100 + 10) {
|
|
exp = _workbook_data[pos];
|
|
pos++;
|
|
}
|
|
if (j >= 150 && j < 150 + 12) {
|
|
exp = _workbook_data[pos];
|
|
pos++;
|
|
}
|
|
|
|
assertEquals(exp, small_buffer[j], "checking byte " + j);
|
|
}
|
|
|
|
// Now repeat it with spanning multiple blocks
|
|
stream = new DocumentInputStream(_workbook_n);
|
|
// Read several blocks work
|
|
buffer = new byte[_workbook_size / 5];
|
|
stream.read(buffer);
|
|
for (int j = 0; j < buffer.length; j++) {
|
|
assertEquals(_workbook_data[j], buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size - buffer.length, available(stream));
|
|
|
|
// Read all of it again, check it began at the start again
|
|
stream.reset();
|
|
assertEquals(_workbook_size, available(stream));
|
|
|
|
stream.read(buffer);
|
|
for (int j = 0; j < buffer.length; j++) {
|
|
assertEquals(_workbook_data[j], buffer[j], "checking byte " + j);
|
|
}
|
|
|
|
// Mark our position, and read another whole buffer
|
|
stream.mark(12);
|
|
stream.read(buffer);
|
|
assertEquals(_workbook_size - (2 * buffer.length), available(stream));
|
|
for (int j = buffer.length; j < (2 * buffer.length); j++) {
|
|
assertEquals(_workbook_data[j], buffer[j - buffer.length], "checking byte " + j);
|
|
}
|
|
|
|
// Reset, should go back to only one buffer full read
|
|
stream.reset();
|
|
assertEquals(_workbook_size - buffer.length, available(stream));
|
|
|
|
// Read the buffer again
|
|
stream.read(buffer);
|
|
assertEquals(_workbook_size - (2 * buffer.length), available(stream));
|
|
for (int j = buffer.length; j < (2 * buffer.length); j++) {
|
|
assertEquals(_workbook_data[j], buffer[j - buffer.length], "checking byte " + j);
|
|
}
|
|
assertTrue(stream.markSupported());
|
|
}
|
|
|
|
/**
|
|
* test simple read method
|
|
*/
|
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
|
@Test
|
|
void testReadSingleByte() throws IOException {
|
|
DocumentInputStream stream = new DocumentInputStream(_workbook_n);
|
|
int remaining = _workbook_size;
|
|
|
|
// Try and read each byte in turn
|
|
for (int j = 0; j < _workbook_size; j++) {
|
|
int b = stream.read();
|
|
assertTrue(b >= 0, "checking sign of " + j);
|
|
assertEquals(_workbook_data[j], (byte) b, "validating byte " + j);
|
|
remaining--;
|
|
assertEquals(remaining, available(stream), "checking remaining after reading byte " + j);
|
|
}
|
|
|
|
// Ensure we fell off the end
|
|
assertEquals(-1, stream.read());
|
|
|
|
// Check that after close we can no longer read
|
|
stream.close();
|
|
assertThrows(IOException.class, stream::read);
|
|
}
|
|
|
|
/**
|
|
* Test buffered read
|
|
*/
|
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
|
@Test
|
|
void testBufferRead() throws IOException {
|
|
DocumentInputStream stream = new DocumentInputStream(_workbook_n);
|
|
// Need to give a byte array to read
|
|
assertThrows(NullPointerException.class, () -> stream.read(null));
|
|
|
|
// test reading zero length buffer
|
|
assertEquals(0, stream.read(new byte[0]));
|
|
assertEquals(_workbook_size, available(stream));
|
|
byte[] buffer = new byte[_buffer_size];
|
|
int offset = 0;
|
|
|
|
while (available(stream) >= buffer.length) {
|
|
assertEquals(_buffer_size, stream.read(buffer));
|
|
for (byte element : buffer) {
|
|
assertEquals(_workbook_data[offset], element, "in main loop, byte " + offset);
|
|
offset++;
|
|
}
|
|
assertEquals(_workbook_size - offset, available(stream), "offset " + offset);
|
|
}
|
|
assertEquals(_workbook_size % _buffer_size, available(stream));
|
|
Arrays.fill(buffer, (byte) 0);
|
|
int count = stream.read(buffer);
|
|
|
|
assertEquals(_workbook_size % _buffer_size, count);
|
|
for (int j = 0; j < count; j++) {
|
|
assertEquals(_workbook_data[offset], buffer[j], "past main loop, byte " + offset);
|
|
offset++;
|
|
}
|
|
assertEquals(_workbook_size, offset);
|
|
for (int j = count; j < buffer.length; j++) {
|
|
assertEquals(0, buffer[j], "checking remainder, byte " + j);
|
|
}
|
|
assertEquals(-1, stream.read(buffer));
|
|
stream.close();
|
|
|
|
assertThrows(IOException.class, () -> stream.read(buffer));
|
|
}
|
|
|
|
/**
|
|
* Test complex buffered read
|
|
*/
|
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
|
@Test
|
|
void testComplexBufferRead() throws IOException {
|
|
DocumentInputStream stream = new DocumentInputStream(_workbook_n);
|
|
assertThrows(IllegalArgumentException.class, () -> stream.read(null, 0, 1));
|
|
|
|
// test illegal offsets and lengths
|
|
assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[5], -4, 0));
|
|
assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[5], 0, -4));
|
|
assertThrows(IndexOutOfBoundsException.class, () -> stream.read(new byte[5], 0, 6));
|
|
|
|
// test reading zero
|
|
assertEquals(0, stream.read(new byte[5], 0, 0));
|
|
assertEquals(_workbook_size, available(stream));
|
|
byte[] buffer = new byte[_workbook_size];
|
|
int offset = 0;
|
|
|
|
while (available(stream) >= _buffer_size) {
|
|
Arrays.fill(buffer, (byte) 0);
|
|
assertEquals(_buffer_size, stream.read(buffer, offset, _buffer_size));
|
|
for (int j = 0; j < offset; j++) {
|
|
assertEquals(0, buffer[j], "checking byte " + j);
|
|
}
|
|
for (int j = offset; j < (offset + _buffer_size); j++) {
|
|
assertEquals(_workbook_data[j], buffer[j], "checking byte " + j);
|
|
}
|
|
for (int j = offset + _buffer_size; j < buffer.length; j++) {
|
|
assertEquals(0, buffer[j], "checking byte " + j);
|
|
}
|
|
offset += _buffer_size;
|
|
assertEquals(_workbook_size - offset, available(stream), "offset " + offset);
|
|
}
|
|
assertEquals(_workbook_size % _buffer_size, available(stream));
|
|
Arrays.fill(buffer, (byte) 0);
|
|
int count = stream.read(buffer, offset, _workbook_size % _buffer_size);
|
|
|
|
assertEquals(_workbook_size % _buffer_size, count);
|
|
for (int j = 0; j < offset; j++) {
|
|
assertEquals(0, buffer[j], "checking byte " + j);
|
|
}
|
|
for (int j = offset; j < buffer.length; j++) {
|
|
assertEquals(_workbook_data[j], buffer[j], "checking byte " + j);
|
|
}
|
|
assertEquals(_workbook_size, offset + count);
|
|
for (int j = count; j < offset; j++) {
|
|
assertEquals(0, buffer[j], "byte " + j);
|
|
}
|
|
|
|
assertEquals(-1, stream.read(buffer, 0, 1));
|
|
stream.close();
|
|
|
|
assertThrows(IOException.class, () -> stream.read(buffer, 0, 1));
|
|
}
|
|
|
|
/**
|
|
* Tests that we can skip within the stream
|
|
*/
|
|
@Test
|
|
void testSkip() throws IOException {
|
|
DocumentInputStream stream = new DocumentInputStream(_workbook_n);
|
|
assertEquals(_workbook_size, available(stream));
|
|
int count = available(stream);
|
|
|
|
while (available(stream) >= _buffer_size) {
|
|
assertEquals(_buffer_size, stream.skip(_buffer_size));
|
|
count -= _buffer_size;
|
|
assertEquals(count, available(stream));
|
|
}
|
|
assertEquals(_workbook_size % _buffer_size,
|
|
stream.skip(_buffer_size));
|
|
assertEquals(0, available(stream));
|
|
stream.reset();
|
|
assertEquals(_workbook_size, available(stream));
|
|
assertEquals(_workbook_size, stream.skip(_workbook_size * 2));
|
|
assertEquals(0, available(stream));
|
|
stream.reset();
|
|
assertEquals(_workbook_size, available(stream));
|
|
assertEquals(_workbook_size,
|
|
stream.skip(2 + (long) Integer.MAX_VALUE));
|
|
assertEquals(0, available(stream));
|
|
}
|
|
|
|
/**
|
|
* Test that we can read files at multiple levels down the tree
|
|
*/
|
|
@Test
|
|
void testReadMultipleTreeLevels() throws Exception {
|
|
final POIDataSamples _samples = POIDataSamples.getPublisherInstance();
|
|
File sample = _samples.getFile("Sample.pub");
|
|
|
|
DocumentInputStream stream;
|
|
|
|
try (POIFSFileSystem poifs = new POIFSFileSystem(sample)) {
|
|
// Ensure we have what we expect on the root
|
|
assertEquals(poifs, poifs.getRoot().getFileSystem());
|
|
|
|
// Check inside
|
|
DirectoryNode root = poifs.getRoot();
|
|
// Top Level
|
|
Entry top = root.getEntry("Contents");
|
|
assertTrue(top.isDocumentEntry());
|
|
stream = root.createDocumentInputStream(top);
|
|
assertNotEquals(-1, stream.read());
|
|
|
|
// One Level Down
|
|
DirectoryNode escher = (DirectoryNode) root.getEntry("Escher");
|
|
Entry one = escher.getEntry("EscherStm");
|
|
assertTrue(one.isDocumentEntry());
|
|
stream = escher.createDocumentInputStream(one);
|
|
assertNotEquals(-1, stream.read());
|
|
|
|
// Two Levels Down
|
|
DirectoryNode quill = (DirectoryNode) root.getEntry("Quill");
|
|
DirectoryNode quillSub = (DirectoryNode) quill.getEntry("QuillSub");
|
|
Entry two = quillSub.getEntry("CONTENTS");
|
|
assertTrue(two.isDocumentEntry());
|
|
stream = quillSub.createDocumentInputStream(two);
|
|
assertNotEquals(-1, stream.read());
|
|
}
|
|
}
|
|
|
|
@SuppressForbidden("just for testing")
|
|
private static int available(InputStream is) throws IOException {
|
|
return is.available();
|
|
}
|
|
}
|