This is an automated email from the ASF dual-hosted git repository.

jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 39fc3245a1 feat(Shapefile): test add, remove and update from 
WritableFeatureSet
39fc3245a1 is described below

commit 39fc3245a1e9c1be8fcc5f981d785464164a184e
Author: jsorel <[email protected]>
AuthorDate: Tue Dec 5 15:24:29 2023 +0100

    feat(Shapefile): test add, remove and update from WritableFeatureSet
---
 .../sis/storage/shapefile/ShapefileStore.java      |  5 +-
 .../apache/sis/storage/shapefile/dbf/DBFField.java | 58 +++++++++-----
 .../sis/storage/shapefile/ShapefileStoreTest.java  | 89 ++++++++++++++++++----
 3 files changed, 115 insertions(+), 37 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
index 2d6fe5e827..6c755a466e 100644
--- 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
@@ -172,7 +172,6 @@ public final class ShapefileStore extends DataStore 
implements WritableFeatureSe
     public void close() throws DataStoreException {
     }
 
-
     /*
     Redirect FeatureSet interface to View
     */
@@ -649,9 +648,9 @@ public final class ShapefileStore extends DataStore 
implements WritableFeatureSe
                         } else if (Long.class.isAssignableFrom(valueClass)) {
                             dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_NUMBER, 0, 19, 0, null));
                         } else if (Float.class.isAssignableFrom(valueClass)) {
-                            dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_NUMBER, 0, 11, 8, null));
+                            dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_NUMBER, 0, 11, 6, null));
                         } else if (Double.class.isAssignableFrom(valueClass)) {
-                            dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_NUMBER, 0, 33, 30, null));
+                            dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_NUMBER, 0, 33, 18, null));
                         } else if 
(LocalDate.class.isAssignableFrom(valueClass)) {
                             dbfHeader.fields = 
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char) 
DBFField.TYPE_DATE, 0, 20, 0, null));
                         } else {
diff --git 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
index 85976ea76a..564bd7ba9d 100644
--- 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
@@ -111,6 +111,7 @@ public final class DBFField {
             case TYPE_NUMBER : {
                 if (fieldDecimals != 0) {  valueClass = Double.class;  reader 
= this::readNumber;     writer = this::writeNumber;
                     format = NumberFormat.getNumberInstance(Locale.US);
+                    format.setGroupingUsed(false);
                     format.setMaximumFractionDigits(fieldDecimals);
                     format.setMinimumFractionDigits(fieldDecimals);
                 }
@@ -198,7 +199,20 @@ public final class DBFField {
     }
 
     private Object readLogic(ChannelDataInput channel) throws IOException {
-        throw new UnsupportedOperationException();
+        final String str = new 
String(channel.readBytes(fieldLength)).trim().toLowerCase();
+        final char c = str.charAt(0);
+        switch (c) {
+            case '1':
+            case 't':
+            case 'y':
+                return Boolean.TRUE;
+            case '0':
+            case 'f':
+            case 'n':
+                return Boolean.FALSE;
+            default:
+                throw new IOException("Unexpected logic value : " + str);
+        }
     }
 
     private Object readMemo(ChannelDataInput channel) throws IOException {
@@ -218,11 +232,11 @@ public final class DBFField {
     }
 
     private Object readFloat(ChannelDataInput channel) throws IOException {
-        throw new UnsupportedOperationException();
+        return channel.readFloat();
     }
 
     private Object readDouble(ChannelDataInput channel) throws IOException {
-        throw new UnsupportedOperationException();
+        return channel.readDouble();
     }
 
     private Object readOLE(ChannelDataInput channel) throws IOException {
@@ -260,6 +274,7 @@ public final class DBFField {
         sb.append(month);
         if(day.length() < 2) sb.append("0");
         sb.append(day);
+        ensureLength(sb.toString());
         channel.repeat(fieldLength - sb.length(), (byte)' ');
         channel.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
     }
@@ -268,32 +283,30 @@ public final class DBFField {
         final Number v = ((Number) value);
         final String str = format.format(v.doubleValue());
         final int length = str.length();
+        ensureLength(str);
         channel.repeat(fieldLength - length, (byte)' ');
         channel.write(str.getBytes(StandardCharsets.US_ASCII));
     }
 
     private void writeNumberInt(ChannelDataOutput channel, Object value) 
throws IOException {
-        final String v = ((Integer) value).toString();
-        final int length = v.length();
-        if (length > fieldLength) {
-            throw new IOException(v + " is longer then field length " + 
fieldLength);
-        }
-        channel.repeat(fieldLength - length, (byte)' ');
-        channel.write(v.getBytes(StandardCharsets.US_ASCII));
+        final String str = ((Integer) value).toString();
+        ensureLength(str);
+        channel.repeat(fieldLength - str.length(), (byte)' ');
+        channel.write(str.getBytes(StandardCharsets.US_ASCII));
     }
 
     private void writeNumberLong(ChannelDataOutput channel, Object value) 
throws IOException {
-        final String v = ((Long) value).toString();
-        final int length = v.length();
-        if (length > fieldLength) {
-            throw new IOException(v + " is longer then field length " + 
fieldLength);
-        }
-        channel.repeat(fieldLength - length, (byte)' ');
-        channel.write(v.getBytes(StandardCharsets.US_ASCII));
+        final String str = ((Long) value).toString();
+        ensureLength(str);
+        channel.repeat(fieldLength - str.length(), (byte)' ');
+        channel.write(str.getBytes(StandardCharsets.US_ASCII));
     }
 
     private void writeLogic(ChannelDataOutput channel, Object value) throws 
IOException {
-        throw new UnsupportedOperationException();
+        final String str = Boolean.TRUE.equals(value) ? "T" : "F";
+        ensureLength(str);
+        channel.repeat(fieldLength - str.length(), (byte)' ');
+        channel.write(str.getBytes(StandardCharsets.US_ASCII));
     }
 
     private void writeMemo(ChannelDataOutput channel, Object value) throws 
IOException {
@@ -313,17 +326,22 @@ public final class DBFField {
     }
 
     private void writeFloat(ChannelDataOutput channel, Object value) throws 
IOException {
-        throw new UnsupportedOperationException();
+        channel.writeFloat(((Number)value).floatValue());
     }
 
     private void writeDouble(ChannelDataOutput channel, Object value) throws 
IOException {
-        throw new UnsupportedOperationException();
+        channel.writeDouble(((Number)value).doubleValue());
     }
 
     private void writeOLE(ChannelDataOutput channel, Object value) throws 
IOException {
         throw new UnsupportedOperationException();
     }
 
+    private void ensureLength(String str) throws IOException{
+        final int remain = fieldLength - str.length();
+        if (remain < 0) throw new IOException("Failed to write field value" + 
str + ", value is larger then field " + this);
+    }
+
     @Override
     public String toString() {
         return "DBFField{" +
diff --git 
a/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
 
b/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
index 6fd3fcf34c..4ea5bcbb25 100644
--- 
a/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.shapefile;
 
+import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -23,8 +24,10 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.time.LocalDate;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.UnaryOperator;
 import java.util.stream.Stream;
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.util.Utilities;
@@ -48,6 +51,7 @@ import org.junit.Test;
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
+import org.opengis.filter.BinaryComparisonOperator;
 import org.opengis.filter.FilterFactory;
 
 
@@ -194,8 +198,8 @@ public class ShapefileStoreTest {
      */
     @Test
     public void testCreate() throws URISyntaxException, DataStoreException, 
IOException {
-        final Path temp = Files.createTempFile("test", ".shp");
-        Files.delete(temp);
+        final Path folder = Files.createTempDirectory("shapefileTest");
+        final Path temp = folder.resolve("test.shp");
         final String name = temp.getFileName().toString().split("\\.")[0];
         try (final ShapefileStore store = new ShapefileStore(temp)) {
             Path[] componentFiles = store.getComponentFiles();
@@ -219,7 +223,6 @@ public class ShapefileStoreTest {
             {// check created type
                 FeatureType type = store.getType();
                 assertEquals(name, type.getName().toString());
-                System.out.println(type.toString());
                 assertEquals(9, type.getProperties(true).size());
                 assertNotNull(type.getProperty("sis:identifier"));
                 assertNotNull(type.getProperty("sis:envelope"));
@@ -239,17 +242,18 @@ public class ShapefileStoreTest {
                 assertEquals(Double.class, floatProp.getValueClass());
                 assertEquals(LocalDate.class, dateProp.getValueClass());
             }
+        } finally {
+            deleteDirectory(folder);
         }
     }
 
     /**
      * Test adding features to a shapefile.
      */
-    @Ignore
     @Test
     public void testAddFeatures() throws URISyntaxException, 
DataStoreException, IOException {
-        final Path temp = Files.createTempFile("test", ".shp");
-        Files.delete(temp);
+        final Path folder = Files.createTempDirectory("shapefileTest");
+        final Path temp = folder.resolve("test.shp");
         try (final ShapefileStore store = new ShapefileStore(temp)) {
             FeatureType type = createType();
             store.updateType(type);
@@ -260,27 +264,76 @@ public class ShapefileStoreTest {
             store.add(List.of(feature1, feature2).iterator());
 
             Object[] result = store.features(false).toArray();
-
-
+            assertEquals(2, result.length);
+            assertEquals(feature1, result[0]);
+            assertEquals(feature2, result[1]);
+        } finally {
+            deleteDirectory(folder);
         }
     }
 
     /**
      * Test remove features from a shapefile.
      */
-    @Ignore
     @Test
-    public void testRemoveFeatures() throws URISyntaxException, 
DataStoreException {
-        //todo
+    public void testRemoveFeatures() throws DataStoreException, IOException {
+        final Path folder = Files.createTempDirectory("shapefileTest");
+        final Path temp = folder.resolve("test.shp");
+        try (final ShapefileStore store = new ShapefileStore(temp)) {
+            FeatureType type = createType();
+            store.updateType(type);
+            type = store.getType();
+            Feature feature1 = createFeature1(type);
+            Feature feature2 = createFeature2(type);
+            store.add(List.of(feature1, feature2).iterator());
+
+            //remove first feature
+            final FilterFactory<Feature, Object, Object> ff = 
DefaultFilterFactory.forFeatures();
+            final BinaryComparisonOperator<Feature> filter = 
ff.equal(ff.property("id"), ff.literal(1));
+            store.removeIf(filter);
+
+            Object[] result = store.features(false).toArray();
+            assertEquals(1, result.length);
+            assertEquals(feature2, result[0]);
+        } finally {
+            deleteDirectory(folder);
+        }
     }
 
     /**
      * Test replacing features in a shapefile.
      */
-    @Ignore
     @Test
-    public void testReplaceFeatures() throws URISyntaxException, 
DataStoreException {
-        //todo
+    public void testReplaceFeatures() throws DataStoreException, IOException {
+        final Path folder = Files.createTempDirectory("shapefileTest");
+        final Path temp = folder.resolve("test.shp");
+        try (final ShapefileStore store = new ShapefileStore(temp)) {
+            FeatureType type = createType();
+            store.updateType(type);
+            type = store.getType();
+            Feature feature1 = createFeature1(type);
+            Feature feature2 = createFeature2(type);
+            store.add(List.of(feature1, feature2).iterator());
+
+            //remove first feature
+            final FilterFactory<Feature, Object, Object> ff = 
DefaultFilterFactory.forFeatures();
+            final BinaryComparisonOperator<Feature> filter = 
ff.equal(ff.property("id"), ff.literal(1));
+            store.replaceIf(filter, new UnaryOperator<Feature>() {
+                @Override
+                public Feature apply(Feature feature) {
+                    feature.setPropertyValue("id",45);
+                    return feature;
+                }
+            });
+
+            Object[] result = store.features(false).toArray();
+            assertEquals(2, result.length);
+            Feature f1 = (Feature) result[0];
+            assertEquals(45, f1.getPropertyValue("id"));
+            assertEquals(feature2, result[1]);
+        } finally {
+            deleteDirectory(folder);
+        }
     }
 
     private static FeatureType createType() {
@@ -317,4 +370,12 @@ public class ShapefileStoreTest {
         return feature;
     }
 
+    private static void deleteDirectory(Path path) throws IOException{
+        try (Stream<Path> stream = Files.walk(path)) {
+            stream.sorted(Comparator.reverseOrder())
+                    .map(Path::toFile)
+                    .forEach(File::delete);
+        }
+    }
+
 }

Reply via email to