Author: desruisseaux
Date: Tue Aug  8 11:15:52 2017
New Revision: 1804399

URL: http://svn.apache.org/viewvc?rev=1804399&view=rev
Log:
Add tests for WritablePixelIterator.

Added:
    
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java
      - copied, changed from r1804398, 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
Removed:
    
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
Modified:
    
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
    
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
    
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java
    
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java

Modified: 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java?rev=1804399&r1=1804398&r2=1804399&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
 [UTF-8] Tue Aug  8 11:15:52 2017
@@ -279,6 +279,18 @@ public abstract class PixelIterator {
     }
 
     /**
+     * Returns {@code true} if this iterator can write pixel values (after 
cast to {@code WritablePixelIterator}).
+     * This method should be used instead than {@code instanceof} check 
because, for some implementations, being
+     * an instance of {@code WritablePixelIterator} is not a sufficient 
condition.
+     *
+     * @return {@code true} if this iterator can safely be casted to {@link 
WritablePixelIterator} and used for
+     *         writing pixel values.
+     */
+    public boolean isWritable() {
+        return false;
+    }
+
+    /**
      * Returns the most efficient type ({@code int}, {@code float} or {@code 
double}) for transferring data between the
      * underlying rasters and this iterator. The transfer type is not 
necessarily the storage type used by the rasters.
      * For example {@code int} values will be used for transferring data even 
if the underlying rasters store all sample

Modified: 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java?rev=1804399&r1=1804398&r2=1804399&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
 [UTF-8] Tue Aug  8 11:15:52 2017
@@ -32,9 +32,11 @@ import org.apache.sis.util.ArgumentCheck
 /**
  * A pixel iterator capable to write sample values. This iterator can edit 
pixel values in place,
  * or write values in a different destination image than the source image. 
Source and destination
- * images must use the same sample model,
+ * images must use the same sample model and the same coordinates (both for 
pixels and tiles).
+ *
+ * <p>Contrarily to {@code PixelIterator}, {@code WritablePixelIterator} needs 
to be closed after
+ * iteration in order to release tiles. Example:</p>
  *
- * <p>Usage example:</p>
  * {@preformat java
  *     try (WritablePixelIterator it = WritablePixelIterator.create(image)) {
  *         double[] samples = null;
@@ -46,6 +48,10 @@ import org.apache.sis.util.ArgumentCheck
  *     }
  * }
  *
+ * <div class="section">Casting a {@code PixelIterator}</div>
+ * To check if a {@code PixelIterator} can be used for writing pixels, a 
{@code … instanceof WritablePixelIterator}
+ * check is not sufficient. The {@link PixelIterator#isWritable()} method 
should be invoked instead.
+ *
  * @author  Rémi Maréchal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
@@ -213,6 +219,19 @@ public abstract class WritablePixelItera
     }
 
     /**
+     * Returns {@code true} if this iterator can write pixel values.
+     * This method should be used instead than {@code instanceof} check 
because, for some implementations, being an
+     * instance of {@code WritablePixelIterator} is not a sufficient 
condition. However this method is guaranteed to
+     * return {@code true} for any iterator created by {@code 
WritablePixelIterator.create(…)} methods.
+     *
+     * @return {@code true} if this iterator can be used for writing pixel 
values.
+     */
+    @Override
+    public boolean isWritable() {
+        return (destination != null) || (destRaster != null);
+    }
+
+    /**
      * Writes a sample value in the specified band of current pixel.
      * The {@link #next()} method must have returned {@code true}, or the 
{@link #moveTo(int,int)} method must have
      * been invoked successfully, before this {@code setSample(int, int)} 
method is invoked. If above condition is

Copied: 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java
 (from r1804398, 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java)
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java?p2=sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java&p1=sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java&r1=1804398&r2=1804399&rev=1804399&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/DefaultIteratorTest.java
 [UTF-8] Tue Aug  8 11:15:52 2017
@@ -28,14 +28,16 @@ import java.nio.FloatBuffer;
 import org.opengis.coverage.grid.SequenceType;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
+import org.junit.After;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
 
 
 /**
- * Base class of {@link PixelIterator} tests. This base class tests the 
default read-only iterator
- * on signed short integer values. Subclasses will test variants, for example 
the read-write iterator.
+ * Base class of {@link PixelIterator} tests. This base class tests the 
default read-write iterator
+ * on signed short integer values. Subclasses will test variants, for example 
optimized iterators
+ * for some specific sample models.
  *
  * @author  Rémi Maréchal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -43,12 +45,12 @@ import static org.junit.Assert.*;
  * @since   0.8
  * @module
  */
-public strictfp class PixelIteratorTest extends TestCase {
+public strictfp class DefaultIteratorTest extends TestCase {
     /**
      * The pixel iterator being tested.
      * This field is initialized by a call to one of the {@code 
createPixelIterator(…)} methods.
      */
-    private PixelIterator iterator;
+    private WritablePixelIterator iterator;
 
     /**
      * The raster or image data type as one of the {@link DataBuffer} 
constants.
@@ -104,18 +106,23 @@ public strictfp class PixelIteratorTest
     private float[] expected;
 
     /**
+     * {@code true} for testing write operations in addition of read 
operations.
+     */
+    private boolean isWritable;
+
+    /**
      * Creates a new test case for the given data type.
      *
      * @param  dataType  the raster or image data type as one of the {@link 
DataBuffer} constants.
      */
-    PixelIteratorTest(final int dataType) {
+    DefaultIteratorTest(final int dataType) {
         this.dataType = dataType;
     }
 
     /**
      * Creates a new test case.
      */
-    public PixelIteratorTest() {
+    public DefaultIteratorTest() {
         this(DataBuffer.TYPE_SHORT);
     }
 
@@ -240,50 +247,62 @@ public strictfp class PixelIteratorTest
      * Creates a {@code PixelIterator} for a sub-area of given raster.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
-     * <p>The default implementation creates read-only iterators.
-     * Tests for read-write iterators need to override.</p>
+     * <p>The default implementation creates {@link DefaultIterator} instances.
+     * Tests for other kinds of iterator need to override.</p>
      *
      * @param  raster   the data on which to perform iteration.
      * @param  subArea  the boundary of the raster sub-area where to perform 
iteration.
      */
     void createPixelIterator(WritableRaster raster, Rectangle subArea) {
-        iterator = new DefaultIterator(raster, null, subArea, null);
+        iterator = new DefaultIterator(raster, isWritable ? raster : null, 
subArea, null);
         assertEquals("getIterationOrder()", SequenceType.LINEAR, 
iterator.getIterationOrder());
+        assertEquals("isWritable", isWritable, iterator.isWritable());
     }
 
     /**
      * Creates a {@code PixelIterator} for a sub-area of given image.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
-     * <p>The default implementation creates read-only iterators.
-     * Tests for read-write iterators need to override.</p>
+     * <p>The default implementation creates {@link DefaultIterator} instances.
+     * Tests for other kinds of iterator need to override.</p>
      *
      * @param  image    the data on which to perform iteration.
      * @param  subArea  the boundary of the image sub-area where to perform 
iteration.
      */
     void createPixelIterator(WritableRenderedImage image, Rectangle subArea) {
-        iterator = new DefaultIterator(image, null, subArea, null);
+        iterator = new DefaultIterator(image, isWritable ? image : null, 
subArea, null);
+        assertEquals("isWritable", isWritable, iterator.isWritable());
     }
 
     /**
      * Creates a {@code PixelIterator} for a window in the given image.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
-     * <p>The default implementation creates read-only iterators.
-     * Tests for read-write iterators need to override.</p>
+     * <p>The default implementation creates {@link DefaultIterator} instances.
+     * Tests for other kinds of iterator need to override.</p>
      *
      * @param  image    the data on which to perform iteration.
      * @param  window   size of the window to use in {@link 
PixelIterator#createWindow(TransferType)} method.
      */
     void createWindowIterator(WritableRenderedImage image, Dimension window) {
-        iterator = new DefaultIterator(image, null, null, window);
+        iterator = new DefaultIterator(image, isWritable ? image : null, null, 
window);
+        assertEquals("isWritable", isWritable, iterator.isWritable());
+    }
+
+    /**
+     * Invoked after every tests for releasing resources.
+     */
+    @After
+    public void dispose() {
+        iterator.close();
     }
 
     /**
      * Verifies the sample value at current iterator position.
+     * If the iterator is writable, tests also setting a value.
      *
-     * @param i  index in {@link #expected} array.
-     * @param b  band number at current iterator position.
+     * @param  i  index in {@link #expected} array.
+     * @param  b  band number at current iterator position.
      */
     private void verifySample(final int i, final int b) {
         final float e = expected[i];
@@ -291,13 +310,19 @@ public strictfp class PixelIteratorTest
         if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(e)) {
             fail("Pixel iteration at index " + i + ": expected " + e + " but 
got " + a);
         }
+        if (isWritable) {
+            final float newValue = a + 20;
+            iterator.setSample(b, newValue);
+            assertEquals("Verification after write", newValue, 
iterator.getSampleFloat(b), 0f);
+            expected[i] = newValue;
+        }
     }
 
     /**
      * Iterates over all values returned by the current {@link #iterator} and 
compares with expected values.
      *
-     * @param verifyIndices  whether to verify also iterator {@code 
getPosition()} return values.
-     *                       This is usually {@code true} if an only if the 
iterator cover the full raster area.
+     * @param  verifyIndices  whether to verify also iterator {@code 
getPosition()} return values.
+     *                        This is usually {@code true} if an only if the 
iterator cover the full raster area.
      *
      * @see #verifyIterationAfterMove(int, int)
      * @see #verifyWindow(Dimension)
@@ -1091,4 +1116,37 @@ public strictfp class PixelIteratorTest
         assertNull("getIterationOrder()", iterator.getIterationOrder());
         verifyWindow(window);
     }
+
+    /**
+     * Tests write operations in a single raster.
+     * The destination image is the same than the source image.
+     */
+    @Test
+    @DependsOnMethod("testOnRasterSubArea")
+    public void testOnWritableRaster() {
+        isWritable = true;
+        testOnRasterSubArea();
+    }
+
+    /**
+     * Tests write operations in a single tile of an image.
+     * The destination image is the same than the source image.
+     */
+    @Test
+    @DependsOnMethod({"testOnWritableRaster", "testOnTileSubArea"})
+    public void testOnWritableTile() {
+        isWritable = true;
+        testOnTileSubArea();
+    }
+
+    /**
+     * Tests write operations in a tiled image.
+     * The destination image is the same than the source image.
+     */
+    @Test
+    @DependsOnMethod({"testOnWritableTile", "testOnImageSubArea"})
+    public void testOnWritableImage() {
+        isWritable = true;
+        testOnImageSubArea();
+    }
 }

Modified: 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java?rev=1804399&r1=1804398&r2=1804399&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/TiledImage.java
 [UTF-8] Tue Aug  8 11:15:52 2017
@@ -29,6 +29,8 @@ import java.awt.image.WritableRaster;
 import java.awt.image.WritableRenderedImage;
 import java.util.Vector;
 
+import static org.junit.Assert.*;
+
 
 /**
  * A rendered image which can contain an arbitrary number of tiles. Tiles are 
stored in memory.
@@ -79,6 +81,16 @@ final class TiledImage implements Writab
     private final SampleModel sampleModel;
 
     /**
+     * Indices of acquired tiles. Those indices are valid only if {@link 
#isTileAcquired} is {@code true}.
+     */
+    private int acquiredTileX, acquiredTileY;
+
+    /**
+     * Whether a tile has been acquired by a call to {@link 
#getWritableTile(int, int)} and not yet released.
+     */
+    private boolean isTileAcquired;
+
+    /**
      * Creates a new tiled image.
      *
      * @param dataType  sample data type as one of the {@link 
java.awt.image.DataBuffer} constants.
@@ -152,23 +164,41 @@ final class TiledImage implements Writab
         if (ox < 0 || ox >= width || oy < 0 || oy >= height) {
             throw new IndexOutOfBoundsException();
         }
-        getWritableTile(ox / tileWidth  + minTileX,
-                        oy / tileHeight + minTileY).setSample(x, y, b, value);
+        tile(ox / tileWidth  + minTileX,
+             oy / tileHeight + minTileY).setSample(x, y, b, value);
     }
 
     /**
      * Returns the tile at the given location in tile coordinates.
+     * This method verifies that no writable raster have been acquired. 
Actually this conditions is not part of
+     * {@link WritableRenderedImage} contract, since a readable and writable 
rasters can be used in same time.
+     * But we add this condition because they way {@link PixelIterator} are 
currently implemented, it would be
+     * a bug if we ask for a readable tile while we already have a writable 
one. This condition may change in
+     * any future Apache SIS version.
      */
     @Override
     public Raster getTile(final int tileX, final int tileY) {
-        return getWritableTile(tileX, tileY);
+        assertFalse("isTileAcquired", isTileAcquired);              // See 
javadoc.
+        return tile(tileX, tileY);
     }
 
     /**
      * Returns the tile at the given location tile coordinates.
      */
     @Override
-    public WritableRaster getWritableTile(int tileX, int tileY) {
+    public WritableRaster getWritableTile(final int tileX, final int tileY) {
+        assertFalse("isTileAcquired", isTileAcquired);
+        isTileAcquired = true;
+        acquiredTileX  = tileX;
+        acquiredTileY  = tileY;
+        return tile(tileX, tileY);
+    }
+
+    /**
+     * Returns the tile at the given index without any verification. It is 
caller responsibility to verify if this
+     * method is invoked in a consistent context (for example after a writable 
raster has been properly acquired).
+     */
+    private WritableRaster tile(int tileX, int tileY) {
         if ((tileX -= minTileX) < 0 || tileX >= numXTiles ||
             (tileY -= minTileY) < 0 || tileY >= numYTiles)
         {
@@ -185,19 +215,23 @@ final class TiledImage implements Writab
     }
 
     /**
-     * Ignored since this implementation does not need to be informed
-     * about when the user is doing with the {@link WritableRaster}.
+     * Verifies that the given tile has been acquired.
      */
     @Override
-    public void releaseWritableTile(int tileX, int tileY) {
+    public void releaseWritableTile(final int tileX, final int tileY) {
+        assertTrue("isTileAcquired", isTileAcquired);
+        assertEquals("tileX", acquiredTileX, tileX);
+        assertEquals("tileY", acquiredTileY, tileY);
+        isTileAcquired = false;
     }
 
     /**
-     * Returns {@code false} since we do not keep track of who called {@link 
#getWritableTile(int,int)}.
+     * Returns {@code true} if the given tile indices are the one given to the 
last call to
+     * {@link #getWritableTile(int, int)} and that tile has not yet been 
released.
      */
     @Override
-    public boolean isTileWritable(int tileX, int tileY) {
-        return false;
+    public boolean isTileWritable(final int tileX, final int tileY) {
+        return isTileAcquired && (tileX == acquiredTileX) && (tileY == 
acquiredTileY);
     }
 
     /**
@@ -205,15 +239,15 @@ final class TiledImage implements Writab
      */
     @Override
     public boolean hasTileWriters() {
-        return false;
+        return isTileAcquired;
     }
 
     /**
-     * Returns {@code null} since we do not keep track of who called {@link 
#getWritableTile(int,int)}.
+     * Returns the indices of acquired tile, or {@code null} if none.
      */
     @Override
     public Point[] getWritableTileIndices() {
-        return null;
+        return isTileAcquired ? new Point[] {new Point(acquiredTileX, 
acquiredTileY)} : null;
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java?rev=1804399&r1=1804398&r2=1804399&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
 [UTF-8] Tue Aug  8 11:15:52 2017
@@ -30,7 +30,7 @@ import org.junit.BeforeClass;
  * @module
  */
 @Suite.SuiteClasses({
-    org.apache.sis.image.PixelIteratorTest.class
+    org.apache.sis.image.DefaultIteratorTest.class
 })
 public final strictfp class RasterTestSuite extends TestSuite {
     /**


Reply via email to