Add GeoJSON point containment helper
This commit is contained in:
181
internal/geo/point_test.go
Normal file
181
internal/geo/point_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package geo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const squarePolygon = `{
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-91.0, 38.0],
|
||||
[-90.0, 38.0],
|
||||
[-90.0, 39.0],
|
||||
[-91.0, 39.0],
|
||||
[-91.0, 38.0]
|
||||
]]
|
||||
}`
|
||||
|
||||
func TestContainsPointInsideSimplePolygon(t *testing.T) {
|
||||
got, err := ContainsPoint([]byte(squarePolygon), Point{Longitude: -90.5, Latitude: 38.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointAcceptsRawMessage(t *testing.T) {
|
||||
got, err := ContainsPoint(json.RawMessage(squarePolygon), Point{Longitude: -90.5, Latitude: 38.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointOutsideSimplePolygon(t *testing.T) {
|
||||
got, err := ContainsPoint([]byte(squarePolygon), Point{Longitude: -89.5, Latitude: 38.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if got {
|
||||
t.Fatalf("ContainsPoint() = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointOnBoundary(t *testing.T) {
|
||||
got, err := ContainsPoint([]byte(squarePolygon), Point{Longitude: -91.0, Latitude: 38.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointInHoleReturnsFalse(t *testing.T) {
|
||||
const polygonWithHole = `{
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[[0,0],[10,0],[10,10],[0,10],[0,0]],
|
||||
[[4,4],[6,4],[6,6],[4,6],[4,4]]
|
||||
]
|
||||
}`
|
||||
|
||||
got, err := ContainsPoint([]byte(polygonWithHole), Point{Longitude: 5, Latitude: 5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if got {
|
||||
t.Fatalf("ContainsPoint() = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointOnHoleBoundaryReturnsTrue(t *testing.T) {
|
||||
const polygonWithHole = `{
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[[0,0],[10,0],[10,10],[0,10],[0,0]],
|
||||
[[4,4],[6,4],[6,6],[4,6],[4,4]]
|
||||
]
|
||||
}`
|
||||
|
||||
got, err := ContainsPoint([]byte(polygonWithHole), Point{Longitude: 4, Latitude: 5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointInsideOneMultiPolygonMember(t *testing.T) {
|
||||
const multiPolygon = `{
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[[[0,0],[1,0],[1,1],[0,1],[0,0]]],
|
||||
[[[10,10],[12,10],[12,12],[10,12],[10,10]]]
|
||||
]
|
||||
}`
|
||||
|
||||
got, err := ContainsPoint([]byte(multiPolygon), Point{Longitude: 11, Latitude: 11})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointUsesLongitudeLatitudeOrder(t *testing.T) {
|
||||
const narrowPolygon = `{
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-91.0, 38.0],
|
||||
[-90.0, 38.0],
|
||||
[-90.0, 39.0],
|
||||
[-91.0, 39.0],
|
||||
[-91.0, 38.0]
|
||||
]]
|
||||
}`
|
||||
|
||||
got, err := ContainsPoint([]byte(narrowPolygon), Point{Longitude: -90.5, Latitude: 38.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() error = %v", err)
|
||||
}
|
||||
if !got {
|
||||
t.Fatalf("ContainsPoint() = false, want true")
|
||||
}
|
||||
|
||||
got, err = ContainsPoint([]byte(narrowPolygon), Point{Longitude: 38.5, Latitude: -90.5})
|
||||
if err != nil {
|
||||
t.Fatalf("ContainsPoint() reversed error = %v", err)
|
||||
}
|
||||
if got {
|
||||
t.Fatalf("ContainsPoint() with reversed coordinate values = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointUnsupportedGeometryError(t *testing.T) {
|
||||
_, err := ContainsPoint([]byte(`{"type":"Point","coordinates":[-90,38]}`), Point{Longitude: -90, Latitude: 38})
|
||||
if err == nil {
|
||||
t.Fatalf("ContainsPoint() error = nil, want error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), `unsupported geojson geometry type "Point"`) {
|
||||
t.Fatalf("ContainsPoint() error = %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointInvalidJSONError(t *testing.T) {
|
||||
_, err := ContainsPoint([]byte(`{"type":"Polygon"`), Point{Longitude: -90, Latitude: 38})
|
||||
if err == nil {
|
||||
t.Fatalf("ContainsPoint() error = nil, want error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "decode geojson geometry") {
|
||||
t.Fatalf("ContainsPoint() error = %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointMalformedCoordinatesError(t *testing.T) {
|
||||
_, err := ContainsPoint([]byte(`{"type":"Polygon","coordinates":[[[1]]]}`), Point{Longitude: 1, Latitude: 1})
|
||||
if err == nil {
|
||||
t.Fatalf("ContainsPoint() error = nil, want error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "need longitude and latitude") {
|
||||
t.Fatalf("ContainsPoint() error = %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsPointEmptyRingError(t *testing.T) {
|
||||
_, err := ContainsPoint([]byte(`{"type":"Polygon","coordinates":[[]]}`), Point{Longitude: 1, Latitude: 1})
|
||||
if err == nil {
|
||||
t.Fatalf("ContainsPoint() error = nil, want error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "ring has no points") {
|
||||
t.Fatalf("ContainsPoint() error = %q", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user