diff --git a/PERF/cdm-v4.properties b/PERF/cdm-v4.properties index 424602f3..6f88489f 100644 --- a/PERF/cdm-v4.properties +++ b/PERF/cdm-v4.properties @@ -216,6 +216,10 @@ spark.cdm.perfops.writeRateLimit 5000 # as Epoch milliseconds # TIMESTAMP_STRING_FORMAT : timestamp stored in a String, # with a custom format +# POLYGON_TYPE : PolygonType geospatial DSE type +# POINT_TYPE : PointType geospatial DSE type +# LINE_STRING : LineStringType geospatial DSE type +# DATE_RANGE : DateRange DSE type # # *** NOTE where there are multiple type pair options, such as with # *** TIMESTAMP_STRING, only one can be configured at a time. diff --git a/pom.xml b/pom.xml index 5fb71789..278c1d57 100644 --- a/pom.xml +++ b/pom.xml @@ -143,6 +143,12 @@ log4j-to-slf4j ${log4j.version} + + runtime + com.esri.geometry + esri-geometry-api + 2.2.0 + @@ -326,7 +332,7 @@ LINE MISSEDCOUNT - 3073 + 3085 diff --git a/src/main/java/com/datastax/cdm/cql/codec/CodecFactory.java b/src/main/java/com/datastax/cdm/cql/codec/CodecFactory.java index b0c484f2..24a71104 100644 --- a/src/main/java/com/datastax/cdm/cql/codec/CodecFactory.java +++ b/src/main/java/com/datastax/cdm/cql/codec/CodecFactory.java @@ -1,6 +1,10 @@ package com.datastax.cdm.cql.codec; import com.datastax.cdm.properties.PropertyHelper; +import com.datastax.dse.driver.internal.core.type.codec.geometry.LineStringCodec; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PointCodec; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PolygonCodec; +import com.datastax.dse.driver.internal.core.type.codec.time.DateRangeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import java.util.Arrays; @@ -15,6 +19,11 @@ public static List> getCodecPair(PropertyHelper propertyHelper, Cod case DECIMAL_STRING: return Arrays.asList(new DECIMAL_StringCodec(propertyHelper), new TEXT_BigDecimalCodec(propertyHelper)); case TIMESTAMP_STRING_MILLIS: return Arrays.asList(new TIMESTAMP_StringMillisCodec(propertyHelper), new TEXTMillis_InstantCodec(propertyHelper)); case TIMESTAMP_STRING_FORMAT: return Arrays.asList(new TIMESTAMP_StringFormatCodec(propertyHelper), new TEXTFormat_InstantCodec(propertyHelper)); + case POLYGON_TYPE: return Arrays.asList(new PolygonCodec()); + case POINT_TYPE: return Arrays.asList(new PointCodec()); + case DATE_RANGE: return Arrays.asList(new DateRangeCodec()); + case LINE_STRING: return Arrays.asList(new LineStringCodec()); + default: throw new IllegalArgumentException("Unknown codec: " + codec); } diff --git a/src/main/java/com/datastax/cdm/cql/codec/Codecset.java b/src/main/java/com/datastax/cdm/cql/codec/Codecset.java index fe5d954f..d5ad2ee6 100644 --- a/src/main/java/com/datastax/cdm/cql/codec/Codecset.java +++ b/src/main/java/com/datastax/cdm/cql/codec/Codecset.java @@ -6,5 +6,9 @@ public enum Codecset { BIGINT_STRING, DECIMAL_STRING, TIMESTAMP_STRING_MILLIS, - TIMESTAMP_STRING_FORMAT + TIMESTAMP_STRING_FORMAT, + POINT_TYPE, + POLYGON_TYPE, + DATE_RANGE, + LINE_STRING } diff --git a/src/main/java/com/datastax/cdm/data/CqlData.java b/src/main/java/com/datastax/cdm/data/CqlData.java index e5e40a6b..3141ef09 100644 --- a/src/main/java/com/datastax/cdm/data/CqlData.java +++ b/src/main/java/com/datastax/cdm/data/CqlData.java @@ -1,5 +1,6 @@ package com.datastax.cdm.data; +import com.datastax.dse.driver.api.core.type.DseDataTypes; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.*; @@ -39,6 +40,10 @@ public enum Type { primitiveDataTypeToJavaClassMap.put(DataTypes.TIMEUUID, java.util.UUID.class); primitiveDataTypeToJavaClassMap.put(DataTypes.COUNTER, Long.class); primitiveDataTypeToJavaClassMap.put(DataTypes.DURATION, com.datastax.oss.driver.api.core.data.CqlDuration.class); + primitiveDataTypeToJavaClassMap.put(DseDataTypes.POLYGON, com.datastax.dse.driver.api.core.data.geometry.Polygon.class); + primitiveDataTypeToJavaClassMap.put(DseDataTypes.POINT, com.datastax.dse.driver.api.core.data.geometry.Point.class); + primitiveDataTypeToJavaClassMap.put(DseDataTypes.LINE_STRING, com.datastax.dse.driver.api.core.data.geometry.LineString.class); + primitiveDataTypeToJavaClassMap.put(DseDataTypes.DATE_RANGE, com.datastax.dse.driver.api.core.data.time.DateRange.class); } public static Type toType(DataType dataType) { diff --git a/src/test/java/com/datastax/cdm/cql/codec/CodecFactoryTest.java b/src/test/java/com/datastax/cdm/cql/codec/CodecFactoryTest.java new file mode 100644 index 00000000..45ec4838 --- /dev/null +++ b/src/test/java/com/datastax/cdm/cql/codec/CodecFactoryTest.java @@ -0,0 +1,114 @@ +package com.datastax.cdm.cql.codec; + +import com.datastax.cdm.data.MockitoExtension; +import com.datastax.cdm.properties.PropertyHelper; +import com.datastax.dse.driver.internal.core.type.codec.geometry.LineStringCodec; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PointCodec; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PolygonCodec; +import com.datastax.dse.driver.internal.core.type.codec.time.DateRangeCodec; +import com.datastax.oss.driver.api.core.type.codec.TypeCodec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +class CodecFactoryTest { + @Mock + private PropertyHelper propertyHelper; + + @BeforeEach + void setUp() { + //Mockito.when(propertyHelper.getString("timestamp.format")).thenReturn("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForPolygonType() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.POLYGON_TYPE); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof PolygonCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForIntString() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.INT_STRING); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof INT_StringCodec); + assertTrue(codecs.get(1) instanceof TEXT_IntegerCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForDoubleString() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.DOUBLE_STRING); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof DOUBLE_StringCodec); + assertTrue(codecs.get(1) instanceof TEXT_DoubleCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForBigintString() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.BIGINT_STRING); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof BIGINT_StringCodec); + assertTrue(codecs.get(1) instanceof TEXT_LongCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForDecimalString() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.DECIMAL_STRING); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof DECIMAL_StringCodec); + assertTrue(codecs.get(1) instanceof TEXT_BigDecimalCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForTimestampStringMillis() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.TIMESTAMP_STRING_MILLIS); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof TIMESTAMP_StringMillisCodec); + assertTrue(codecs.get(1) instanceof TEXTMillis_InstantCodec); + } + +// @Test +// void getCodecPair_ShouldReturnCorrectCodecsForTimestampStringFormat() { +// Mockito.when(propertyHelper.getString("timestamp.format")).thenReturn("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); +// List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.TIMESTAMP_STRING_FORMAT); +// assertFalse(codecs.isEmpty()); +// assertTrue(codecs.get(0) instanceof TIMESTAMP_StringFormatCodec); +// assertTrue(codecs.get(1) instanceof TEXTFormat_InstantCodec); +// } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForPointType() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.POINT_TYPE); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof PointCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForDateRange() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.DATE_RANGE); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof DateRangeCodec); + } + + @Test + void getCodecPair_ShouldReturnCorrectCodecsForLineString() { + List> codecs = CodecFactory.getCodecPair(propertyHelper, Codecset.LINE_STRING); + assertFalse(codecs.isEmpty()); + assertTrue(codecs.get(0) instanceof LineStringCodec); + } + + @Test + void getCodecPair_ShouldThrowExceptionForUnknownCodec() { + assertThrows(NullPointerException.class, () -> { + CodecFactory.getCodecPair(propertyHelper, null); + }); + } + +} diff --git a/src/test/java/com/datastax/cdm/cql/codec/DATERANGETYPE_CodecTest.java b/src/test/java/com/datastax/cdm/cql/codec/DATERANGETYPE_CodecTest.java new file mode 100644 index 00000000..45c9f366 --- /dev/null +++ b/src/test/java/com/datastax/cdm/cql/codec/DATERANGETYPE_CodecTest.java @@ -0,0 +1,127 @@ +package com.datastax.cdm.cql.codec; + +import com.datastax.dse.driver.api.core.data.time.DateRange; +import com.datastax.dse.driver.internal.core.type.codec.time.DateRangeCodec; +import com.datastax.oss.driver.api.core.ProtocolVersion; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.nio.ByteBuffer; +import java.text.ParseException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import static org.junit.jupiter.api.Assertions.*; + +class DATERANGETYPE_CodecTest { + + private DateRangeCodec codec; + private final ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT; + + @BeforeEach + void setUp() { + codec = new DateRangeCodec(); + } + + @Test + void encode_ShouldEncodeDateRangeToByteBuffer() throws ParseException { + String dateRangeString = "2001-01-01"; + DateRange dateRange; + try { + dateRange = DateRange.parse(dateRangeString); + } catch (ParseException e) { + fail("Failed to parse the date range: " + e.getMessage()); + return; + } + + // Encode the DateRange object + ByteBuffer encoded = codec.encode(dateRange, protocolVersion); + + // Assertions + assertNotNull(encoded); + assertTrue(encoded.remaining() > 0); + + // Decode the ByteBuffer back to a DateRange and compare + DateRange decoded = codec.decode(encoded, protocolVersion); + assertEquals(dateRange, decoded); + } + + @Test + void decode_ShouldDecodeByteBufferToDateRange() throws ParseException { + ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.DAYS); + String expectedFormattedDate = DateTimeFormatter.ISO_LOCAL_DATE.format(zonedDateTime); + + // Create a DateRange object using a string in the expected format + DateRange dateRange = DateRange.parse(expectedFormattedDate); + String formatted = codec.format(dateRange); + + // The formatted string should be surrounded by single quotes, remove them for the comparison + String unquotedFormatted = formatted.replace("'", ""); + assertEquals(expectedFormattedDate, unquotedFormatted); + } + + @Test + void format_ShouldFormatDateRangeToString() throws ParseException { + String dateRangeString = "2001-01-01"; // Adjust this string to the correct format + DateRange dateRange; + try { + dateRange = DateRange.parse(dateRangeString); + } catch (ParseException e) { + fail("Failed to parse the date range for setup: " + e.getMessage()); + return; + } + + // Format the date range using the codec + String formatted = codec.format(dateRange); + assertNotNull(formatted); + + // Remove single quotes for parsing + String unquotedFormatted = formatted.replace("'", ""); + DateRange parsedDateRange; + try { + parsedDateRange = DateRange.parse(unquotedFormatted); + } catch (ParseException e) { + fail("Failed to parse the formatted date range: " + e.getMessage()); + return; + } + + // The parsed DateRange should equal the original DateRange + assertEquals(dateRange, parsedDateRange); + } + + @Test + void parse_ShouldParseStringToDateRange() throws ParseException { + String formattedDateTime = ZonedDateTime.now() + .withZoneSameInstant(ZoneOffset.UTC) + .truncatedTo(ChronoUnit.MILLIS) + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + + // Enclose in single quotes as per the error message + String dateRangeLiteral = "'" + formattedDateTime + "'"; + + // Attempt to parse it using the codec + DateRange parsedDateRange; + try { + parsedDateRange = codec.parse(dateRangeLiteral); + } catch (Exception e) { + fail("Parsing failed with exception: " + e.getMessage()); + return; + } + + assertNotNull(parsedDateRange); + } + + @Test + void encode_ShouldHandleNullValues() { + ByteBuffer result = codec.encode(null, protocolVersion); + assertNull(result); + } + + @Test + void decode_ShouldHandleNullByteBuffer() { + DateRange result = codec.decode(null, protocolVersion); + assertNull(result); + } +} diff --git a/src/test/java/com/datastax/cdm/cql/codec/LINESTRINGTYPE_CodecTest.java b/src/test/java/com/datastax/cdm/cql/codec/LINESTRINGTYPE_CodecTest.java new file mode 100644 index 00000000..490f79c5 --- /dev/null +++ b/src/test/java/com/datastax/cdm/cql/codec/LINESTRINGTYPE_CodecTest.java @@ -0,0 +1,81 @@ +package com.datastax.cdm.cql.codec; + +import com.datastax.cdm.data.CqlConversion; +import com.datastax.dse.driver.api.core.data.geometry.LineString; +import com.datastax.dse.driver.internal.core.data.geometry.DefaultLineString; +import com.datastax.dse.driver.internal.core.type.codec.geometry.LineStringCodec; +import com.esri.core.geometry.ogc.OGCLineString; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.*; + +class LINESTRINGTYPE_CodecTest { + + private LineStringCodec codec; + + @BeforeEach + void setUp() { + codec = new LineStringCodec(); + } + + @Test + void encode_ShouldEncodeLineStringToByteBuffer() { + LineString lineString = new DefaultLineString((OGCLineString) OGCLineString.fromText("LINESTRING (30 10, 10 30, 40 40)")); + ByteBuffer encoded = codec.encode(lineString, CqlConversion.PROTOCOL_VERSION); + + assertNotNull(encoded); + assertTrue(encoded.remaining() > 0); + + ByteBuffer expected = codec.encode(lineString, CqlConversion.PROTOCOL_VERSION); + assertTrue(expected.equals(encoded)); + } + + @Test + void decode_ShouldDecodeByteBufferToLineString() { + String lineString = "LINESTRING (30 10, 10 30, 40 40)"; + LineString expectedLineString = new DefaultLineString((OGCLineString) OGCLineString.fromText(lineString)); + ByteBuffer byteBuffer = codec.encode(expectedLineString, CqlConversion.PROTOCOL_VERSION); + + LineString actualLineString = codec.decode(byteBuffer, CqlConversion.PROTOCOL_VERSION); + + assertNotNull(actualLineString); + String actualWkt = actualLineString.asWellKnownText(); + assertEquals(lineString, actualWkt); + } + + @Test + void format_ShouldFormatLineStringToWktString() { + String line = "LINESTRING (30 10, 10 30, 40 40)"; + LineString lineString = new DefaultLineString((OGCLineString) OGCLineString.fromText(line)); + + String formatted = codec.format(lineString); + assertNotNull(formatted); + + String unquotedFormatted = formatted.replace("'", ""); + assertEquals(line, unquotedFormatted); + } + + @Test + void parse_ShouldParseWktStringToLineString() { + String stringLineString = "LINESTRING (30 10, 10 30, 40 40)"; + String quotedLineString = "'" + stringLineString + "'"; + LineString parsedLineString = codec.parse(quotedLineString); + + assertNotNull(parsedLineString); + assertEquals(stringLineString, parsedLineString.asWellKnownText()); + } + + @Test + void encode_ShouldHandleNullValues() { + ByteBuffer result = codec.encode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } + + @Test + void decode_ShouldHandleNullByteBuffer() { + LineString result = codec.decode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } +} diff --git a/src/test/java/com/datastax/cdm/cql/codec/POINTTYPE_CodecTest.java b/src/test/java/com/datastax/cdm/cql/codec/POINTTYPE_CodecTest.java new file mode 100644 index 00000000..f9bfc767 --- /dev/null +++ b/src/test/java/com/datastax/cdm/cql/codec/POINTTYPE_CodecTest.java @@ -0,0 +1,81 @@ +package com.datastax.cdm.cql.codec; + +import com.datastax.cdm.data.CqlConversion; +import com.datastax.dse.driver.api.core.data.geometry.Point; +import com.datastax.dse.driver.internal.core.data.geometry.DefaultPoint; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PointCodec; +import com.esri.core.geometry.ogc.OGCPoint; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.*; + +class POINTTYPE_CodecTest { + + private PointCodec codec; + + @BeforeEach + void setUp() { + codec = new PointCodec(); + } + + @Test + void encode_ShouldEncodePointToByteBuffer() { + Point point = new DefaultPoint((OGCPoint) OGCPoint.fromText("POINT (30 10)")); + ByteBuffer encoded = codec.encode(point, CqlConversion.PROTOCOL_VERSION); + + assertNotNull(encoded); + assertTrue(encoded.remaining() > 0); + + ByteBuffer expected = codec.encode(point, CqlConversion.PROTOCOL_VERSION); + assertTrue(expected.equals(encoded)); + } + + @Test + void decode_ShouldDecodeByteBufferToPoint() { + String wkt = "POINT (30 10)"; + Point expectedPoint = new DefaultPoint((OGCPoint) OGCPoint.fromText(wkt)); + ByteBuffer byteBuffer = codec.encode(expectedPoint, CqlConversion.PROTOCOL_VERSION); + + Point actualPoint = codec.decode(byteBuffer, CqlConversion.PROTOCOL_VERSION); + + assertNotNull(actualPoint); + String actualWkt = actualPoint.asWellKnownText(); + assertEquals(wkt, actualWkt); + } + + @Test + void format_ShouldFormatPointToWktString() { + String wkt = "POINT (30 10)"; + Point point = new DefaultPoint((OGCPoint) OGCPoint.fromText(wkt)); + + String formatted = codec.format(point); + assertNotNull(formatted); + + String unquotedFormatted = formatted.replace("'", ""); + assertEquals(wkt, unquotedFormatted); + } + + @Test + void parse_ShouldParseWktStringToPoint() { + String stringPoint = "POINT (30 10)"; + String quotedPoint = "'" + stringPoint + "'"; + Point parsedPoint = codec.parse(quotedPoint); + + assertNotNull(parsedPoint); + assertEquals(stringPoint, parsedPoint.asWellKnownText()); + } + + @Test + void encode_ShouldHandleNullValues() { + ByteBuffer result = codec.encode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } + + @Test + void decode_ShouldHandleNullByteBuffer() { + Point result = codec.decode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } +} diff --git a/src/test/java/com/datastax/cdm/cql/codec/POLYGONTYPE_CodecTest.java b/src/test/java/com/datastax/cdm/cql/codec/POLYGONTYPE_CodecTest.java new file mode 100644 index 00000000..22ca2723 --- /dev/null +++ b/src/test/java/com/datastax/cdm/cql/codec/POLYGONTYPE_CodecTest.java @@ -0,0 +1,92 @@ +package com.datastax.cdm.cql.codec; + +import com.datastax.cdm.data.CqlConversion; +import com.datastax.dse.driver.api.core.data.geometry.Polygon; +import com.datastax.dse.driver.internal.core.data.geometry.DefaultPolygon; +import com.datastax.dse.driver.internal.core.type.codec.geometry.PolygonCodec; +import com.esri.core.geometry.ogc.OGCPolygon; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.*; + +class POLYGONTYPE_CodecTest { + + private PolygonCodec codec; + + @BeforeEach + void setUp() { + codec = new PolygonCodec(); + } + + @Test + void encode_ShouldEncodePolygonToByteBuffer() { + Polygon polygon = new DefaultPolygon((OGCPolygon) OGCPolygon.fromText("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))")); + ByteBuffer encoded = codec.encode(polygon, CqlConversion.PROTOCOL_VERSION); // Assuming protocol version is not needed or a mock version is provided + + // Assert that the result is not null + assertNotNull(encoded); + + // Assert that the ByteBuffer is not empty + assertTrue(encoded.remaining() > 0); + + ByteBuffer expected = codec.encode(polygon, CqlConversion.PROTOCOL_VERSION); + assertTrue(expected.equals(encoded)); + } + + @Test + void decode_ShouldDecodeByteBufferToPolygon() { + // Create a ByteBuffer that represents a Polygon + String wkt = "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"; + Polygon expectedPolygon = new DefaultPolygon((OGCPolygon) OGCPolygon.fromText(wkt)); + ByteBuffer byteBuffer = codec.encode(expectedPolygon, CqlConversion.PROTOCOL_VERSION); + + // Use the codec to decode this ByteBuffer into a Polygon object + Polygon actualPolygon = codec.decode(byteBuffer, CqlConversion.PROTOCOL_VERSION); + + // Assert that the result is not null + assertNotNull(actualPolygon); + + // Assert that the actual Polygon object is equal to the expected Polygon object + String actualWkt = actualPolygon.asWellKnownText(); + assertEquals(wkt, actualWkt); + } + @Test + void format_ShouldFormatPolygonToWktString() { + String wkt = "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"; + Polygon polygon = new DefaultPolygon((OGCPolygon) OGCPolygon.fromText(wkt)); + + String formatted = codec.format(polygon); + assertNotNull(formatted); + + String unquotedFormatted = formatted.replace("'", ""); + assertEquals(wkt, unquotedFormatted); + } + + @Test + void parse_ShouldParseWktStringToPolygon() { + String stringPolygon = "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"; + String quotedPolygon = "'" + stringPolygon + "'"; + // Parse it using the codec + Polygon parsedPolygon = codec.parse(quotedPolygon); + + // Assert that the resulting Polygon object is as expected + assertNotNull(parsedPolygon); + assertEquals(stringPolygon, parsedPolygon.asWellKnownText()); + } + + @Test + void encode_ShouldHandleNullValues() { + // Call encode with a null Polygon + ByteBuffer result = codec.encode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } + + @Test + void decode_ShouldHandleNullByteBuffer() { + // Call decode with a null ByteBuffer + Polygon result = codec.decode(null, CqlConversion.PROTOCOL_VERSION); + assertNull(result); + } +}