1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package s2
16
17 import (
18 "bytes"
19 "testing"
20
21 "github.com/golang/geo/r1"
22 "github.com/golang/geo/r3"
23 "github.com/golang/geo/s1"
24 )
25
26 func TestParseLatLng(t *testing.T) {
27 tests := []struct {
28 have string
29 want []LatLng
30 }{
31 {
32 have: "",
33 want: []LatLng{},
34 },
35 {
36 have: "blah",
37 want: []LatLng{},
38 },
39 {
40 have: "0:0",
41 want: []LatLng{LatLng{0, 0}},
42 },
43 {
44 have: "0:0, 0:-90",
45 want: []LatLng{
46 LatLngFromDegrees(0, 0),
47 LatLngFromDegrees(0, -90),
48 },
49 },
50 {
51 have: "-20:150, -20:151, -19:150",
52 want: []LatLng{
53 LatLngFromDegrees(-20, 150),
54 LatLngFromDegrees(-20, 151),
55 LatLngFromDegrees(-19, 150),
56 },
57 },
58 }
59
60 for _, test := range tests {
61 got := parseLatLngs(test.have)
62
63 if len(got) != len(test.want) {
64 t.Errorf("parseLatLngs(%s) = %+v, got different number of results %+v", test.have, got, test.want)
65 continue
66 }
67
68 for k, v := range got {
69 if v != test.want[k] {
70 t.Errorf("parseLatlng(%q): %d. %+v, want %+v", test.have, k, v, test.want[k])
71 }
72 }
73 }
74 }
75
76 func TestTextFormatWritePoints(t *testing.T) {
77 tests := []struct {
78 have []Point
79 want string
80 }{
81 {
82 have: nil,
83 want: "",
84 },
85 {
86 have: []Point{},
87 want: "",
88 },
89 {
90 have: []Point{PointFromCoords(1, 0, 0)},
91 want: "0:0",
92 },
93 {
94 have: []Point{PointFromCoords(1, 0, 0), PointFromCoords(0, -1, 0)},
95 want: "0:0, 0:-90",
96 },
97 }
98
99 for _, test := range tests {
100 var buf bytes.Buffer
101 writePoints(&buf, test.have)
102 if got := buf.String(); got != test.want {
103 t.Errorf("writePoints(%v) = %q, want %q", test.have, got, test.want)
104 }
105 }
106 }
107
108 func TestTextFormatParsePointRoundtrip(t *testing.T) {
109 tests := []struct {
110 have string
111 want Point
112 }{
113 {"0:0", Point{r3.Vector{1, 0, 0}}},
114 {"90:0", Point{r3.Vector{6.123233995736757e-17, 0, 1}}},
115 {"-45:0", Point{r3.Vector{0.7071067811865476, 0, -0.7071067811865475}}},
116 {"0:0.01", Point{r3.Vector{0.9999999847691292, 0.00017453292431333684, 0}}},
117 {"0:30", Point{r3.Vector{0.8660254037844387, 0.49999999999999994, 0}}},
118 {"0:45", Point{r3.Vector{0.7071067811865476, 0.7071067811865475, 0}}},
119 {"0:90", Point{r3.Vector{6.123233995736757e-17, 1, 0}}},
120 {"30:30", Point{r3.Vector{0.7500000000000001, 0.4330127018922193, 0.49999999999999994}}},
121 {"-30:30", Point{r3.Vector{0.7500000000000001, 0.4330127018922193, -0.49999999999999994}}},
122 {"0:180", Point{r3.Vector{-1, 6.123233995736757e-17, 0}}},
123 {"0:-180", Point{r3.Vector{-1, -6.123233995736757e-17, 0}}},
124 {"90:-180", Point{r3.Vector{-6.123233995736757e-17, -0, 1}}},
125 {"1e-20:1e-30", Point{r3.Vector{1, 0, 0}}},
126 }
127
128 for _, test := range tests {
129 pt := parsePoint(test.have)
130 if !pt.ApproxEqual(test.want) {
131 t.Errorf("parsePoint(%s) = %v, want %v", test.have, pt, test.want)
132 }
133 if got := pointToString(pt); got != test.have {
134 t.Errorf("pointToString(parsePoint(%v)) = %v, want %v", test.have, got, test.have)
135 }
136 }
137 }
138
139 func TestTextFormatParsePointRoundtripEdgecases(t *testing.T) {
140 tests := []struct {
141 have string
142 wantPt Point
143 wantStr string
144 }{
145
146 {
147 have: "91:0",
148 wantPt: Point{r3.Vector{-0.017452406437283473, 0, 0.9998476951563913}},
149 wantStr: "89:-180",
150 },
151 {
152 have: "-91:0",
153 wantPt: Point{r3.Vector{-0.017452406437283473, -0, -0.9998476951563913}},
154 wantStr: "-89:-180",
155 },
156
157
158
159
160
161
162
163 {
164 have: "179.99:0",
165 wantPt: Point{r3.Vector{-0.9999999847691292, -0, 0.00017453292431344843}},
166 wantStr: "0.0100000000000064:-180",
167 },
168
176 {
177 have: "181.0:0",
178 wantPt: Point{r3.Vector{-0.9998476951563913, -0, -0.017452406437283637}},
179 wantStr: "-1.00000000000001:-180",
180 },
181
190
191
192 {
193 have: "37.4210:-122.0866, 37.4231:-122.0819",
194 wantPt: Point{r3.Vector{-0.4218751185559026, -0.6728760966593905, 0.6076669670863027}},
195 wantStr: "37.421:-122.0866",
196 },
197 }
198
199 for _, test := range tests {
200 pt := parsePoint(test.have)
201 if !pt.ApproxEqual(test.wantPt) {
202 t.Errorf("parsePoint(%s) = %v, want %v", test.have, pt, test.wantPt)
203 }
204 if got := pointToString(pt); got != test.wantStr {
205 t.Errorf("pointToString(parsePoint(%v)) = %v, want %v", test.have, got, test.wantStr)
206 }
207 }
208 }
209
210 func TestTextFormatParsePointsLatLngs(t *testing.T) {
211 tests := []struct {
212 have string
213 wantPts []Point
214 wantLLs []LatLng
215 }{
216 {
217 have: "0:0",
218 wantPts: []Point{{r3.Vector{1, 0, 0}}},
219 wantLLs: []LatLng{{Lat: 0, Lng: 0}},
220 },
221 {
222 have: " 0:0, ",
223 wantPts: []Point{{r3.Vector{1, 0, 0}}},
224 wantLLs: []LatLng{{Lat: 0, Lng: 0}},
225 },
226 {
227 have: "90:0,-90:0",
228 wantPts: []Point{
229 {r3.Vector{6.123233995736757e-17, 0, 1}},
230 {r3.Vector{6.123233995736757e-17, 0, -1}},
231 },
232 wantLLs: []LatLng{
233 {Lat: 90 * s1.Degree, Lng: 0},
234 {Lat: -90 * s1.Degree, Lng: 0},
235 },
236 },
237 {
238 have: "90:0, 0:90, -90:0, 0:-90",
239 wantPts: []Point{
240 {r3.Vector{6.123233995736757e-17, 0, 1}},
241 {r3.Vector{6.123233995736757e-17, 1, 0}},
242 {r3.Vector{6.123233995736757e-17, 0, -1}},
243 {r3.Vector{6.123233995736757e-17, -1, 0}},
244 },
245 wantLLs: []LatLng{
246 {Lat: 90 * s1.Degree, Lng: 0},
247 {Lat: 0, Lng: 90 * s1.Degree},
248 {Lat: -90 * s1.Degree, Lng: 0},
249 {Lat: 0, Lng: -90 * s1.Degree},
250 },
251 },
252 {
253 have: "37.4210:-122.0866, 37.4231:-122.0819",
254 wantPts: []Point{
255 {r3.Vector{-0.421875118555903, -0.672876096659391, 0.607666967086303}},
256 {r3.Vector{-0.421808091075447, -0.672891829588934, 0.607696075333505}},
257 },
258 wantLLs: []LatLng{
259 {s1.Degree * 37.4210, s1.Degree * -122.0866},
260 {s1.Degree * 37.4231, s1.Degree * -122.0819},
261 },
262 },
263 {
264
265 have: "",
266 },
267 {
268
269 have: ",",
270 },
271 {
272
273 have: "9000:1234.56",
274 wantPts: []Point{
275 {r3.Vector{-0.903035619536086, 0.429565675827430, 9.82193362e-16}},
276 },
277
278 wantLLs: []LatLng{
279 {Lat: 9000 * s1.Degree, Lng: 1234.56 * s1.Degree},
280 },
281 },
282 }
283
284 for _, test := range tests {
285 for i, pt := range parsePoints(test.have) {
286 if !pt.ApproxEqual(test.wantPts[i]) {
287 t.Errorf("parsePoints(%s): [%d]: got %v, want %v", test.have, i, pt, test.wantPts[i])
288 }
289 }
290
291
292
293 for i, ll := range parseLatLngs(test.have) {
294 if ll != test.wantLLs[i] {
295 t.Errorf("parseLatLngs(%s): [%d]: got %v, want %v", test.have, i, ll, test.wantLLs[i])
296 }
297 }
298
299
300 }
301 }
302
303 func TestTextFormatParseRect(t *testing.T) {
304 tests := []struct {
305 have string
306 want Rect
307 }{
308 {"0:0", Rect{}},
309 {
310 "1:1",
311 Rect{
312 r1.Interval{float64(s1.Degree), float64(s1.Degree)},
313 s1.Interval{float64(s1.Degree), float64(s1.Degree)},
314 },
315 },
316 {
317 "1:1, 2:2, 3:3",
318 Rect{
319 r1.Interval{float64(s1.Degree), 3 * float64(s1.Degree)},
320 s1.Interval{float64(s1.Degree), 3 * float64(s1.Degree)},
321 },
322 },
323 {
324 "-90:-180, 90:180",
325 Rect{
326 r1.Interval{-90 * float64(s1.Degree), 90 * float64(s1.Degree)},
327 s1.Interval{180 * float64(s1.Degree), -180 * float64(s1.Degree)},
328 },
329 },
330 {
331 "-89.99:0, 89.99:179.99",
332 Rect{
333 r1.Interval{-89.99 * float64(s1.Degree), 89.99 * float64(s1.Degree)},
334 s1.Interval{0, 179.99 * float64(s1.Degree)},
335 },
336 },
337 {
338 "-89.99:-179.99, 89.99:179.99",
339 Rect{
340 r1.Interval{-89.99 * float64(s1.Degree), 89.99 * float64(s1.Degree)},
341 s1.Interval{179.99 * float64(s1.Degree), -179.99 * float64(s1.Degree)},
342 },
343 },
344 {
345 "37.4210:-122.0866, 37.4231:-122.0819",
346 Rect{
347 r1.Interval{float64(s1.Degree * 37.4210), float64(s1.Degree * 37.4231)},
348 s1.Interval{float64(s1.Degree * -122.0866), float64(s1.Degree * -122.0819)},
349 },
350 },
351 {
352 "-876.54:-654.43, 963.84:2468.35",
353 Rect{
354 r1.Interval{-876.54 * float64(s1.Degree), -876.54 * float64(s1.Degree)},
355 s1.Interval{-654.43 * float64(s1.Degree), -654.43 * float64(s1.Degree)},
356 },
357 },
358 }
359 for _, test := range tests {
360 if got := makeRect(test.have); got != test.want {
361 t.Errorf("makeRect(%s) = %v, want %v", test.have, got, test.want)
362 }
363 }
364 }
365
366 func TestTextFormatMakeCellUnion(t *testing.T) {
367 tests := []struct {
368 have []string
369 want CellUnion
370 }{
371 {
372 have: nil,
373 want: CellUnion{},
374 },
375 {
376 have: []string{},
377 want: CellUnion{},
378 },
379 {
380 have: []string{"google"},
381 want: CellUnion{0},
382 },
383 {
384 have: []string{"0/"},
385 want: CellUnion{CellIDFromFace(0)},
386 },
387 {
388 have: []string{"2/010", "2/011", "2/02"},
389 want: CellUnion{0x4240000000000000, 0x42c0000000000000, 0x4500000000000000},
390 },
391 }
392
393 for _, test := range tests {
394 got := makeCellUnion(test.have...)
395 got.Normalize()
396 if !got.Equal(test.want) {
397 t.Errorf("makeCellUnion(%v) = %v, want %v", test.have, got, test.want)
398 }
399 }
400 }
401
402 func TestTextFormatMakeLaxPolyline(t *testing.T) {
403 l := makeLaxPolyline("-20:150, -20:151, -19:150")
404
405
406 if len(l.vertices) != 3 {
407 t.Errorf("len(l.vertices) = %d, want 3", len(l.vertices))
408 }
409 if got, want := LatLngFromPoint(l.vertices[0]), LatLngFromDegrees(-20, 150); !latLngsApproxEqual(got, want, epsilon) {
410 t.Errorf("vertex(0) = %v, want %v", got, want)
411 }
412 if got, want := LatLngFromPoint(l.vertices[1]), LatLngFromDegrees(-20, 151); !latLngsApproxEqual(got, want, epsilon) {
413 t.Errorf("vertex(1) = %v, want %v", got, want)
414 }
415 if got, want := LatLngFromPoint(l.vertices[2]), LatLngFromDegrees(-19, 150); !latLngsApproxEqual(got, want, epsilon) {
416 t.Errorf("vertex(2) = %v, want %v", got, want)
417 }
418
419
420
421 }
422
423 func TestTextFormatMakeLaxPolygonEmpty(t *testing.T) {
424
425 shape := makeLaxPolygon("")
426 if got, want := shape.numLoops, 0; got != want {
427 t.Errorf("laxPolygon.numLoops = %d, want %d", got, want)
428 }
429 shape = makeLaxPolygon("empty")
430 if got, want := shape.numLoops, 0; got != want {
431 t.Errorf("laxPolygon.numLoops = %d, want %d", got, want)
432 }
433 }
434
435 func TestTextFormatMakeLaxPolygonFull(t *testing.T) {
436 shape := makeLaxPolygon("full")
437 if got, want := shape.numLoops, 1; got != want {
438 t.Errorf("laxPolygon.numLoops = %d, want %d", got, want)
439 }
440 if got, want := shape.numLoopVertices(0), 0; got != want {
441 t.Errorf("laxPolygon.numLoopVertices(%d) = %d, want %d", 0, got, want)
442 }
443 }
444
445 func TestTextFormatMakeLaxPolygonFullWithHole(t *testing.T) {
446 shape := makeLaxPolygon("full; 0:0")
447 if got, want := shape.numLoops, 2; got != want {
448 t.Errorf("laxPolygon.numLoops = %d, want %d", got, want)
449 }
450 if got, want := shape.numLoopVertices(0), 0; got != want {
451 t.Errorf("laxPolygon.numLoopVertices(%d) = %d, want %d", 0, got, want)
452 }
453 if got, want := shape.numLoopVertices(1), 1; got != want {
454 t.Errorf("laxPolygon.numLoopVertices(%d) = %d, want %d", 1, got, want)
455
456 }
457 if got, want := shape.NumEdges(), 1; got != want {
458 t.Errorf("laxPolygon.NumEdges() = %d, want %d", got, want)
459 }
460 }
461
462 func TestTextFormatShapeIndexDebugStringRoundTrip(t *testing.T) {
463 tests := []string{
464 "# #",
465 "0:0 # #",
466 "0:0 | 1:0 # #",
467 "0:0 | 1:0 # #",
468 "# 0:0, 0:0 #",
469 "# 0:0, 0:0 | 1:0, 2:0 #",
470 "# # 0:0",
471 "# # 0:0, 0:1",
472 "# # 0:0, 0:1, 1:0",
473 "# # 0:0, 0:1, 1:0, 2:2",
474 }
475
476 for _, want := range tests {
477 if got := shapeIndexDebugString(makeShapeIndex(want)); got != want {
478 t.Errorf("ShapeIndex failed roundtrip to string. got %q, want %q", got, want)
479 }
480 }
481 }
482
483
484
485
486
487
488
489
490
View as plain text