From d06de78703eb67738c8715e1dcdb1c967435c157 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Tue, 14 Apr 2020 19:07:24 +0000 Subject: [PATCH] #64350 - Sonar fix - "Iterator.next()" methods should throw "NoSuchElementException" git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1876525 13f79535-47bb-0310-9956-ffa450edef68 --- .../aggregates/ValueRecordsAggregate.java | 6 +- .../filesystem/FilteringDirectoryNode.java | 35 ++--- .../poi/poifs/filesystem/POIFSMiniStore.java | 53 ++++---- .../poi/poifs/filesystem/POIFSStream.java | 51 +++---- .../poi/util/StringCodepointsIterable.java | 4 + src/java/org/apache/poi/util/StringUtil.java | 36 +---- .../poi/hemf/record/emf/HemfComment.java | 4 + .../hemf/record/emf/HemfRecordIterator.java | 4 + .../emfplus/HemfPlusRecordIterator.java | 4 + .../hsmf/extractor/OutlookTextExtractor.java | 31 +++-- .../TestFilteringDirectoryNode.java | 57 +++++--- .../poifs/filesystem/TestPOIFSMiniStore.java | 125 +++++++++--------- .../poi/poifs/filesystem/TestPOIFSStream.java | 26 +--- .../org/apache/poi/util/TestStringUtil.java | 61 +-------- 14 files changed, 222 insertions(+), 275 deletions(-) diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java index 8a416cdb7b..ab4eeac311 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java @@ -18,6 +18,7 @@ package org.apache.poi.hssf.record.aggregates; import java.util.Iterator; +import java.util.NoSuchElementException; import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.BlankRecord; @@ -338,8 +339,9 @@ public final class ValueRecordsAggregate implements Iterable> childExcludes; - + private DirectoryEntry directory; - + /** * Creates a filter round the specified directory, which * will exclude entries such as "MyNode" and "MyDir/IgnoreNode". * The excludes can stretch into children, if they contain a /. - * + * * @param directory The Directory to filter * @param excludes The Entries to exclude * @throws IllegalArgumentException if directory is null @@ -66,7 +67,7 @@ public class FilteringDirectoryNode implements DirectoryEntry throw new IllegalArgumentException("directory cannot be null"); } this.directory = directory; - + // Process the excludes this.excludes = new HashSet<>(); this.childExcludes = new HashMap<>(); @@ -108,7 +109,7 @@ public class FilteringDirectoryNode implements DirectoryEntry public Iterator iterator() { return getEntries(); } - + public int getEntryCount() { int size = directory.getEntryCount(); for (String excl : excludes) { @@ -118,7 +119,7 @@ public class FilteringDirectoryNode implements DirectoryEntry } return size; } - + public Set getEntryNames() { Set names = new HashSet<>(); for (String name : directory.getEntryNames()) { @@ -144,7 +145,7 @@ public class FilteringDirectoryNode implements DirectoryEntry if (excludes.contains(name)) { throw new FileNotFoundException(name); } - + Entry entry = directory.getEntry(name); return wrapEntry(entry); } @@ -152,7 +153,7 @@ public class FilteringDirectoryNode implements DirectoryEntry String name = entry.getName(); if (childExcludes.containsKey(name) && entry instanceof DirectoryEntry) { return new FilteringDirectoryNode( - (DirectoryEntry)entry, childExcludes.get(name)); + (DirectoryEntry)entry, childExcludes.get(name)); } return entry; } @@ -172,7 +173,7 @@ public class FilteringDirectoryNode implements DirectoryEntry public boolean renameTo(String newName) { return directory.renameTo(newName); } - + public String getName() { return directory.getName(); } @@ -188,11 +189,11 @@ public class FilteringDirectoryNode implements DirectoryEntry public boolean isDocumentEntry() { return false; } - + private class FilteringIterator implements Iterator { private Iterator parent; private Entry next; - + private FilteringIterator() { parent = directory.getEntries(); locateNext(); @@ -207,17 +208,21 @@ public class FilteringDirectoryNode implements DirectoryEntry } } } - + public boolean hasNext() { return (next != null); } - + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Entry e = next; locateNext(); return e; } - + public void remove() { throw new UnsupportedOperationException("Remove not supported"); } diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java b/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java index 0a9465baaa..5bd83cbdf5 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.property.RootProperty; @@ -49,10 +50,10 @@ public class POIFSMiniStore extends BlockStore this._sbat_blocks = sbats; this._header = header; this._root = root; - + this._mini_stream = new POIFSStream(filesystem, root.getStartBlock()); } - + /** * Load the block at the given offset. */ @@ -61,18 +62,16 @@ public class POIFSMiniStore extends BlockStore int byteOffset = offset * POIFSConstants.SMALL_BLOCK_SIZE; int bigBlockNumber = byteOffset / _filesystem.getBigBlockSize(); int bigBlockOffset = byteOffset % _filesystem.getBigBlockSize(); - + // Now locate the data block for it Iterator it = _mini_stream.getBlockIterator(); for(int i=0; i private BlockStore blockStore; private int startBlock; private OutputStream outStream; - + /** * Constructor for an existing stream. It's up to you - * to know how to get the start block (eg from a - * {@link HeaderBlock} or a {@link Property}) + * to know how to get the start block (eg from a + * {@link HeaderBlock} or a {@link Property}) */ public POIFSStream(BlockStore blockStore, int startBlock) { this.blockStore = blockStore; this.startBlock = startBlock; } - + /** * Constructor for a new stream. A start block won't * be allocated until you begin writing to it. @@ -68,7 +69,7 @@ public class POIFSStream implements Iterable this.blockStore = blockStore; this.startBlock = POIFSConstants.END_OF_CHAIN; } - + /** * What block does this stream start at? * Will be {@link POIFSConstants#END_OF_CHAIN} for a @@ -85,7 +86,7 @@ public class POIFSStream implements Iterable public Iterator iterator() { return getBlockIterator(); } - + Iterator getBlockIterator() { if(startBlock == POIFSConstants.END_OF_CHAIN) { throw new IllegalStateException( @@ -113,11 +114,11 @@ public class POIFSStream implements Iterable } return outStream; } - + // TODO Streaming write support // TODO then convert fixed sized write to use streaming internally // TODO Append write support (probably streaming) - + /** * Frees all blocks in the stream */ @@ -135,14 +136,14 @@ public class POIFSStream implements Iterable } this.startBlock = POIFSConstants.END_OF_CHAIN; } - + /** * Class that handles a streaming read of one stream */ protected class StreamBlockByteBufferIterator implements Iterator { private ChainLoopDetector loopDetector; private int nextBlock; - + StreamBlockByteBufferIterator(int firstBlock) { this.nextBlock = firstBlock; try { @@ -157,10 +158,10 @@ public class POIFSStream implements Iterable } public ByteBuffer next() { - if(nextBlock == POIFSConstants.END_OF_CHAIN) { - throw new IndexOutOfBoundsException("Can't read past the end of the stream"); + if (!hasNext()) { + throw new NoSuchElementException("Can't read past the end of the stream"); } - + try { loopDetector.claim(nextBlock); ByteBuffer data = blockStore.getBlockAt(nextBlock); @@ -175,7 +176,7 @@ public class POIFSStream implements Iterable throw new UnsupportedOperationException(); } } - + protected class StreamBlockByteBuffer extends OutputStream { byte[] oneByte = new byte[1]; ByteBuffer buffer; @@ -192,25 +193,25 @@ public class POIFSStream implements Iterable void createBlockIfNeeded() throws IOException { if (buffer != null && buffer.hasRemaining()) return; - + int thisBlock = nextBlock; - + // Allocate a block if needed, otherwise figure // out what the next block will be if(thisBlock == POIFSConstants.END_OF_CHAIN) { thisBlock = blockStore.getFreeBlock(); loopDetector.claim(thisBlock); - + // We're on the end of the chain nextBlock = POIFSConstants.END_OF_CHAIN; - + // Mark the previous block as carrying on to us if needed if(prevBlock != POIFSConstants.END_OF_CHAIN) { blockStore.setNextBlock(prevBlock, thisBlock); } blockStore.setNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN); - - // If we've just written the first block on a + + // If we've just written the first block on a // new stream, save the start block offset if(startBlock == POIFSConstants.END_OF_CHAIN) { startBlock = thisBlock; @@ -221,7 +222,7 @@ public class POIFSStream implements Iterable } buffer = blockStore.createBlockIfNeeded(thisBlock); - + // Update pointers prevBlock = thisBlock; } @@ -249,12 +250,12 @@ public class POIFSStream implements Iterable len -= writeBytes; } while (len > 0); } - + public void close() throws IOException { // If we're overwriting, free any remaining blocks POIFSStream toFree = new POIFSStream(blockStore, nextBlock); toFree.free(loopDetector); - + // Mark the end of the stream, if we have any data if (prevBlock != POIFSConstants.END_OF_CHAIN) { blockStore.setNextBlock(prevBlock, POIFSConstants.END_OF_CHAIN); diff --git a/src/java/org/apache/poi/util/StringCodepointsIterable.java b/src/java/org/apache/poi/util/StringCodepointsIterable.java index a56a6ae6c1..5fb83935bb 100644 --- a/src/java/org/apache/poi/util/StringCodepointsIterable.java +++ b/src/java/org/apache/poi/util/StringCodepointsIterable.java @@ -18,6 +18,7 @@ package org.apache.poi.util; import java.util.Iterator; +import java.util.NoSuchElementException; // based on https://gist.github.com/EmmanuelOga/48df70b27ead4d80234b @Internal @@ -37,6 +38,9 @@ public class StringCodepointsIterable implements Iterable { @Override public String next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } int codePoint = StringCodepointsIterable.this.string.codePointAt(index); index += Character.charCount(codePoint); return new String(Character.toChars(codePoint)); diff --git a/src/java/org/apache/poi/util/StringUtil.java b/src/java/org/apache/poi/util/StringUtil.java index b946d65430..2bf29a55a0 100644 --- a/src/java/org/apache/poi/util/StringUtil.java +++ b/src/java/org/apache/poi/util/StringUtil.java @@ -17,9 +17,10 @@ package org.apache.poi.util; +import static java.nio.charset.StandardCharsets.ISO_8859_1; + import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Iterator; import java.util.Locale; /** @@ -27,7 +28,6 @@ import java.util.Locale; */ @Internal public final class StringUtil { - private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1; //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 10000000; @@ -305,38 +305,6 @@ public final class StringUtil { return haystack.regionMatches(true, start, suffix, 0, length); } - /** - * An Iterator over an array of Strings. - */ - public static class StringsIterator implements Iterator { - private String[] strings = {}; - private int position; - - public StringsIterator(String[] strings) { - if (strings != null) { - this.strings = strings.clone(); - } - } - - @Override - public boolean hasNext() { - return position < strings.length; - } - - @Override - public String next() { - int ourPos = position++; - if (ourPos >= strings.length) { - throw new ArrayIndexOutOfBoundsException(ourPos); - } - return strings[ourPos]; - } - - @Override - public void remove() { - } - } - @Internal public static String toLowerCase(char c) { return Character.toString(c).toLowerCase(Locale.ROOT); diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java index 2e603fe261..228cfd285f 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.function.Supplier; import org.apache.poi.common.usermodel.GenericRecord; @@ -172,6 +173,9 @@ public class HemfComment { @Override public EmfCommentData next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } EmfCommentData toReturn = currentRecord; final boolean isEOF = (limit == -1 || leis.getReadIndex() >= startIdx+limit); // (currentRecord instanceof HemfPlusMisc.EmfEof) diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java index dc5a2e3d57..bbe930f4ac 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java @@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emf; import java.io.IOException; import java.util.Iterator; +import java.util.NoSuchElementException; import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianInputStream; @@ -44,6 +45,9 @@ public class HemfRecordIterator implements Iterator { @Override public HemfRecord next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } HemfRecord toReturn = currentRecord; currentRecord = (currentRecord instanceof HemfMisc.EmfEof) ? null : _next(); return toReturn; diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java b/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java index d30ba5d79c..032ef0a86c 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java @@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emfplus; import java.io.IOException; import java.util.Iterator; +import java.util.NoSuchElementException; import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.RecordFormatException; @@ -49,6 +50,9 @@ public class HemfPlusRecordIterator implements Iterator { @Override public HemfPlusRecord next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } HemfPlusRecord toReturn = currentRecord; // add the size for recordId/flags/recordSize/dataSize = 12 bytes final boolean isEOF = (limit == -1 || (leis.getReadIndex()-startIdx)+12 > limit); diff --git a/src/scratchpad/src/org/apache/poi/hsmf/extractor/OutlookTextExtractor.java b/src/scratchpad/src/org/apache/poi/hsmf/extractor/OutlookTextExtractor.java index 0dff34f567..e11f005fe3 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/extractor/OutlookTextExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/extractor/OutlookTextExtractor.java @@ -16,6 +16,17 @@ ==================================================================== */ package org.apache.poi.hsmf.extractor; +import static org.apache.poi.util.StringUtil.startsWithIgnoreCase; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Locale; + import org.apache.poi.extractor.POIOLE2TextExtractor; import org.apache.poi.hsmf.MAPIMessage; import org.apache.poi.hsmf.datatypes.AttachmentChunks; @@ -24,16 +35,6 @@ import org.apache.poi.hsmf.exceptions.ChunkNotFoundException; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.LocaleUtil; -import org.apache.poi.util.Removal; -import org.apache.poi.util.StringUtil.StringsIterator; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.text.SimpleDateFormat; -import java.util.Locale; - -import static org.apache.poi.util.StringUtil.startsWithIgnoreCase; /** * A text extractor for HSMF (Outlook) .msg files. @@ -90,13 +91,11 @@ public class OutlookTextExtractor extends POIOLE2TextExtractor { msg.guess7BitEncoding(); // Off we go - StringsIterator emails; + Iterator emails; try { - emails = new StringsIterator( - msg.getRecipientEmailAddressList() - ); + emails = Arrays.asList(msg.getRecipientEmailAddressList()).iterator(); } catch (ChunkNotFoundException e) { - emails = new StringsIterator(new String[0]); + emails = Collections.emptyIterator(); } try { @@ -174,7 +173,7 @@ public class OutlookTextExtractor extends POIOLE2TextExtractor { * of emails, and does its best to return something like * "Nick ; Jim " */ - protected void handleEmails(StringBuilder s, String type, String displayText, StringsIterator emails) { + protected void handleEmails(StringBuilder s, String type, String displayText, Iterator emails) { if (displayText == null || displayText.length() == 0) { return; } diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java b/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java index b1fa580f75..65d9265ab0 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java @@ -18,18 +18,23 @@ package org.apache.poi.poifs.filesystem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - /** * Class to test FilteringDirectoryNode functionality */ @@ -68,16 +73,20 @@ public final class TestFilteringDirectoryNode { assertFalse(d.getEntry(eRoot.getName()).isDirectoryEntry()); assertTrue(d.getEntry(eRoot.getName()).isDocumentEntry()); - Iterator i = d.getEntries(); - assertEquals(dirA, i.next()); - assertEquals(dirB, i.next()); - assertEquals(eRoot, i.next()); - assertNull(i.next()); + Iterator i = d.getEntries(); + assertEquals(dirA, i.next()); + assertEquals(dirB, i.next()); + assertEquals(eRoot, i.next()); + try { + assertNull(i.next()); + fail("Should throw NoSuchElementException when depleted"); + } catch (NoSuchElementException ignored) { + } } @Test public void testChildFiltering() throws Exception { - List excl = Arrays.asList(new String[]{"NotThere", "AlsoNotThere", eRoot.getName()}); + List excl = Arrays.asList("NotThere", "AlsoNotThere", eRoot.getName()); FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); assertEquals(2, d.getEntryCount()); @@ -96,11 +105,15 @@ public final class TestFilteringDirectoryNode { Iterator i = d.getEntries(); assertEquals(dirA, i.next()); assertEquals(dirB, i.next()); - assertNull(i.next()); + try { + assertNull(i.next()); + fail("Should throw NoSuchElementException when depleted"); + } catch (NoSuchElementException ignored) { + } // Filter more - excl = Arrays.asList(new String[]{"NotThere", "AlsoNotThere", eRoot.getName(), dirA.getName()}); + excl = Arrays.asList("NotThere", "AlsoNotThere", eRoot.getName(), dirA.getName()); d = new FilteringDirectoryNode(fs.getRoot(), excl); assertEquals(1, d.getEntryCount()); @@ -122,11 +135,15 @@ public final class TestFilteringDirectoryNode { i = d.getEntries(); assertEquals(dirB, i.next()); - assertNull(i.next()); + try { + assertNull(i.next()); + fail("Should throw NoSuchElementException when depleted"); + } catch (NoSuchElementException ignored) { + } // Filter everything - excl = Arrays.asList(new String[]{"NotThere", eRoot.getName(), dirA.getName(), dirB.getName()}); + excl = Arrays.asList("NotThere", eRoot.getName(), dirA.getName(), dirB.getName()); d = new FilteringDirectoryNode(fs.getRoot(), excl); assertEquals(0, d.getEntryCount()); @@ -151,17 +168,19 @@ public final class TestFilteringDirectoryNode { } i = d.getEntries(); - assertNull(i.next()); + try { + assertNull(i.next()); + fail("Should throw NoSuchElementException when depleted"); + } catch (NoSuchElementException ignored) { + } } @Test public void testNestedFiltering() throws Exception { - List excl = Arrays.asList(new String[]{ - dirA.getName() + "/" + "MadeUp", - dirA.getName() + "/" + eA.getName(), - dirA.getName() + "/" + dirAA.getName() + "/Test", - eRoot.getName() - }); + List excl = Arrays.asList(dirA.getName() + "/" + "MadeUp", + dirA.getName() + "/" + eA.getName(), + dirA.getName() + "/" + dirAA.getName() + "/Test", + eRoot.getName()); FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); // Check main diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSMiniStore.java b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSMiniStore.java index ea70b4f146..92ea46c698 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSMiniStore.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSMiniStore.java @@ -26,6 +26,7 @@ import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.NoSuchElementException; import org.apache.poi.POIDataSamples; import org.apache.poi.poifs.common.POIFSConstants; @@ -38,7 +39,7 @@ import org.junit.Test; @SuppressWarnings("CatchMayIgnoreException") public final class TestPOIFSMiniStore { private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance(); - + /** * Check that for a given mini block, we can correctly figure * out what the next one is @@ -52,24 +53,24 @@ public final class TestPOIFSMiniStore { POIFSFileSystem fsD = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB,fsC,fsD}) { POIFSMiniStore ministore = fs.getMiniStore(); - + // 0 -> 51 is one stream for(int i=0; i<50; i++) { assertEquals(i+1, ministore.getNextBlock(i)); } assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50)); - + // 51 -> 103 is the next for(int i=51; i<103; i++) { assertEquals(i+1, ministore.getNextBlock(i)); } assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(103)); - + // Then there are 3 one block ones assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(104)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(105)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(106)); - + // 107 -> 154 is the next for(int i=107; i<154; i++) { assertEquals(i+1, ministore.getNextBlock(i)); @@ -81,32 +82,32 @@ public final class TestPOIFSMiniStore { assertEquals(i+1, ministore.getNextBlock(i)); } assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(160)); - + // 161 -> 166 is the next for(int i=161; i<166; i++) { assertEquals(i+1, ministore.getNextBlock(i)); } assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(166)); - + // 167 -> 172 is the next for(int i=167; i<172; i++) { assertEquals(i+1, ministore.getNextBlock(i)); } assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(172)); - + // Now some short ones assertEquals(174 , ministore.getNextBlock(173)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(174)); - + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(175)); - + assertEquals(177 , ministore.getNextBlock(176)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(177)); - + assertEquals(179 , ministore.getNextBlock(178)); assertEquals(180 , ministore.getNextBlock(179)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); - + // 181 onwards is free for(int i=181; i 179 -> 180, 181+ is free assertEquals(179 , ministore.getNextBlock(178)); assertEquals(180 , ministore.getNextBlock(179)); @@ -281,7 +282,7 @@ public final class TestPOIFSMiniStore { for(int i=181; i<256; i++) { assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); } - + // However, the ministore data only covers blocks to 183 for(int i=0; i<=183; i++) { ministore.getBlockAt(i); @@ -289,8 +290,8 @@ public final class TestPOIFSMiniStore { try { ministore.getBlockAt(184); fail("No block at 184"); - } catch(IndexOutOfBoundsException e) {} - + } catch(NoSuchElementException e) {} + // The ministore itself is made up of 23 big blocks Iterator it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); int count = 0; @@ -299,10 +300,10 @@ public final class TestPOIFSMiniStore { it.next(); } assertEquals(23, count); - + // Ask it to get block 184 with creating, it will do ministore.createBlockIfNeeded(184); - + // The ministore should be one big block bigger now it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); count = 0; @@ -311,7 +312,7 @@ public final class TestPOIFSMiniStore { it.next(); } assertEquals(24, count); - + // The mini block block counts now run to 191 for(int i=0; i<=191; i++) { ministore.getBlockAt(i); @@ -319,14 +320,14 @@ public final class TestPOIFSMiniStore { try { ministore.getBlockAt(192); fail("No block at 192"); - } catch(IndexOutOfBoundsException e) {} - - + } catch(NoSuchElementException e) {} + + // Now try writing through to 192, check that the SBAT and blocks are there byte[] data = new byte[15*64]; POIFSStream stream = new POIFSStream(ministore, 178); stream.updateContents(data); - + // Check now assertEquals(179 , ministore.getNextBlock(178)); assertEquals(180 , ministore.getNextBlock(179)); @@ -346,10 +347,10 @@ public final class TestPOIFSMiniStore { for(int i=193; i<256; i++) { assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); } - + fs.close(); } - + @Test public void testCreateMiniStoreFirst() throws Exception { POIFSFileSystem fs = new POIFSFileSystem(); @@ -365,14 +366,14 @@ public final class TestPOIFSMiniStore { try { ministore.getNextBlock(0); } catch (IndexOutOfBoundsException e) {} - + // Write a very small new document, will populate the ministore for us byte[] data = new byte[8]; for (int i=0; i i = stream.getBlockIterator(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b = i.next(); assertFalse(i.hasNext()); - assertFalse(i.hasNext()); - assertFalse(i.hasNext()); // Check the contents assertEquals((byte)0x81, b.get()); @@ -103,15 +100,10 @@ public final class TestPOIFSStream { POIFSStream stream = new POIFSStream(fs, 97); Iterator i = stream.getBlockIterator(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b97 = i.next(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b98 = i.next(); assertFalse(i.hasNext()); - assertFalse(i.hasNext()); - assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0x01, b97.get()); @@ -169,18 +161,21 @@ public final class TestPOIFSStream { // Check the contents // 1st block is at 0 + assertNotNull(b0); assertEquals((byte)0x9e, b0.get()); assertEquals((byte)0x75, b0.get()); assertEquals((byte)0x97, b0.get()); assertEquals((byte)0xf6, b0.get()); // 2nd block is at 1 + assertNotNull(b1); assertEquals((byte)0x86, b1.get()); assertEquals((byte)0x09, b1.get()); assertEquals((byte)0x22, b1.get()); assertEquals((byte)0xfb, b1.get()); // last block is at 89 + assertNotNull(b22); assertEquals((byte)0xfe, b22.get()); assertEquals((byte)0xff, b22.get()); assertEquals((byte)0x00, b22.get()); @@ -204,18 +199,12 @@ public final class TestPOIFSStream { POIFSStream stream = new POIFSStream(fs, 0); Iterator i = stream.getBlockIterator(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b0 = i.next(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b1 = i.next(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b2 = i.next(); assertFalse(i.hasNext()); - assertFalse(i.hasNext()); - assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0x9E, b0.get()); @@ -304,17 +293,12 @@ public final class TestPOIFSStream { POIFSStream stream = new POIFSStream(ministore, 178); Iterator i = stream.getBlockIterator(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b178 = i.next(); assertTrue(i.hasNext()); - assertTrue(i.hasNext()); ByteBuffer b179 = i.next(); assertTrue(i.hasNext()); ByteBuffer b180 = i.next(); assertFalse(i.hasNext()); - assertFalse(i.hasNext()); - assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0xfe, b178.get()); @@ -803,7 +787,7 @@ public final class TestPOIFSStream { try { ministore.getBlockAt(184); fail("Block 184 should be off the end of the list"); - } catch (IndexOutOfBoundsException e) { + } catch (NoSuchElementException e) { } data = new byte[64 * 6 + 12]; diff --git a/src/testcases/org/apache/poi/util/TestStringUtil.java b/src/testcases/org/apache/poi/util/TestStringUtil.java index 184cf12cf4..b70a7dbda1 100644 --- a/src/testcases/org/apache/poi/util/TestStringUtil.java +++ b/src/testcases/org/apache/poi/util/TestStringUtil.java @@ -24,7 +24,6 @@ import static org.junit.Assert.fail; import java.nio.charset.Charset; -import org.apache.poi.util.StringUtil.StringsIterator; import org.junit.Test; /** @@ -127,52 +126,6 @@ public class TestStringUtil { } } - @Test - public void testStringsIterator() { - StringsIterator i; - - - i = new StringsIterator(new String[0]); - assertFalse(i.hasNext()); - try { - i.next(); - fail(); - } catch(ArrayIndexOutOfBoundsException e) { - // expected here - } - - - i = new StringsIterator(new String[] {"1"}); - assertTrue(i.hasNext()); - assertEquals("1", i.next()); - - assertFalse(i.hasNext()); - try { - i.next(); - fail(); - } catch(ArrayIndexOutOfBoundsException e) { - // expected here - } - - - i = new StringsIterator(new String[] {"1","2","3"}); - assertTrue(i.hasNext()); - assertEquals("1", i.next()); - assertTrue(i.hasNext()); - assertEquals("2", i.next()); - assertTrue(i.hasNext()); - assertEquals("3", i.next()); - - assertFalse(i.hasNext()); - try { - i.next(); - fail(); - } catch(ArrayIndexOutOfBoundsException e) { - // expected here - } - } - - @Test public void startsWithIgnoreCase() { assertTrue("same string", StringUtil.startsWithIgnoreCase("Apache POI", "Apache POI")); @@ -181,7 +134,7 @@ public class TestStringUtil { assertFalse("leading whitespace should not be ignored", StringUtil.startsWithIgnoreCase(" Apache POI project", "Apache POI")); assertFalse("shorter string", StringUtil.startsWithIgnoreCase("Apache", "Apache POI")); } - + @Test public void endsWithIgnoreCase() { assertTrue("same string", StringUtil.endsWithIgnoreCase("Apache POI", "Apache POI")); @@ -190,34 +143,34 @@ public class TestStringUtil { assertFalse("trailing whitespace should not be ignored", StringUtil.endsWithIgnoreCase("Apache POI project ", "Apache POI")); assertFalse("shorter string", StringUtil.endsWithIgnoreCase("Apache", "Apache POI")); } - + @Test public void join() { assertEquals("", StringUtil.join(",")); // degenerate case: nothing to join assertEquals("abc", StringUtil.join(",", "abc")); // degenerate case: one thing to join, no trailing comma assertEquals("abc|def|ghi", StringUtil.join("|", "abc", "def", "ghi")); assertEquals("5|8.5|true|string", StringUtil.join("|", 5, 8.5, true, "string")); //assumes Locale prints number decimal point as a period rather than a comma - + String[] arr = new String[] { "Apache", "POI", "project" }; assertEquals("no separator", "ApachePOIproject", StringUtil.join(arr)); assertEquals("separator", "Apache POI project", StringUtil.join(arr, " ")); } - + @Test public void count() { String test = "Apache POI project\n\u00a9 Copyright 2016"; // supports search in null or empty string assertEquals("null", 0, StringUtil.countMatches(null, 'A')); assertEquals("empty string", 0, StringUtil.countMatches("", 'A')); - + assertEquals("normal", 2, StringUtil.countMatches(test, 'e')); assertEquals("normal, should not find a in escaped copyright", 1, StringUtil.countMatches(test, 'a')); - + // search for non-printable characters assertEquals("null character", 0, StringUtil.countMatches(test, '\0')); assertEquals("CR", 0, StringUtil.countMatches(test, '\r')); assertEquals("LF", 1, StringUtil.countMatches(test, '\n')); - + // search for unicode characters assertEquals("Unicode", 1, StringUtil.countMatches(test, '\u00a9')); }