#![allow(clippy::unwrap_used)]
use futures::{StreamExt as _, TryStreamExt as _};
use martin_tile_utils::{Tile, TileCoord};
use mbtiles::{MbtError, Mbtiles, create_metadata_table};
use sqlx::{Executor as _, SqliteConnection, query};
fn coord_key(coord: &TileCoord) -> (u8, u32, u32) {
let TileCoord { z, x, y } = *coord;
(z, x, y)
}
fn tile_key(tile: &Tile) -> (u8, u32, u32) {
coord_key(&tile.0)
}
async fn new(rows: &[&str]) -> (Mbtiles, SqliteConnection) {
let mbtiles = Mbtiles::new(":memory:").unwrap();
let mut conn = mbtiles.open().await.unwrap();
create_metadata_table(&mut conn, false).await.unwrap();
conn.execute(
"CREATE TABLE tiles (
zoom_level integer,
tile_column integer,
tile_row integer,
tile_data blob,
PRIMARY KEY(zoom_level, tile_column, tile_row));",
)
.await
.unwrap();
for row in rows {
let sql = format!(
"INSERT INTO tiles (zoom_level, tile_column, tile_row, tile_data)
VALUES ({row});"
);
query(&sql).execute(&mut conn).await.expect(&sql);
}
(mbtiles, conn)
}
#[tokio::test(flavor = "current_thread")]
async fn mbtiles_stream_tiles() {
let (mbtiles, mut conn) = new(&[
"1, 0, 1, CAST('tl' AS BLOB)",
"1, 1, 0, CAST('br' AS BLOB)",
"2, 0, 0, NULL",
])
.await;
{
let mut coords: Vec<TileCoord> = mbtiles
.stream_coords(&mut conn)
.try_collect()
.await
.expect("Failed to collect tile coords");
coords.sort_by_key(coord_key);
assert_eq!(
coords,
[
TileCoord { z: 1, x: 0, y: 0 },
TileCoord { z: 1, x: 1, y: 1 },
TileCoord { z: 2, x: 0, y: 3 },
]
);
let mbt_type = mbtiles.detect_type(&mut conn).await.unwrap();
for coord in coords {
assert!(
mbtiles
.contains(&mut conn, mbt_type, coord.z, coord.x, coord.y)
.await
.unwrap()
);
}
assert!(
!mbtiles
.contains(&mut conn, mbt_type, 0, 0, 0)
.await
.unwrap()
);
}
{
let mut tiles: Vec<Tile> = mbtiles
.stream_tiles(&mut conn)
.try_collect()
.await
.expect("Failed to collect tiles");
tiles.sort_by_key(tile_key);
assert_eq!(
tiles,
[
(TileCoord { z: 1, x: 0, y: 0 }, Some(b"tl".to_vec())),
(TileCoord { z: 1, x: 1, y: 1 }, Some(b"br".to_vec())),
(TileCoord { z: 2, x: 0, y: 3 }, None),
]
);
let mbt_type = mbtiles.detect_type(&mut conn).await.unwrap();
for (coord, _) in tiles {
assert!(
mbtiles
.contains(&mut conn, mbt_type, coord.z, coord.x, coord.y)
.await
.unwrap()
);
}
assert!(
!mbtiles
.contains(&mut conn, mbt_type, 0, 0, 0)
.await
.unwrap()
);
}
}
#[tokio::test(flavor = "current_thread")]
async fn mbtiles_stream_errors() {
let (mbtiles, mut conn) = new(&[
"2, 4, 0, NULL",
])
.await;
{
let mut stream = mbtiles.stream_coords(&mut conn);
match stream.next().await {
Some(Err(MbtError::InvalidTileIndex(..))) => {}
_ => panic!("Unexpected value returned from stream!"),
}
}
let mbt_type = mbtiles.detect_type(&mut conn).await.unwrap();
for y in 0..=20 {
assert!(
!mbtiles
.contains(&mut conn, mbt_type, 2, y, 0)
.await
.unwrap()
);
}
}