TWKBWriterTest.java
/*
* Copyright (c) 2018 James Hughes
* Copyright (c) 2019 Gabriel Roldan
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.io.twkb;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.twkb.TWKBTestSupport.TWKBTestData;
public class TWKBWriterTest {
public @Rule TWKBTestSupport testSupport = new TWKBTestSupport();
private TWKBWriter writer = new TWKBWriter();
private TWKBReader reader = new TWKBReader();
public @Test void testEmptyGeometries() throws ParseException {
check("POINT EMPTY", -1, 0, 0, false, false, "1110");
check("POINT EMPTY", 0, 0, 0, false, false, "0110");
check("POINT EMPTY", 1, 0, 0, false, false, "2110");
check("POINT EMPTY", 5, 0, 0, false, false, "a110");
check("LINESTRING EMPTY", -1, 0, 0, false, false, "1210");
check("LINESTRING EMPTY", 0, 0, 0, false, false, "0210");
check("LINESTRING EMPTY", 1, 0, 0, false, false, "2210");
check("LINESTRING EMPTY", 5, 0, 0, false, false, "a210");
check("POLYGON EMPTY", -1, 0, 0, false, false, "1310");
check("POLYGON EMPTY", 0, 0, 0, false, false, "0310");
check("POLYGON EMPTY", 1, 0, 0, false, false, "2310");
check("POLYGON EMPTY", 5, 0, 0, false, false, "a310");
check("MULTIPOINT EMPTY", -1, 0, 0, false, false, "1410");
check("MULTIPOINT EMPTY", 0, 0, 0, false, false, "0410");
check("MULTIPOINT EMPTY", 1, 0, 0, false, false, "2410");
check("MULTIPOINT EMPTY", 5, 0, 0, false, false, "a410");
check("MULTILINESTRING EMPTY", -1, 0, 0, false, false, "1510");
check("MULTILINESTRING EMPTY", 0, 0, 0, false, false, "0510");
check("MULTILINESTRING EMPTY", 1, 0, 0, false, false, "2510");
check("MULTILINESTRING EMPTY", 5, 0, 0, false, false, "a510");
check("MULTIPOLYGON EMPTY", -1, 0, 0, false, false, "1610");
check("MULTIPOLYGON EMPTY", 0, 0, 0, false, false, "0610");
check("MULTIPOLYGON EMPTY", 1, 0, 0, false, false, "2610");
check("MULTIPOLYGON EMPTY", 5, 0, 0, false, false, "a610");
check("GEOMETRYCOLLECTION EMPTY", -1, 0, 0, false, false, "1710");
check("GEOMETRYCOLLECTION EMPTY", 0, 0, 0, false, false, "0710");
check("GEOMETRYCOLLECTION EMPTY", 1, 0, 0, false, false, "2710");
check("GEOMETRYCOLLECTION EMPTY", 5, 0, 0, false, false, "a710");
}
public @Test void testXYPrecision() throws ParseException {
final String encodeWKT = "POINT (12345678.12345678 0)";
testXYPrecision(0, encodeWKT, "01009c85e30b00");
testXYPrecision(1, encodeWKT, "21009ab4de7500");
testXYPrecision(2, encodeWKT, "4100888ab0990900");
testXYPrecision(3, encodeWKT, "6100d6e4e0fd5b00");
testXYPrecision(4, encodeWKT, "8100e6eec7e9970700");
testXYPrecision(5, encodeWKT, "a100f4d3ce9fee4700");
testXYPrecision(6, encodeWKT, "c10082c792bccece0500");
testXYPrecision(7, encodeWKT, "e10090c6b9d990923800");
testXYPrecision(-1, encodeWKT, "110090da960100");
testXYPrecision(-2, encodeWKT, "310082890f00");
testXYPrecision(-3, encodeWKT, "5100f4c00100");
testXYPrecision(-4, encodeWKT, "7100a61300");
testXYPrecision(-5, encodeWKT, "9100f60100");
testXYPrecision(-6, encodeWKT, "b1001800");
testXYPrecision(-7, encodeWKT, "d1000200");
}
private void testXYPrecision(int xyprecision, String encodeWKT, String expectedHex)
throws ParseException {
boolean noSize = false;
boolean noBbox = false;
int zprecision = 0;
int mprecision = 0;
check(encodeWKT, xyprecision, zprecision, mprecision, noSize, noBbox, expectedHex);
}
public @Test void testZMPrecision() throws ParseException {
final String encodeWKT = "POINT ZM (0 0 12345678.12345678 12345678.12345678)";
testZMPrecision(0, encodeWKT, "01080300009c85e30b9c85e30b");
testZMPrecision(1, encodeWKT, "01082700009ab4de759ab4de75");
testZMPrecision(2, encodeWKT, "01084b0000888ab09909888ab09909");
testZMPrecision(3, encodeWKT, "01086f0000d6e4e0fd5bd6e4e0fd5b");
testZMPrecision(4, encodeWKT, "0108930000e6eec7e99707e6eec7e99707");
testZMPrecision(5, encodeWKT, "0108b70000f4d3ce9fee47f4d3ce9fee47");
testZMPrecision(6, encodeWKT, "0108db000082c792bccece0582c792bccece05");
testZMPrecision(7, encodeWKT, "0108ff000090c6b9d990923890c6b9d9909238");
}
private void testZMPrecision(int zmprecision, String encodeWKT, String expectedHex)
throws ParseException {
boolean noSize = false;
boolean noBbox = false;
int xyprecision = 0;
check(encodeWKT, xyprecision, zmprecision, zmprecision, noSize, noBbox, expectedHex);
}
public @Test void testIncludeSizeOnEmptyGeometries() throws ParseException {
final boolean withSize = true;
final boolean noBbox = false;
check("POINT EMPTY", -1, 0, 0, withSize, noBbox, "111200");
check("LINESTRING EMPTY", -1, 0, 0, withSize, noBbox, "121200");
check("LINESTRING EMPTY", 5, 0, 0, withSize, noBbox, "a21200");
check("POLYGON EMPTY", 5, 0, 0, withSize, noBbox, "a31200");
check("MULTIPOINT EMPTY", 0, 0, 0, withSize, noBbox, "041200");
check("MULTILINESTRING EMPTY", 1, 0, 0, withSize, noBbox, "251200");
check("MULTIPOLYGON EMPTY", -1, 0, 0, withSize, noBbox, "161200");
check("GEOMETRYCOLLECTION EMPTY", 0, 0, 0, withSize, noBbox, "071200");
}
public @Test void testEmptyGeometriesIncludeBboxIgnored() throws ParseException {
final boolean withBbox = true;
check("POINT EMPTY", -1, 0, 0, false, withBbox, "1110");
check("POINT EMPTY", -1, 0, 0, true, withBbox, "111200");
check("LINESTRING EMPTY", -1, 0, 0, false, withBbox, "1210");
check("LINESTRING EMPTY", -1, 0, 0, true, withBbox, "121200");
check("LINESTRING EMPTY", 5, 0, 0, false, withBbox, "a210");
check("LINESTRING EMPTY", 5, 0, 0, true, withBbox, "a21200");
check("POLYGON EMPTY", 5, 0, 0, false, withBbox, "a310");
check("POLYGON EMPTY", 5, 0, 0, true, withBbox, "a31200");
check("MULTIPOINT EMPTY", 0, 0, 0, false, withBbox, "0410");
check("MULTIPOINT EMPTY", 0, 0, 0, true, withBbox, "041200");
check("MULTILINESTRING EMPTY", 1, 0, 0, false, withBbox, "2510");
check("MULTILINESTRING EMPTY", 1, 0, 0, true, withBbox, "251200");
check("MULTIPOLYGON EMPTY", -1, 0, 0, false, withBbox, "1610");
check("MULTIPOLYGON EMPTY", -1, 0, 0, true, withBbox, "161200");
check("GEOMETRYCOLLECTION EMPTY", 0, 0, 0, false, withBbox, "0710");
check("GEOMETRYCOLLECTION EMPTY", 0, 0, 0, true, withBbox, "071200");
}
public @Test void testPoints() {
testEncode(testSupport.getPoints());
}
public @Test void testMultiPoints() {
testEncode(testSupport.getMultiPoints());
}
public @Test void testLineStrings() {
testEncode(testSupport.getLineStrings());
}
public @Test void testMultiLineStrings() {
testEncode(testSupport.getMultiLineStrings());
}
public @Test void testPolygons() {
testEncode(testSupport.getPolygons());
}
public @Test void testMultiPolygons() {
testEncode(testSupport.getMultiPolygons());
}
public @Test void testGeometryCollections() {
testEncode(testSupport.getGeometryCollections());
}
private void testEncode(List<TWKBTestData> testData) {
testData.forEach(this::testEncode);
}
private void testEncode(TWKBTestData testData) {
String input = testData.getInputWKT();
int xyprecision = testData.getXyprecision();
int zprecision = testData.getZprecision();
int mprecision = testData.getMprecision();
boolean includeSize = testData.isIncludeSize();
boolean includeBbox = testData.isIncludeBbox();
String expectedTWKB = testData.getExpectedTWKBHex();
try {
check(input, xyprecision, zprecision, mprecision, includeSize, includeBbox,
expectedTWKB);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
private void check(String inputWKT, int xyprecision, int zprecision, int mprecision,
boolean includeSize, boolean includeBbox, String expectedTWKB) throws ParseException {
Geometry geom = testSupport.parseWKT(inputWKT);
byte[] twkb = WKBReader.hexToBytes(expectedTWKB);
writer.setXYPrecision(xyprecision);
writer.setZPrecision(zprecision);
writer.setMPrecision(mprecision);
writer.setIncludeSize(includeSize);
writer.setIncludeBbox(includeBbox);
byte[] written = writer.write(geom);
boolean isEqualHex = Arrays.equals(twkb, written);
String expected = expectedTWKB;
String actual = testSupport.toHexString(written);
if (!isEqualHex) {
log("precision[xy: %d, z: %d, m: %d], include size: %s, include bbox: %s", xyprecision,
zprecision, mprecision, includeSize, includeBbox);
log("input : %s", inputWKT);
log("expected: %s", expected);
log("encoded : %s", actual);
log("decoded encoded : %s", reader.read(written));
log("----------");
log("\\set g '%s'", inputWKT);
log("SELECT :'g' AS input, %d AS xy, %d AS z, %d AS m, %s AS size, %s AS bbox,",
xyprecision, zprecision, mprecision, includeSize, includeBbox);
log("\tST_AsText(ST_GeomFromTWKB( ST_AsTWKB(:'g'::Geometry, %d, %d, %d, %s, %s))) AS expected_wkt,",
xyprecision, zprecision, mprecision, includeSize, includeBbox);
log("\tST_AsTWKB(:'g'::Geometry, %d, %d, %d, %s, %s) AS expected_twkb;", xyprecision,
zprecision, mprecision, includeSize, includeBbox);
assertEquals(expected, actual);
}
}
private void log(String fmt, Object... args) {
System.err.printf(fmt + "\n", args);
}
}