github.com/omniscale/go-osm@v0.3.1/parser/pbf/parser_test.go (about) 1 package pbf 2 3 import ( 4 "context" 5 "os" 6 "reflect" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/omniscale/go-osm" 12 ) 13 14 func TestParser(t *testing.T) { 15 checkParser(t, false) 16 } 17 18 func BenchmarkParser(b *testing.B) { 19 b.ReportAllocs() 20 for i := 0; i < b.N; i++ { 21 checkParser(b, false) 22 } 23 } 24 25 func BenchmarkParser_IncludeMetadata(b *testing.B) { 26 b.ReportAllocs() 27 for i := 0; i < b.N; i++ { 28 checkParser(b, true) 29 } 30 } 31 32 func checkParser(t testing.TB, includeMD bool) { 33 conf := Config{ 34 Coords: make(chan []osm.Node), 35 Nodes: make(chan []osm.Node), 36 Ways: make(chan []osm.Way), 37 Relations: make(chan []osm.Relation), 38 IncludeMetadata: includeMD, 39 } 40 41 f, err := os.Open("./monaco-20150428.osm.pbf") 42 if err != nil { 43 t.Fatal(err) 44 } 45 defer f.Close() 46 47 p := New(f, conf) 48 49 wg := sync.WaitGroup{} 50 51 var numNodes, numCoords, numWays, numRelations int64 52 53 go func() { 54 wg.Add(1) 55 for nd := range conf.Nodes { 56 numNodes += int64(len(nd)) 57 } 58 wg.Done() 59 }() 60 61 go func() { 62 wg.Add(1) 63 for nd := range conf.Coords { 64 numCoords += int64(len(nd)) 65 } 66 wg.Done() 67 }() 68 69 go func() { 70 wg.Add(1) 71 for ways := range conf.Ways { 72 numWays += int64(len(ways)) 73 } 74 wg.Done() 75 }() 76 77 go func() { 78 wg.Add(1) 79 for rels := range conf.Relations { 80 numRelations += int64(len(rels)) 81 } 82 wg.Done() 83 }() 84 85 err = p.Parse(context.Background()) 86 if err != nil { 87 t.Fatal(err) 88 } 89 wg.Wait() 90 91 if numCoords != 17233 { 92 t.Error("parsed an unexpected number of coords:", numCoords) 93 } 94 if numNodes != 978 { 95 t.Error("parsed an unexpected number of nodes:", numNodes) 96 } 97 if numWays != 2398 { 98 t.Error("parsed an unexpected number of ways:", numWays) 99 } 100 if numRelations != 108 { 101 t.Error("parsed an unexpected number of relations:", numRelations) 102 } 103 } 104 105 func TestParseCoords(t *testing.T) { 106 conf := Config{ 107 Coords: make(chan []osm.Node), 108 } 109 110 f, err := os.Open("./monaco-20150428.osm.pbf") 111 if err != nil { 112 t.Fatal(err) 113 } 114 defer f.Close() 115 116 p := New(f, conf) 117 118 wg := sync.WaitGroup{} 119 120 var numCoords int64 121 122 go func() { 123 wg.Add(1) 124 for nd := range conf.Coords { 125 numCoords += int64(len(nd)) 126 } 127 wg.Done() 128 }() 129 130 err = p.Parse(context.Background()) 131 if err != nil { 132 t.Fatal(err) 133 } 134 wg.Wait() 135 136 if numCoords != 17233 { 137 t.Error("parsed an unexpected number of coords:", numCoords) 138 } 139 } 140 141 func TestParseNodes(t *testing.T) { 142 conf := Config{ 143 Nodes: make(chan []osm.Node), 144 } 145 146 f, err := os.Open("./monaco-20150428.osm.pbf") 147 if err != nil { 148 t.Fatal(err) 149 } 150 defer f.Close() 151 152 p := New(f, conf) 153 154 wg := sync.WaitGroup{} 155 156 var numNodes int64 157 158 go func() { 159 wg.Add(1) 160 for nd := range conf.Nodes { 161 numNodes += int64(len(nd)) 162 } 163 wg.Done() 164 }() 165 166 err = p.Parse(context.Background()) 167 if err != nil { 168 t.Fatal(err) 169 } 170 wg.Wait() 171 172 if numNodes != 17233 { 173 t.Error("parsed an unexpected number of nodes:", numNodes) 174 } 175 } 176 177 func TestParserNotify(t *testing.T) { 178 conf := Config{ 179 Coords: make(chan []osm.Node), 180 Nodes: make(chan []osm.Node), 181 Ways: make(chan []osm.Way), 182 Relations: make(chan []osm.Relation), 183 } 184 185 f, err := os.Open("./monaco-20150428.osm.pbf") 186 if err != nil { 187 t.Fatal(err) 188 } 189 defer f.Close() 190 191 nodesWg := sync.WaitGroup{} // use nodesWg to wait till all nodes are processed 192 nodesProcessed := false 193 conf.OnFirstWay = func() { 194 // Send nil sentinal to nodes/coords goroutines to indicate that they 195 // should call nodesWg.Done after processing. 196 // Note: Need to send as many nils as there are goroutines. 197 conf.Coords <- nil 198 conf.Nodes <- nil 199 nodesProcessed = true 200 nodesWg.Wait() 201 } 202 203 waysWg := sync.WaitGroup{} // use waysWg to wait till all ways are processed 204 waysProcessed := false 205 conf.OnFirstRelation = func() { 206 // Send nil sentinal to ways goroutines to indicate that they 207 // should call waysWg.Done after processing. 208 // Note: Need to send as many nils as there are goroutines. 209 conf.Ways <- nil 210 waysProcessed = true 211 waysWg.Wait() 212 } 213 214 p := New(f, conf) 215 216 wg := sync.WaitGroup{} 217 218 var numNodes, numCoords, numWays, numRelations int64 219 220 nodesWg.Add(1) 221 go func() { 222 wg.Add(1) 223 for nd := range conf.Nodes { 224 if nd == nil { 225 nodesWg.Done() 226 nodesWg.Wait() 227 continue 228 } 229 numNodes += int64(len(nd)) 230 } 231 wg.Done() 232 }() 233 234 nodesWg.Add(1) 235 go func() { 236 wg.Add(1) 237 for nd := range conf.Coords { 238 if nd == nil { 239 nodesWg.Done() 240 nodesWg.Wait() 241 continue 242 } 243 numCoords += int64(len(nd)) 244 } 245 wg.Done() 246 }() 247 248 waysWg.Add(1) 249 go func() { 250 wg.Add(1) 251 for ways := range conf.Ways { 252 if ways == nil { 253 waysWg.Done() 254 waysWg.Wait() 255 continue 256 } 257 if !nodesProcessed { 258 t.Fatal("received ways before all nodes were processed") 259 } 260 numWays += int64(len(ways)) 261 } 262 wg.Done() 263 }() 264 265 go func() { 266 wg.Add(1) 267 for rels := range conf.Relations { 268 if !nodesProcessed { 269 t.Fatal("received relations before all nodes were processed") 270 } 271 if !waysProcessed { 272 t.Fatal("received relations before all ways were processed") 273 } 274 numRelations += int64(len(rels)) 275 } 276 wg.Done() 277 }() 278 279 err = p.Parse(context.Background()) 280 if err != nil { 281 t.Fatal(err) 282 } 283 wg.Wait() 284 285 if numCoords != 17233 { 286 t.Error("parsed an unexpected number of coords:", numCoords) 287 } 288 if numNodes != 978 { 289 t.Error("parsed an unexpected number of nodes:", numNodes) 290 } 291 if numWays != 2398 { 292 t.Error("parsed an unexpected number of ways:", numWays) 293 } 294 if numRelations != 108 { 295 t.Error("parsed an unexpected number of relations:", numRelations) 296 } 297 } 298 299 func TestParseCancel(t *testing.T) { 300 conf := Config{ 301 Nodes: make(chan []osm.Node), 302 Ways: make(chan []osm.Way), 303 Relations: make(chan []osm.Relation), 304 Concurrency: 1, 305 } 306 307 f, err := os.Open("./monaco-20150428.osm.pbf") 308 if err != nil { 309 t.Fatal(err) 310 } 311 defer f.Close() 312 313 p := New(f, conf) 314 315 wg := sync.WaitGroup{} 316 ctx, stop := context.WithCancel(context.Background()) 317 var numNodes, numWays, numRelations int64 318 319 go func() { 320 wg.Add(1) 321 for nd := range conf.Nodes { 322 numNodes += int64(len(nd)) 323 // stop after first parsed nodes 324 stop() 325 } 326 wg.Done() 327 }() 328 go func() { 329 wg.Add(1) 330 for ways := range conf.Ways { 331 numWays += int64(len(ways)) 332 } 333 wg.Done() 334 }() 335 go func() { 336 wg.Add(1) 337 for rels := range conf.Relations { 338 numRelations += int64(len(rels)) 339 } 340 wg.Done() 341 }() 342 343 err = p.Parse(ctx) 344 if err != context.Canceled { 345 t.Fatal(err) 346 } 347 wg.Wait() 348 349 // only two blocks of 8k nodes should be parsed before everything is stop()ed 350 if numNodes != 16000 { 351 t.Error("parsed an unexpected number of nodes:", numNodes) 352 } 353 if numWays != 0 { 354 t.Error("parsed an unexpected number of ways:", numWays) 355 } 356 if numRelations != 0 { 357 t.Error("parsed an unexpected number of relations:", numRelations) 358 } 359 } 360 361 func TestParseMetadata(t *testing.T) { 362 conf := Config{ 363 IncludeMetadata: true, 364 Nodes: make(chan []osm.Node), 365 Ways: make(chan []osm.Way), 366 Relations: make(chan []osm.Relation), 367 Concurrency: 1, 368 } 369 370 f, err := os.Open("./monaco-20150428.osm.pbf") 371 if err != nil { 372 t.Fatal(err) 373 } 374 defer f.Close() 375 376 p := New(f, conf) 377 378 wg := sync.WaitGroup{} 379 380 var nodes []osm.Node 381 wg.Add(1) 382 go func() { 383 for nds := range conf.Nodes { 384 nodes = append(nodes, nds...) 385 } 386 wg.Done() 387 }() 388 389 var ways []osm.Way 390 wg.Add(1) 391 go func() { 392 for ws := range conf.Ways { 393 ways = append(ways, ws...) 394 } 395 wg.Done() 396 }() 397 398 var rels []osm.Relation 399 wg.Add(1) 400 go func() { 401 for rs := range conf.Relations { 402 rels = append(rels, rs...) 403 } 404 wg.Done() 405 }() 406 407 err = p.Parse(context.Background()) 408 if err != nil { 409 t.Fatal(err) 410 } 411 wg.Wait() 412 413 for _, tc := range []struct { 414 Idx int 415 Want osm.Node 416 }{ 417 {Idx: 0, 418 Want: osm.Node{ 419 Element: osm.Element{ 420 ID: 21911863, 421 Metadata: &osm.Metadata{ 422 UserID: 378737, 423 UserName: "Scrup", 424 Version: 5, 425 Timestamp: time.Unix(1335970231, 0), 426 Changeset: 11480240, 427 }, 428 }, 429 Lat: 43.737012500000006, 430 Long: 7.422028, 431 }, 432 }, 433 {Idx: 2, 434 Want: osm.Node{ 435 Element: osm.Element{ 436 ID: 21911886, 437 Tags: osm.Tags{"crossing_ref": "zebra", "highway": "crossing"}, 438 Metadata: &osm.Metadata{ 439 UserID: 378737, 440 UserName: "Scrup", 441 Version: 8, 442 Timestamp: time.Unix(1335884779, 0), 443 Changeset: 11470653, 444 }, 445 }, 446 Lat: 43.737239900000006, 447 Long: 7.423498500000001, 448 }, 449 }, 450 } { 451 if !reflect.DeepEqual(nodes[tc.Idx], tc.Want) { 452 t.Errorf("unexpected node, got:\n%#v\n%#v\nwant:\n%#v\n%#v", nodes[tc.Idx], nodes[tc.Idx].Metadata, tc.Want, tc.Want.Metadata) 453 } 454 } 455 456 for _, tc := range []struct { 457 Idx int 458 Want osm.Way 459 }{ 460 {Idx: 0, 461 Want: osm.Way{ 462 Element: osm.Element{ 463 ID: 4097656, 464 Tags: osm.Tags{"highway": "primary", "name": "Avenue Princesse Alice", "oneway": "yes"}, 465 Metadata: &osm.Metadata{ 466 UserID: 852996, 467 UserName: "Mg2", 468 Version: 7, 469 Timestamp: time.Unix(1417551724, 0), 470 Changeset: 27187519, 471 }, 472 }, 473 Refs: []int64{21912089, 1079750744, 2104793864, 1110560507, 21912093, 21912095, 1079751630, 21912097, 21912099}, 474 }, 475 }, 476 {Idx: 2, 477 Want: osm.Way{ 478 Element: osm.Element{ 479 ID: 4224972, 480 Tags: osm.Tags{"name": "Avenue des Papalins", "oneway": "yes", "highway": "residential"}, 481 Metadata: &osm.Metadata{ 482 UserID: 393883, 483 UserName: "fmalamaire", 484 Version: 9, 485 Timestamp: time.Unix(1368522546, 0), 486 Changeset: 16122419, 487 }, 488 }, 489 Refs: []int64{25177418, 25177397}, 490 }, 491 }, 492 } { 493 if !reflect.DeepEqual(ways[tc.Idx], tc.Want) { 494 t.Errorf("unexpected way, got:\n%#v\n%#v\nwant:\n%#v\n%#v", ways[tc.Idx], ways[tc.Idx].Metadata, tc.Want, tc.Want.Metadata) 495 } 496 } 497 498 for _, tc := range []struct { 499 Idx int 500 Want osm.Relation 501 }{ 502 {Idx: 26, 503 Want: osm.Relation{ 504 Element: osm.Element{ 505 ID: 1369631, 506 Tags: osm.Tags{"type": "multipolygon"}, 507 Metadata: &osm.Metadata{ 508 UserID: 110263, 509 UserName: "werner2101", 510 Version: 2, 511 Timestamp: time.Unix(1298228849, 0), 512 Changeset: 7346501, 513 }, 514 }, 515 Members: []osm.Member{ 516 osm.Member{ID: 94452671, Type: 1, Role: "inner"}, 517 osm.Member{ID: 94452619, Type: 1, Role: "outer"}, 518 }, 519 }, 520 }, 521 } { 522 if !reflect.DeepEqual(rels[tc.Idx], tc.Want) { 523 t.Errorf("unexpected rel, got:\n%#v\n%#v\nwant:\n%#v\n%#v", rels[tc.Idx], rels[tc.Idx].Metadata, tc.Want, tc.Want.Metadata) 524 } 525 } 526 }