@@ -286,92 +286,170 @@ crate::operations::macros::define_read_factory!("from_tilejson", Args, Operation
286286#[ cfg( test) ]
287287mod tests {
288288 use super :: * ;
289-
289+ use rstest:: rstest;
290+
291+ // ── detect_tile_format ──────────────────────────────────────────────
292+
293+ #[ rstest]
294+ #[ case( ".pbf" , TileFormat :: MVT ) ]
295+ #[ case( ".png" , TileFormat :: PNG ) ]
296+ #[ case( ".webp" , TileFormat :: WEBP ) ]
297+ #[ case( ".jpg" , TileFormat :: JPG ) ]
298+ #[ case( ".jpeg" , TileFormat :: JPG ) ]
299+ #[ case( ".avif" , TileFormat :: AVIF ) ]
300+ #[ case( ".geojson" , TileFormat :: GEOJSON ) ]
301+ #[ case( ".json" , TileFormat :: JSON ) ]
302+ #[ case( ".svg" , TileFormat :: SVG ) ]
303+ #[ case( ".topojson" , TileFormat :: TOPOJSON ) ]
304+ #[ case( ".PNG" , TileFormat :: PNG ) ]
290305 #[ test]
291- fn test_detect_tile_format_from_tilejson_field ( ) {
292- let tilejson = TileJSON {
293- tile_format : Some ( TileFormat :: MVT ) ,
294- ..Default :: default ( )
295- } ;
296- let result = detect_tile_format ( & tilejson, "https://example.com/{z}/{x}/{y}" ) ;
297- assert_eq ! ( result. unwrap( ) , TileFormat :: MVT ) ;
306+ fn detect_format_from_url_extension ( #[ case] ext : & str , #[ case] expected : TileFormat ) {
307+ let url = format ! ( "https://example.com/{{z}}/{{x}}/{{y}}{ext}" ) ;
308+ assert_eq ! ( detect_tile_format( & TileJSON :: default ( ) , & url) . unwrap( ) , expected) ;
298309 }
299310
311+ #[ rstest]
312+ #[ case( "https://example.com/{z}/{x}/{y}" ) ]
313+ #[ case( "https://example.com/{z}/{x}/{y}.xyz" ) ]
314+ #[ case( "https://example.com/{z}/{x}/{y}?format=png" ) ]
300315 #[ test]
301- fn test_detect_tile_format_from_url_pbf ( ) {
302- let tilejson = TileJSON :: default ( ) ;
303- let result = detect_tile_format ( & tilejson, "https://example.com/{z}/{x}/{y}.pbf" ) ;
304- assert_eq ! ( result. unwrap( ) , TileFormat :: MVT ) ;
316+ fn detect_format_from_url_fails ( #[ case] url : & str ) {
317+ assert ! ( detect_tile_format( & TileJSON :: default ( ) , url) . is_err( ) ) ;
305318 }
306319
307320 #[ test]
308- fn test_detect_tile_format_from_url_png ( ) {
309- let tilejson = TileJSON :: default ( ) ;
310- let result = detect_tile_format ( & tilejson, "https://example.com/{z}/{x}/{y}.png" ) ;
311- assert_eq ! ( result. unwrap( ) , TileFormat :: PNG ) ;
312- }
313-
314- #[ test]
315- fn test_detect_tile_format_missing ( ) {
316- let tilejson = TileJSON :: default ( ) ;
317- let result = detect_tile_format ( & tilejson, "https://example.com/{z}/{x}/{y}" ) ;
318- assert ! ( result. is_err( ) ) ;
321+ fn detect_format_from_tilejson_field ( ) {
322+ let tilejson = TileJSON {
323+ tile_format : Some ( TileFormat :: MVT ) ,
324+ ..Default :: default ( )
325+ } ;
326+ assert_eq ! (
327+ detect_tile_format( & tilejson, "https://example.com/{z}/{x}/{y}" ) . unwrap( ) ,
328+ TileFormat :: MVT ,
329+ ) ;
319330 }
320331
321332 #[ test]
322- fn test_detect_tile_format_tilejson_takes_precedence ( ) {
333+ fn detect_format_tilejson_takes_precedence_over_url ( ) {
323334 let tilejson = TileJSON {
324335 tile_format : Some ( TileFormat :: JPG ) ,
325336 ..Default :: default ( )
326337 } ;
327- let result = detect_tile_format ( & tilejson, "https://example.com/{z}/{x}/{y}.png" ) ;
328- assert_eq ! ( result. unwrap( ) , TileFormat :: JPG ) ;
338+ assert_eq ! (
339+ detect_tile_format( & tilejson, "https://example.com/{z}/{x}/{y}.png" ) . unwrap( ) ,
340+ TileFormat :: JPG ,
341+ ) ;
329342 }
330343
344+ // ── extract_tile_url ────────────────────────────────────────────────
345+
346+ #[ rstest]
347+ #[ case(
348+ r#"{"tilejson":"3.0.0","tiles":["https://example.com/{z}/{x}/{y}.pbf"]}"# ,
349+ "https://example.com/{z}/{x}/{y}.pbf"
350+ ) ]
351+ #[ case(
352+ r#"{"tilejson":"3.0.0","tiles":["https://a.example.com/{z}/{x}/{y}.pbf","https://b.example.com/{z}/{x}/{y}.pbf"]}"# ,
353+ "https://a.example.com/{z}/{x}/{y}.pbf"
354+ ) ]
355+ #[ case(
356+ r#"{"tilejson":"3.0.0","tiles":["https://tiles.example.com/v1/{z}/{x}/{y}.mvt?token=abc123"]}"# ,
357+ "https://tiles.example.com/v1/{z}/{x}/{y}.mvt?token=abc123"
358+ ) ]
331359 #[ test]
332- fn test_extract_tile_url_valid ( ) -> Result < ( ) > {
333- let tilejson = TileJSON :: try_from ( r#"{"tilejson":"3.0.0","tiles":["https://example.com/{z}/{x}/{y}.pbf"]}"# ) ?;
334- let url = extract_tile_url ( & tilejson) ?;
335- assert_eq ! ( url, "https://example.com/{z}/{x}/{y}.pbf" ) ;
360+ fn extract_url_valid ( #[ case] json : & str , #[ case] expected : & str ) -> Result < ( ) > {
361+ let tilejson = TileJSON :: try_from ( json) ?;
362+ assert_eq ! ( extract_tile_url( & tilejson) ?, expected) ;
336363 Ok ( ( ) )
337364 }
338365
339366 #[ test]
340- fn test_extract_tile_url_missing_tiles ( ) {
341- let tilejson = TileJSON :: default ( ) ;
342- let result = extract_tile_url ( & tilejson) ;
343- assert ! ( result. is_err( ) ) ;
367+ fn extract_url_missing_tiles ( ) {
368+ assert ! ( extract_tile_url( & TileJSON :: default ( ) ) . is_err( ) ) ;
344369 }
345370
346371 #[ test]
347- fn test_extract_tile_url_empty_tiles ( ) -> Result < ( ) > {
372+ fn extract_url_empty_tiles ( ) -> Result < ( ) > {
348373 let tilejson = TileJSON :: try_from ( r#"{"tilejson":"3.0.0","tiles":[]}"# ) ?;
349- let result = extract_tile_url ( & tilejson) ;
350- assert ! ( result. is_err( ) ) ;
374+ assert ! ( extract_tile_url( & tilejson) . is_err( ) ) ;
351375 Ok ( ( ) )
352376 }
353377
378+ // ── build_tile_url ──────────────────────────────────────────────────
379+
380+ #[ rstest]
381+ #[ case( "https://example.com/{z}/{x}/{y}.pbf" , 3 , 5 , 7 , "https://example.com/3/5/7.pbf" ) ]
382+ #[ case(
383+ "https://tiles.example.com/data/{z}/{x}/{y}.png" ,
384+ 0 ,
385+ 0 ,
386+ 0 ,
387+ "https://tiles.example.com/data/0/0/0.png"
388+ ) ]
389+ #[ case(
390+ "https://example.com/{z}/{x}/{y}.pbf" ,
391+ 18 ,
392+ 131072 ,
393+ 262143 ,
394+ "https://example.com/18/131072/262143.pbf"
395+ ) ]
396+ #[ case(
397+ "https://example.com/{z}/{x}/{y}.pbf?token=secret&v=2" ,
398+ 5 ,
399+ 10 ,
400+ 20 ,
401+ "https://example.com/5/10/20.pbf?token=secret&v=2"
402+ ) ]
403+ #[ case(
404+ "https://{z}.tiles.example.com/{x}/{y}.png" ,
405+ 4 ,
406+ 8 ,
407+ 12 ,
408+ "https://4.tiles.example.com/8/12.png"
409+ ) ]
410+ #[ case(
411+ "https://example.com/{z}/{x}/{y}?zoom={z}" ,
412+ 7 ,
413+ 100 ,
414+ 50 ,
415+ "https://example.com/7/100/50?zoom=7"
416+ ) ]
354417 #[ test]
355- fn test_build_tile_url ( ) {
356- let template = "https://example.com/{z}/{x}/{y}.pbf" ;
357- let coord = TileCoord :: new ( 3 , 5 , 7 ) . unwrap ( ) ;
358- let url = build_tile_url ( template, & coord) ;
359- assert_eq ! ( url, "https://example.com/3/5/7.pbf" ) ;
418+ fn build_url ( #[ case] template : & str , #[ case] z : u8 , #[ case] x : u32 , #[ case] y : u32 , #[ case] expected : & str ) {
419+ let coord = TileCoord :: new ( z, x, y) . unwrap ( ) ;
420+ assert_eq ! ( build_tile_url( template, & coord) , expected) ;
360421 }
361422
362- #[ test]
363- fn test_build_tile_url_origin ( ) {
364- let template = "https://tiles.example.com/data/{z}/{x}/{y}.png" ;
365- let coord = TileCoord :: new ( 0 , 0 , 0 ) . unwrap ( ) ;
366- let url = build_tile_url ( template, & coord) ;
367- assert_eq ! ( url, "https://tiles.example.com/data/0/0/0.png" ) ;
423+ // ── fetch_tile ──────────────────────────────────────────────────────
424+
425+ #[ tokio:: test]
426+ async fn fetch_tile_404_returns_none ( ) {
427+ let client = reqwest:: Client :: new ( ) ;
428+ let result = fetch_tile (
429+ client,
430+ "https://httpbin.org/status/404" . to_string ( ) ,
431+ TileCoord :: new ( 0 , 0 , 0 ) . unwrap ( ) ,
432+ TileFormat :: PNG ,
433+ 0 ,
434+ )
435+ . await ;
436+ assert ! ( result. is_none( ) ) ;
368437 }
369438
370- #[ test]
371- fn test_build_tile_url_high_zoom ( ) {
372- let template = "https://example.com/{z}/{x}/{y}.pbf" ;
373- let coord = TileCoord :: new ( 18 , 131072 , 262143 ) . unwrap ( ) ;
374- let url = build_tile_url ( template, & coord) ;
375- assert_eq ! ( url, "https://example.com/18/131072/262143.pbf" ) ;
439+ #[ tokio:: test]
440+ async fn fetch_tile_connection_refused_returns_none ( ) {
441+ let client = reqwest:: Client :: builder ( )
442+ . timeout ( Duration :: from_millis ( 500 ) )
443+ . build ( )
444+ . unwrap ( ) ;
445+ let result = fetch_tile (
446+ client,
447+ "http://127.0.0.1:1/{z}/{x}/{y}.pbf" . to_string ( ) ,
448+ TileCoord :: new ( 0 , 0 , 0 ) . unwrap ( ) ,
449+ TileFormat :: MVT ,
450+ 0 ,
451+ )
452+ . await ;
453+ assert ! ( result. is_none( ) ) ;
376454 }
377455}
0 commit comments