diff --git a/pkg/geocode/geocode.go b/pkg/geocode/geocode.go index 97805979f..89ec89892 100644 --- a/pkg/geocode/geocode.go +++ b/pkg/geocode/geocode.go @@ -88,7 +88,8 @@ type googleResult struct { } type googleGeometry struct { - Bounds *Rect `json:"bounds"` + Bounds *Rect `json:"bounds"` + Viewport *Rect `json:"viewport"` } func decodeGoogleResponse(r io.Reader) (rects []Rect, err error) { @@ -98,7 +99,17 @@ func decodeGoogleResponse(r io.Reader) (rects []Rect, err error) { } for _, res := range resTop.Results { if res.Geometry != nil && res.Geometry.Bounds != nil { - rects = append(rects, *res.Geometry.Bounds) + r := res.Geometry.Bounds + if r.NorthEast.Lat == 90 && r.NorthEast.Long == 180 && + r.SouthWest.Lat == -90 && r.SouthWest.Long == -180 { + // Google sometimes returns a "whole world" rect for large addresses (like "USA") + // so instead use the viewport in that case. + if res.Geometry.Viewport != nil { + rects = append(rects, *res.Geometry.Viewport) + } + } else { + rects = append(rects, *r) + } } } return diff --git a/pkg/geocode/geocode_test.go b/pkg/geocode/geocode_test.go index 5088227f4..660636b93 100644 --- a/pkg/geocode/geocode_test.go +++ b/pkg/geocode/geocode_test.go @@ -24,22 +24,45 @@ import ( ) func TestDecodeGoogleResponse(t *testing.T) { - rects, err := decodeGoogleResponse(strings.NewReader(googleRes)) - if err != nil { - t.Fatal(err) - } - want := []Rect{ - Rect{ - NorthEast: LatLong{pf("56.009657"), pf("37.945661")}, - SouthWest: LatLong{pf("55.48992699999999"), pf("37.319329")}, + tests := []struct { + name string + res string + want []Rect + }{ + { + name: "moscow", + res: googleMoscow, + want: []Rect{ + Rect{ + NorthEast: LatLong{pf("56.009657"), pf("37.945661")}, + SouthWest: LatLong{pf("55.48992699999999"), pf("37.319329")}, + }, + Rect{ + NorthEast: LatLong{pf("46.758882"), pf("-116.962068")}, + SouthWest: LatLong{pf("46.710912"), pf("-117.039698")}, + }, + }, }, - Rect{ - NorthEast: LatLong{pf("46.758882"), pf("-116.962068")}, - SouthWest: LatLong{pf("46.710912"), pf("-117.039698")}, + { + name: "usa", + res: googleUSA, + want: []Rect{ + Rect{ + NorthEast: LatLong{pf("49.38"), pf("-66.94")}, + SouthWest: LatLong{pf("25.82"), pf("-124.39")}, + }, + }, }, } - if !reflect.DeepEqual(rects, want) { - t.Errorf("wrong rects\n Got %#v\nWant %#v", rects, want) + for _, tt := range tests { + rects, err := decodeGoogleResponse(strings.NewReader(tt.res)) + if err != nil { + t.Errorf("Decoding %s: %v", tt.name, err) + continue + } + if !reflect.DeepEqual(rects, tt.want) { + t.Errorf("Test %s: wrong rects\n Got %#v\nWant %#v", tt.name, rects, tt.want) + } } } @@ -52,7 +75,7 @@ func pf(s string) float64 { return v } -var googleRes = ` +var googleMoscow = ` { "results" : [ { @@ -165,3 +188,51 @@ var googleRes = ` "status" : "OK" } ` + +// Response for "usa". +// Note the geometry bounds covering the whole world. In this case, use the viewport instead. +var googleUSA = ` +{ + "results" : [ + { + "address_components" : [ + { + "long_name" : "United States", + "short_name" : "US", + "types" : [ "country", "political" ] + } + ], + "formatted_address" : "United States", + "geometry" : { + "bounds" : { + "northeast" : { + "lat" : 90, + "lng" : 180 + }, + "southwest" : { + "lat" : -90, + "lng" : -180 + } + }, + "location" : { + "lat" : 37.09024, + "lng" : -95.712891 + }, + "location_type" : "APPROXIMATE", + "viewport" : { + "northeast" : { + "lat" : 49.38, + "lng" : -66.94 + }, + "southwest" : { + "lat" : 25.82, + "lng" : -124.39 + } + } + }, + "types" : [ "country", "political" ] + } + ], + "status" : "OK" +} +`