use slint::{ComponentHandle, Model, PhysicalSize};
use slint_mapping::sources::FileTileSource;
use slint_mapping::{MapController, MapView};
use std::cell::Cell;
fn init_backend() {
thread_local! {
static INITED: Cell<bool> = const { Cell::new(false) };
}
INITED.with(|done| {
if !done.get() {
i_slint_backend_testing::init_no_event_loop();
done.set(true);
}
});
}
fn make_map() -> (MapView, MapController) {
init_backend();
let map = MapView::new().expect("MapView::new");
map.window().set_size(PhysicalSize::new(800, 600));
let source = FileTileSource::new(slint_mapping::SAMPLE_TILES_DIR);
let controller = MapController::new(&map, source);
(map, controller)
}
#[test]
fn initial_state_matches_slint_defaults() {
let (map, _c) = make_map();
assert_eq!(map.get_latitude(), 0.0);
assert_eq!(map.get_longitude(), 0.0);
assert_eq!(map.get_zoom(), 2.0);
}
#[test]
fn set_centre_updates_slint_properties() {
let (map, c) = make_map();
c.set_centre(-0.1276, 51.5074);
c.set_zoom(3.0);
assert!(
(map.get_longitude() - -0.1276).abs() < 1e-3,
"longitude property: got {}",
map.get_longitude()
);
assert!(
(map.get_latitude() - 51.5074).abs() < 1e-3,
"latitude property: got {}",
map.get_latitude()
);
assert_eq!(map.get_zoom(), 3.0);
}
#[test]
fn invoke_pan_callback_moves_camera() {
let (map, _c) = make_map();
let lon_before = map.get_longitude();
map.invoke_pan(200.0, 0.0);
let lon_after = map.get_longitude();
assert!(
lon_after < lon_before,
"drag right should decrease longitude, before={lon_before} after={lon_after}"
);
}
#[test]
fn invoke_pan_then_unpan_round_trips() {
let (map, _c) = make_map();
let lon0 = map.get_longitude();
let lat0 = map.get_latitude();
map.invoke_pan(137.0, -89.0);
map.invoke_pan(-137.0, 89.0);
assert!(
(map.get_longitude() - lon0).abs() < 1e-3,
"lon round-trip: {} -> {}",
lon0,
map.get_longitude()
);
assert!(
(map.get_latitude() - lat0).abs() < 1e-3,
"lat round-trip: {} -> {}",
lat0,
map.get_latitude()
);
}
#[test]
fn invoke_zoom_by_changes_zoom_level() {
let (map, _c) = make_map();
let z0 = map.get_zoom();
map.invoke_zoom_by(1.0, 400.0, 300.0); assert!(
(map.get_zoom() - (z0 + 1.0)).abs() < 1e-6,
"expected zoom {} after +1, got {}",
z0 + 1.0,
map.get_zoom()
);
}
#[test]
fn zoom_anchored_at_centre_does_not_drift_camera() {
let (map, c) = make_map();
c.set_centre(2.3522, 48.8566); c.set_zoom(3.0);
let lon0 = map.get_longitude();
let lat0 = map.get_latitude();
map.invoke_zoom_by(1.0, 400.0, 300.0); assert!(
(map.get_longitude() - lon0).abs() < 1e-4,
"centre-anchored zoom should NOT move longitude: {lon0} -> {}",
map.get_longitude()
);
assert!(
(map.get_latitude() - lat0).abs() < 1e-4,
"centre-anchored zoom should NOT move latitude: {lat0} -> {}",
map.get_latitude()
);
}
#[test]
fn zoom_anchored_off_centre_does_move_camera() {
let (map, c) = make_map();
c.set_centre(0.0, 0.0);
c.set_zoom(3.0);
let lon0 = map.get_longitude();
map.invoke_zoom_by(2.0, 0.0, 0.0);
assert!(
map.get_longitude() < lon0,
"off-centre zoom-in should shift camera toward anchor (lon decrease), got {}",
map.get_longitude()
);
assert!(
map.get_latitude() > 0.0,
"off-centre zoom-in should shift camera toward anchor (lat increase), got {}",
map.get_latitude()
);
}
#[test]
fn zoom_clamps_to_source_max() {
let (map, c) = make_map();
c.set_zoom(2.0);
for _ in 0..50 {
map.invoke_zoom_by(1.0, 400.0, 300.0);
}
assert!(
map.get_zoom() <= 22.0,
"zoom must not exceed source max, got {}",
map.get_zoom()
);
}
#[test]
fn zoom_clamps_to_source_min() {
let (map, c) = make_map();
c.set_zoom(2.0);
for _ in 0..50 {
map.invoke_zoom_by(-1.0, 400.0, 300.0);
}
assert!(
map.get_zoom() >= 0.0,
"zoom must not go below source min, got {}",
map.get_zoom()
);
}
#[test]
fn refresh_populates_the_tile_model() {
let (map, _c) = make_map();
let tiles = map.get_tiles();
let count = tiles.row_count();
assert!(
count > 0,
"tile model should be populated for an 800x600 viewport at z=2"
);
assert!(
count <= 64,
"didn't expect more than the whole z=2 grid (16) plus over-draw, got {count}"
);
}
#[test]
fn pan_refresh_keeps_tile_model_non_empty() {
let (map, _c) = make_map();
let count_before = map.get_tiles().row_count();
assert!(count_before > 0);
map.invoke_pan(600.0, 0.0);
map.invoke_pan(0.0, 400.0);
let count_after = map.get_tiles().row_count();
assert!(
count_after > 0,
"tile model should not empty out under panning"
);
}
#[test]
fn changing_source_via_controller_re_renders() {
let (map, c) = make_map();
let count_before = map.get_tiles().row_count();
c.set_source(slint_mapping::sources::SyntheticTileSource::new());
let count_after = map.get_tiles().row_count();
assert!(
count_after >= count_before,
"source swap should not lose tiles, before={count_before} after={count_after}"
);
}