/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.index.search.geo; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.geo.RandomGeoGenerator; import java.io.IOException; import static org.elasticsearch.common.geo.GeoHashUtils.stringEncode; import static org.hamcrest.Matchers.is; public class GeoPointParsingTests extends ESTestCase { private static final double TOLERANCE = 1E-5; public void testGeoPointReset() throws IOException { double lat = 1 + randomDouble() * 89; double lon = 1 + randomDouble() * 179; GeoPoint point = new GeoPoint(0, 0); GeoPoint point2 = new GeoPoint(0, 0); assertPointsEqual(point, point2); assertPointsEqual(point.reset(lat, lon), point2.reset(lat, lon)); assertPointsEqual(point.reset(0, 0), point2.reset(0, 0)); assertPointsEqual(point.resetLat(lat), point2.reset(lat, 0)); assertPointsEqual(point.resetLat(0), point2.reset(0, 0)); assertPointsEqual(point.resetLon(lon), point2.reset(0, lon)); assertPointsEqual(point.resetLon(0), point2.reset(0, 0)); assertCloseTo(point.resetFromGeoHash(stringEncode(lon, lat)), lat, lon); assertPointsEqual(point.reset(0, 0), point2.reset(0, 0)); assertPointsEqual(point.resetFromString(Double.toString(lat) + ", " + Double.toHexString(lon)), point2.reset(lat, lon)); assertPointsEqual(point.reset(0, 0), point2.reset(0, 0)); } public void testEqualsHashCodeContract() { // generate a random geopoint final GeoPoint x = RandomGeoGenerator.randomPoint(random()); final GeoPoint y = new GeoPoint(x.lat(), x.lon()); final GeoPoint z = new GeoPoint(y.lat(), y.lon()); // GeoPoint doesn't care about coordinate system bounds, this simply validates inequality final GeoPoint a = new GeoPoint(x.lat() + randomIntBetween(1, 5), x.lon() + randomIntBetween(1, 5)); /** equality test */ // reflexive assertTrue(x.equals(x)); // symmetry assertTrue(x.equals(y)); // transitivity assertTrue(y.equals(z)); assertTrue(x.equals(z)); // inequality assertFalse(x.equals(a)); /** hashCode test */ // symmetry assertTrue(x.hashCode() == y.hashCode()); // transitivity assertTrue(y.hashCode() == z.hashCode()); assertTrue(x.hashCode() == z.hashCode()); // inequality assertFalse(x.hashCode() == a.hashCode()); } public void testGeoPointParsing() throws IOException { GeoPoint randomPt = RandomGeoGenerator.randomPoint(random()); GeoPoint point = GeoUtils.parseGeoPoint(objectLatLon(randomPt.lat(), randomPt.lon())); assertPointsEqual(point, randomPt); GeoUtils.parseGeoPoint(arrayLatLon(randomPt.lat(), randomPt.lon()), point); assertPointsEqual(point, randomPt); GeoUtils.parseGeoPoint(geohash(randomPt.lat(), randomPt.lon()), point); assertCloseTo(point, randomPt.lat(), randomPt.lon()); GeoUtils.parseGeoPoint(stringLatLon(randomPt.lat(), randomPt.lon()), point); assertCloseTo(point, randomPt.lat(), randomPt.lon()); } // Based on #5390 public void testInvalidPointEmbeddedObject() throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startObject(); content.startObject("location"); content.field("lat", 0).field("lon", 0); content.endObject(); content.endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); } public void testInvalidPointLatHashMix() throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startObject(); content.field("lat", 0).field("geohash", stringEncode(0d, 0d)); content.endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); } public void testInvalidPointLonHashMix() throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startObject(); content.field("lon", 0).field("geohash", stringEncode(0d, 0d)); content.endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); } public void testInvalidField() throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startObject(); content.field("lon", 0).field("lat", 0).field("test", 0); content.endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); } private XContentParser objectLatLon(double lat, double lon) throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startObject(); content.field("lat", lat).field("lon", lon); content.endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); return parser; } private XContentParser arrayLatLon(double lat, double lon) throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.startArray().value(lon).value(lat).endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); return parser; } private XContentParser stringLatLon(double lat, double lon) throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.value(Double.toString(lat) + ", " + Double.toString(lon)); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); return parser; } private XContentParser geohash(double lat, double lon) throws IOException { XContentBuilder content = JsonXContent.contentBuilder(); content.value(stringEncode(lon, lat)); XContentParser parser = createParser(JsonXContent.jsonXContent, content.bytes()); parser.nextToken(); return parser; } public static void assertPointsEqual(final GeoPoint point1, final GeoPoint point2) { assertEquals(point1, point2); assertEquals(point1.hashCode(), point2.hashCode()); } public static void assertCloseTo(final GeoPoint point, final double lat, final double lon) { assertEquals(point.lat(), lat, TOLERANCE); assertEquals(point.lon(), lon, TOLERANCE); } }