Author: msahyoun
Date: Mon Dec 23 10:55:46 2019
New Revision: 1871922

URL: http://svn.apache.org/viewvc?rev=1871922&view=rev
Log:
PDFBOX-4669: throw UnsupportedOperationException for remove operation for a 
filtered list; adjust unit test

Modified:
    
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java
    
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/COSArrayListTest.java

Modified: 
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java
URL: 
http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java?rev=1871922&r1=1871921&r2=1871922&view=diff
==============================================================================
--- 
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java
 (original)
+++ 
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java
 Mon Dec 23 10:55:46 2019
@@ -43,6 +43,10 @@ public class COSArrayList<E> implements
     private final COSArray array;
     private final List<E> actual;
 
+    // indicates that the list has been filtered
+    // i.e. the number of entries in array and actual differ 
+    private boolean isFiltered = false;
+
     private COSDictionary parentDict;
     private COSName dictKey;
 
@@ -65,6 +69,12 @@ public class COSArrayList<E> implements
     {
         actual = actualList;
         array = cosArray;
+
+        // if the number of entries differs this may come from a filter being
+        // applied at the PDModel level 
+        if (actual.size() != array.size()) {
+            isFiltered = true;
+        }
     }
 
     /**
@@ -200,6 +210,11 @@ public class COSArrayList<E> implements
     @Override
     public boolean remove(Object o)
     {
+
+        if (isFiltered) {
+            throw new UnsupportedOperationException("removing entries from a 
filtered List is not permitted");
+        }
+
         boolean retval = true;
         int index = actual.indexOf( o );
         if( index >= 0 )
@@ -607,8 +622,13 @@ public class COSArrayList<E> implements
     @Override
     public E remove(int index)
     {
+        if (isFiltered) {
+            throw new UnsupportedOperationException("removing entries from a 
filtered List is not permitted");
+        }
+
         E toBeRemoved = actual.get(index);
-        remove(toBeRemoved);
+        array.remove(index);
+        actual.remove(index);
         return toBeRemoved;
     }
 

Modified: 
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/COSArrayListTest.java
URL: 
http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/COSArrayListTest.java?rev=1871922&r1=1871921&r2=1871922&view=diff
==============================================================================
--- 
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/COSArrayListTest.java
 (original)
+++ 
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/COSArrayListTest.java
 Mon Dec 23 10:55:46 2019
@@ -16,14 +16,15 @@
 package org.apache.pdfbox.pdmodel.common;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.interactive.annotation.AnnotationFilter;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
@@ -31,9 +32,15 @@ import org.apache.pdfbox.pdmodel.interac
 import 
org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationSquareCircle;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class COSArrayListTest {
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
     // next two entries are to be used for comparison with
     // COSArrayList behaviour in order to ensure that the
     // intented object is now at the correct position.
@@ -64,25 +71,29 @@ public class COSArrayListTest {
         annotationsList.add(txtMark);
         annotationsList.add(txtLink);
         annotationsList.add(aCircle);
-        assertTrue(annotationsList.size() == 3);
+        annotationsList.add(txtLink);
+        assertTrue(annotationsList.size() == 4);
 
         tbcAnnotationsList = new ArrayList<PDAnnotation>();
         tbcAnnotationsList.add(txtMark);
         tbcAnnotationsList.add(txtLink);
         tbcAnnotationsList.add(aCircle);
-        assertTrue(tbcAnnotationsList.size() == 3);
+        tbcAnnotationsList.add(txtLink);
+        assertTrue(tbcAnnotationsList.size() == 4);
 
         annotationsArray = new COSArray();
         annotationsArray.add(txtMark);
         annotationsArray.add(txtLink);
         annotationsArray.add(aCircle);
-        assertTrue(annotationsArray.size() == 3);
+        annotationsArray.add(txtLink);
+        assertTrue(annotationsArray.size() == 4);
 
-        tbcAnnotationsArray = new COSBase[3];
+        tbcAnnotationsArray = new COSBase[4];
         tbcAnnotationsArray[0] = txtMark.getCOSObject();
         tbcAnnotationsArray[1] = txtLink.getCOSObject();
         tbcAnnotationsArray[2] = aCircle.getCOSObject();
-        assertTrue(tbcAnnotationsArray.length == 3);
+        tbcAnnotationsArray[3] = txtLink.getCOSObject();
+        assertTrue(tbcAnnotationsArray.length == 4);
 
         // add the annotations to the page
         pdPage = new PDPage();
@@ -96,17 +107,16 @@ public class COSArrayListTest {
     public void getFromList() throws Exception {
         COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
 
-        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < cosArrayList.size(); i++) {
             PDAnnotation annot = (PDAnnotation) cosArrayList.get(i);
-            // compare position using COSArrayList
-            assertTrue("PDAnnotations cosObject at " + i + " shall be at index 
" + i + " of COSArray",
-                    annotationsArray.indexOf(annot.getCOSObject()) == i);
+            assertTrue("PDAnnotations cosObject at " + i + " shall be equal to 
index " + i + " of COSArray",
+                annotationsArray.get(i).equals(annot.getCOSObject()));
 
             // compare with Java List/Array
             assertTrue("PDAnnotations at " + i + " shall be at index " + i + " 
of List",
-                    tbcAnnotationsList.indexOf(annot) == i);
+                tbcAnnotationsList.get(i).equals((annot)));
             assertEquals("PDAnnotations cosObject at " + i + " shall be at 
position " + i + " of Array",
-                    tbcAnnotationsArray[i], annot.getCOSObject());
+                tbcAnnotationsArray[i], annot.getCOSObject());
         }
     }
 
@@ -121,12 +131,12 @@ public class COSArrayListTest {
         PDAnnotationSquareCircle aSquare = new 
PDAnnotationSquareCircle(PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
         cosArrayList.add(aSquare);
 
-        assertTrue("List size shall be 4", annotationsList.size() == 4);
-        assertTrue("COSArray size shall be 4", annotationsArray.size() == 4);
+        assertTrue("List size shall be 5", annotationsList.size() == 5);
+        assertTrue("COSArray size shall be 5", annotationsArray.size() == 5);
 
-        PDAnnotation annot = (PDAnnotation) annotationsList.get(3);
-        assertTrue("Added annotation shall be 4th entry in COSArray", 
annotationsArray.indexOf(annot.getCOSObject()) == 3);
-        assertEquals("Provided COSArray and underlying COSArray shall be 
equal", annotationsArray, cosArrayList.toList());
+        PDAnnotation annot = (PDAnnotation) annotationsList.get(4);
+        assertTrue("Added annotation shall be 4th entry in COSArray", 
annotationsArray.indexOf(annot.getCOSObject()) == 4);
+        assertEquals("Provided COSArray and underlying COSArray shall be 
equal", annotationsArray, cosArrayList.getCOSArray());
     }
 
     /**
@@ -136,66 +146,114 @@ public class COSArrayListTest {
     public void removeFromListByIndex() throws Exception {
         COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
 
-        int positionToRemove = 1;
+        int positionToRemove = 2;
         cosArrayList.remove(positionToRemove);
 
-        assertTrue("List size shall be 2", cosArrayList.size() == 2);
-        assertTrue("COSArray size shall be 2", annotationsArray.size() == 2);
+        assertTrue("List size shall be 3", cosArrayList.size() == 3);
+        assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
 
-        PDAnnotation annot = (PDAnnotation) cosArrayList.get(1);
-        assertTrue("Object at original position 2 shall now be at position 1 
in underlying COSArray",
-                annotationsArray.indexOf(annot.getCOSObject()) == 1);
+        assertTrue("PDAnnotation shall no longer exist in List",
+            cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == 
-1);
+        assertTrue("COSObject shall no longer exist in COSArray",
+            annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == 
-1);
+    }
+
+    /**
+     * Test removing a unique PDModel element by index is in sync with 
underlying COSArray
+     */
+    @Test
+    public void removeUniqueFromListByObject() throws Exception {
+        COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
+
+        int positionToRemove = 2;
+        PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
+
+        assertTrue("Remove operation shall return 
true",cosArrayList.remove(toBeRemoved));
+        assertTrue("List size shall be 3", cosArrayList.size() == 3);
+        assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
 
         // compare with Java List/Array to ensure correct object at position
-        assertTrue("List object at 2 is at position 1 in COSArrayList now",
-                cosArrayList.indexOf(tbcAnnotationsList.get(2)) == 1);
-        assertTrue("COSObject of List object at 2 is at position 1 in COSArray 
now",
-                
annotationsArray.indexOf(tbcAnnotationsList.get(2).getCOSObject()) == 1);
-        assertTrue("Array object at 2 is at position 1 in underlying COSArray 
now",
-                annotationsArray.indexOf(tbcAnnotationsArray[2]) == 1);
+        assertTrue("List object at 3 is at position 2 in COSArrayList now",
+            cosArrayList.get(2).equals(tbcAnnotationsList.get(3)));
+        assertTrue("COSObject of List object at 3 is at position 2 in COSArray 
now",
+            
annotationsArray.get(2).equals(tbcAnnotationsList.get(3).getCOSObject()));
+        assertTrue("Array object at 3 is at position 2 in underlying COSArray 
now",
+            annotationsArray.get(2).equals(tbcAnnotationsArray[3]));
 
         assertTrue("PDAnnotation shall no longer exist in List",
-                cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) 
== -1);
+            cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == 
-1);
         assertTrue("COSObject shall no longer exist in COSArray",
-                
annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
+            annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == 
-1);
+
+        assertFalse("Remove shall not remove any 
object",cosArrayList.remove(toBeRemoved));
+
     }
 
     /**
-     * Test removing a PDModel element by index is in sync with underlying 
COSArray
+     * Test removing a unique PDModel element by index is in sync with 
underlying COSArray
+     */
+    @Test
+    public void removeAllUniqueFromListByObject() throws Exception {
+        COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
+
+        int positionToRemove = 2;
+        PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
+
+        List<PDAnnotation> toBeRemovedInstances = 
Collections.singletonList(toBeRemoved);
+
+        assertTrue("Remove operation shall return 
true",cosArrayList.removeAll(toBeRemovedInstances));
+        assertTrue("List size shall be 3", cosArrayList.size() == 3);
+        assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
+
+        assertFalse("Remove shall not remove any 
object",cosArrayList.removeAll(toBeRemovedInstances));
+    }
+
+
+    /**
+     * Test removing a multiple appearing PDModel element by index is in sync 
with underlying COSArray
      */
     @Test
-    public void removeFromListByObject() throws Exception {
+    public void removeMultipleFromListByObject() throws Exception {
         COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
 
         int positionToRemove = 1;
         PDAnnotation toBeRemoved = tbcAnnotationsList.get(positionToRemove);
 
-        cosArrayList.remove(toBeRemoved);
+        assertTrue("Remove operation shall return 
true",cosArrayList.remove(toBeRemoved));
+        assertTrue("List size shall be 3", cosArrayList.size() == 3);
+        assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
 
+        assertTrue("Remove operation shall return 
true",cosArrayList.remove(toBeRemoved));
         assertTrue("List size shall be 2", cosArrayList.size() == 2);
         assertTrue("COSArray size shall be 2", annotationsArray.size() == 2);
 
-        PDAnnotation annot = (PDAnnotation) cosArrayList.get(1);
-        assertTrue("Object at original position 2 shall now be at position 1 
in underlying COSArray",
-                annotationsArray.indexOf(annot.getCOSObject()) == 1);
+    }
 
-        // compare with Java List/Array to ensure correct object at position
-        assertTrue("List object at 2 is at position 1 in COSArrayList now",
-                cosArrayList.indexOf(tbcAnnotationsList.get(2)) == 1);
-        assertTrue("COSObject of List object at 2 is at position 1 in COSArray 
now",
-                
annotationsArray.indexOf(tbcAnnotationsList.get(2).getCOSObject()) == 1);
-        assertTrue("Array object at 2 is at position 1 in underlying COSArray 
now",
-                annotationsArray.indexOf(tbcAnnotationsArray[2]) == 1);
+        /**
+     * Test removing a unique PDModel element by index is in sync with 
underlying COSArray
+     */
+    @Test
+    public void removeAllMultipleFromListByObject() throws Exception {
+        COSArrayList<PDAnnotation> cosArrayList = new 
COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
 
-        assertTrue("PDAnnotation shall no longer exist in List",
-                cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) 
== -1);
-        assertTrue("COSObject shall no longer exist in COSArray",
-                
annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
+        int positionToRemove = 1;
+        PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
+
+        List<PDAnnotation> toBeRemovedInstances = 
Collections.singletonList(toBeRemoved);
+
+        assertTrue("Remove operation shall return 
true",cosArrayList.removeAll(toBeRemovedInstances));
+        assertTrue("List size shall be 2", cosArrayList.size() == 2);
+        assertTrue("COSArray size shall be 2", annotationsArray.size() == 2);
+
+        assertFalse("Remove shall not remove any 
object",cosArrayList.removeAll(toBeRemovedInstances));
     }
 
     @Test
     public void removeFromFilteredListByIndex() throws Exception
     {
+        // removing from a filtered list is not permitted
+        thrown.expect(UnsupportedOperationException.class);
+
         // retrieve all annotations from page but the link annotation
         // which is 2nd in list - see above setup
         AnnotationFilter annotsFilter = new AnnotationFilter()
@@ -208,31 +266,18 @@ public class COSArrayListTest {
         };
 
         COSArrayList<PDAnnotation> cosArrayList = (COSArrayList<PDAnnotation>) 
pdPage.getAnnotations(annotsFilter);
-        COSArray underlyingCOSArray = 
pdPage.getCOSObject().getCOSArray(COSName.ANNOTS);
-
-        assertTrue("Filtered COSArrayList size shall be 2", 
cosArrayList.size() == 2);
-        assertTrue("Underlying COSArray shall have 3 entries", 
underlyingCOSArray.size() == 3);
-        assertTrue("Backed COSArray shall have 3 entries", 
cosArrayList.getCOSArray().size() == 3);
 
-        // remove aCircle annotation
-        int positionToRemove = 1;
-        PDAnnotation toBeRemoved = cosArrayList.get(positionToRemove);
-        assertTrue("We should remove the circle annotation", 
toBeRemoved.getSubtype().equals(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE));
-        cosArrayList.remove(positionToRemove);
-
-        assertTrue("List size shall be 2", cosArrayList.size() == 1);
-        assertTrue("COSArray size shall be 2", underlyingCOSArray.size() == 2);
-        assertTrue("Backed COSArray size shall be 2", 
cosArrayList.getCOSArray().size() == 2);
-
-        assertTrue("Removed annotation shall no longer appear in 
COSArrayList", cosArrayList.indexOf(toBeRemoved) == -1);
-        assertTrue("Removed annotation shall no longer appear in underlying 
COSArray", underlyingCOSArray.indexOf(toBeRemoved.getCOSObject()) == -1);
-        assertTrue("Removed annotation shall no longer appear in backed 
COSArray", cosArrayList.getCOSArray().indexOf(toBeRemoved.getCOSObject()) == 
-1);
+        // this call should fail
+        cosArrayList.remove(1);
     }
     
 
     @Test
     public void removeFromFilteredListByObject() throws Exception
     {
+        // removing from a filtered list is not permitted
+        thrown.expect(UnsupportedOperationException.class);
+        
         // retrieve all annotations from page but the link annotation
         // which is 2nd in list - see above setup
         AnnotationFilter annotsFilter = new AnnotationFilter()
@@ -245,24 +290,13 @@ public class COSArrayListTest {
         };
 
         COSArrayList<PDAnnotation> cosArrayList = (COSArrayList<PDAnnotation>) 
pdPage.getAnnotations(annotsFilter);
-        COSArray underlyingCOSArray = 
pdPage.getCOSObject().getCOSArray(COSName.ANNOTS);
-
-        assertTrue("Filtered COSArrayList size shall be 2", 
cosArrayList.size() == 2);
-        assertTrue("Underlying COSArray shall have 3 entries", 
underlyingCOSArray.size() == 3);
-        assertTrue("Backed COSArray shall have 3 entries", 
cosArrayList.getCOSArray().size() == 3);
 
-        // remove aCircle annotation
+        // remove object
         int positionToRemove = 1;
         PDAnnotation toBeRemoved = cosArrayList.get(positionToRemove);
-        assertTrue("We should remove the circle annotation", 
toBeRemoved.getSubtype().equals(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE));
+
+        // this call should fail
         cosArrayList.remove(toBeRemoved);
 
-        assertTrue("List size shall be 2", cosArrayList.size() == 1);
-        assertTrue("COSArray size shall be 2", underlyingCOSArray.size() == 2);
-        assertTrue("Backed COSArray size shall be 2", 
cosArrayList.getCOSArray().size() == 2);
-
-        assertTrue("Removed annotation shall no longer appear in 
COSArrayList", cosArrayList.indexOf(toBeRemoved) == -1);
-        assertTrue("Removed annotation shall no longer appear in underlying 
COSArray", underlyingCOSArray.indexOf(toBeRemoved.getCOSObject()) == -1);
-        assertTrue("Removed annotation shall no longer appear in backed 
COSArray", cosArrayList.getCOSArray().indexOf(toBeRemoved.getCOSObject()) == 
-1);
     }
 }
\ No newline at end of file


Reply via email to