Skip to content

Commit 07b7cfa

Browse files
Add tests for dggrid_compat, plot_methods, grid_helpers (coverage 74% -> 82%)
1 parent c8a23d2 commit 07b7cfa

File tree

3 files changed

+558
-0
lines changed

3 files changed

+558
-0
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# tests/testthat/test-dggrid-compat-functions.R
2+
# Tests for dggridR compatibility layer functions
3+
4+
test_that("as_dggrid converts hexify_grid to dggridR format", {
5+
grid <- hexify_grid(area = 1000, aperture = 3)
6+
dggs <- as_dggrid(grid)
7+
8+
expect_type(dggs, "list")
9+
expect_equal(dggs$aperture, 3)
10+
expect_equal(dggs$res, grid$resolution)
11+
expect_equal(dggs$topology, "HEXAGON")
12+
expect_equal(dggs$projection, "ISEA")
13+
expect_equal(dggs$precision, 7L)
14+
expect_equal(dggs$pole_lon_deg, 11.25)
15+
})
16+
17+
test_that("as_dggrid rejects non-hexify_grid objects", {
18+
expect_error(as_dggrid(list(a = 1)), "must be a hexify_grid object")
19+
expect_error(as_dggrid(data.frame()), "must be a hexify_grid object")
20+
})
21+
22+
test_that("from_dggrid converts dggridR format to hexify_grid", {
23+
dggs <- list(
24+
res = 5L,
25+
aperture = 3L,
26+
topology = "HEXAGON",
27+
projection = "ISEA"
28+
)
29+
30+
grid <- from_dggrid(dggs)
31+
32+
expect_s3_class(grid, "hexify_grid")
33+
expect_equal(grid$resolution, 5L)
34+
expect_equal(grid$aperture, 3L)
35+
})
36+
37+
test_that("from_dggrid rejects invalid input", {
38+
expect_error(from_dggrid("not a list"), "must be a list")
39+
expect_error(from_dggrid(list()), "missing required fields")
40+
expect_error(from_dggrid(list(res = 5)), "missing required fields")
41+
})
42+
43+
test_that("from_dggrid warns on unsupported projection", {
44+
dggs <- list(
45+
res = 5L,
46+
aperture = 3L,
47+
topology = "HEXAGON",
48+
projection = "FULLER"
49+
)
50+
expect_warning(from_dggrid(dggs), "Only ISEA projection")
51+
})
52+
53+
test_that("from_dggrid warns on unsupported topology", {
54+
dggs <- list(
55+
res = 5L,
56+
aperture = 3L,
57+
topology = "DIAMOND",
58+
projection = "ISEA"
59+
)
60+
expect_warning(from_dggrid(dggs), "Only HEXAGON topology")
61+
})
62+
63+
test_that("from_dggrid rejects unsupported aperture", {
64+
dggs <- list(
65+
res = 5L,
66+
aperture = 5L,
67+
topology = "HEXAGON",
68+
projection = "ISEA"
69+
)
70+
expect_error(from_dggrid(dggs), "Aperture 5 not supported")
71+
})
72+
73+
test_that("from_dggrid warns on non-default orientation", {
74+
dggs <- list(
75+
res = 5L,
76+
aperture = 3L,
77+
topology = "HEXAGON",
78+
projection = "ISEA",
79+
pole_lon_deg = 0
80+
)
81+
expect_warning(from_dggrid(dggs), "Non-default pole_lon_deg")
82+
83+
dggs$pole_lon_deg <- 11.25
84+
dggs$pole_lat_deg <- 0
85+
expect_warning(from_dggrid(dggs), "Non-default pole_lat_deg")
86+
87+
dggs$pole_lat_deg <- 58.28252559
88+
dggs$azimuth_deg <- 45
89+
expect_warning(from_dggrid(dggs), "Non-default azimuth_deg")
90+
})
91+
92+
test_that("dggrid_is_compatible validates compatible grids", {
93+
dggs <- list(
94+
res = 5L,
95+
aperture = 3L,
96+
topology = "HEXAGON",
97+
projection = "ISEA"
98+
)
99+
expect_true(dggrid_is_compatible(dggs))
100+
})
101+
102+
test_that("dggrid_is_compatible rejects incompatible grids (strict=TRUE)", {
103+
# Not a list
104+
expect_error(dggrid_is_compatible("not a list"), "not compatible")
105+
106+
# Wrong projection
107+
dggs <- list(aperture = 3L, topology = "HEXAGON", projection = "FULLER")
108+
expect_error(dggrid_is_compatible(dggs), "ISEA projection")
109+
110+
# Wrong topology
111+
dggs <- list(aperture = 3L, topology = "DIAMOND", projection = "ISEA")
112+
expect_error(dggrid_is_compatible(dggs), "HEXAGON topology")
113+
114+
# Wrong aperture
115+
dggs <- list(aperture = 5L, topology = "HEXAGON", projection = "ISEA")
116+
expect_error(dggrid_is_compatible(dggs), "Aperture must be")
117+
})
118+
119+
test_that("dggrid_is_compatible returns FALSE for incompatible grids (strict=FALSE)", {
120+
dggs <- list(aperture = 3L, topology = "HEXAGON", projection = "FULLER")
121+
expect_false(dggrid_is_compatible(dggs, strict = FALSE))
122+
123+
dggs <- list(aperture = 3L, topology = "DIAMOND", projection = "ISEA")
124+
expect_false(dggrid_is_compatible(dggs, strict = FALSE))
125+
})
126+
127+
test_that("dggrid_is_compatible detects non-default orientation", {
128+
dggs <- list(
129+
aperture = 3L,
130+
topology = "HEXAGON",
131+
projection = "ISEA",
132+
pole_lon_deg = 0
133+
)
134+
expect_error(dggrid_is_compatible(dggs), "pole_lon_deg")
135+
})
136+
137+
test_that("round-trip: hexify_grid -> dggridR -> hexify_grid", {
138+
original <- hexify_grid(area = 1000, aperture = 3)
139+
dggs <- as_dggrid(original)
140+
recovered <- from_dggrid(dggs)
141+
142+
expect_equal(original$resolution, recovered$resolution)
143+
expect_equal(original$aperture, recovered$aperture)
144+
})

tests/testthat/test-grid-helpers.R

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# tests/testthat/test-grid-helpers.R
2+
# Tests for grid helper functions
3+
4+
test_that("lonlat_to_cell works with HexGridInfo", {
5+
grid <- hex_grid(area_km2 = 1000)
6+
cells <- lonlat_to_cell(lon = c(0, 10), lat = c(45, 50), grid = grid)
7+
8+
expect_type(cells, "double")
9+
expect_length(cells, 2)
10+
expect_true(all(cells > 0))
11+
})
12+
13+
test_that("lonlat_to_cell works with HexData", {
14+
df <- data.frame(lon = c(0, 10), lat = c(45, 50))
15+
result <- hexify(df, lon = "lon", lat = "lat", area_km2 = 1000)
16+
17+
# Use the HexData object as grid source
18+
cells <- lonlat_to_cell(lon = 5, lat = 48, grid = result)
19+
20+
expect_type(cells, "double")
21+
expect_length(cells, 1)
22+
})
23+
24+
test_that("lonlat_to_cell works with mixed aperture", {
25+
grid <- hex_grid(area_km2 = 1000, aperture = "4/3")
26+
cells <- lonlat_to_cell(lon = c(0, 10), lat = c(45, 50), grid = grid)
27+
28+
expect_type(cells, "double")
29+
expect_length(cells, 2)
30+
})
31+
32+
test_that("cell_to_lonlat returns cell centers", {
33+
grid <- hex_grid(area_km2 = 1000)
34+
cells <- lonlat_to_cell(lon = c(0, 10), lat = c(45, 50), grid = grid)
35+
coords <- cell_to_lonlat(cells, grid)
36+
37+
expect_type(coords, "list")
38+
expect_true("lon_deg" %in% names(coords))
39+
expect_true("lat_deg" %in% names(coords))
40+
expect_length(coords$lon_deg, 2)
41+
})
42+
43+
test_that("cell_to_lonlat works with mixed aperture", {
44+
grid <- hex_grid(area_km2 = 1000, aperture = "4/3")
45+
cells <- lonlat_to_cell(lon = c(0, 10), lat = c(45, 50), grid = grid)
46+
coords <- cell_to_lonlat(cells, grid)
47+
48+
expect_type(coords, "list")
49+
expect_length(coords$lon_deg, 2)
50+
})
51+
52+
test_that("lonlat_to_cell -> cell_to_lonlat round-trip lands in same cell", {
53+
grid <- hex_grid(area_km2 = 1000)
54+
55+
original_lon <- c(0, 10, -5)
56+
original_lat <- c(45, 50, 48)
57+
58+
cells1 <- lonlat_to_cell(original_lon, original_lat, grid)
59+
centers <- cell_to_lonlat(cells1, grid)
60+
cells2 <- lonlat_to_cell(centers$lon_deg, centers$lat_deg, grid)
61+
62+
expect_equal(cells1, cells2)
63+
})
64+
65+
test_that("cell_to_sf creates sf polygons", {
66+
skip_if_not_installed("sf")
67+
68+
grid <- hex_grid(area_km2 = 10000)
69+
cells <- lonlat_to_cell(lon = c(0, 10), lat = c(45, 50), grid = grid)
70+
polys <- cell_to_sf(cells, grid)
71+
72+
expect_s3_class(polys, "sf")
73+
expect_true("cell_id" %in% names(polys))
74+
expect_equal(nrow(polys), length(unique(cells)))
75+
})
76+
77+
test_that("cell_to_sf works with HexData (no cell_id)", {
78+
skip_if_not_installed("sf")
79+
80+
df <- data.frame(lon = c(0, 10, 20), lat = c(45, 50, 55))
81+
result <- hexify(df, lon = "lon", lat = "lat", area_km2 = 10000)
82+
83+
polys <- cell_to_sf(grid = result)
84+
85+
expect_s3_class(polys, "sf")
86+
expect_equal(nrow(polys), length(unique(result@cell_id)))
87+
})
88+
89+
test_that("cell_to_sf errors without cell_id for HexGridInfo", {
90+
skip_if_not_installed("sf")
91+
92+
grid <- hex_grid(area_km2 = 10000)
93+
expect_error(cell_to_sf(grid = grid), "cell_id required")
94+
})
95+
96+
test_that("cell_to_sf errors on empty cell_id", {
97+
skip_if_not_installed("sf")
98+
99+
grid <- hex_grid(area_km2 = 10000)
100+
expect_error(cell_to_sf(cell_id = numeric(0), grid = grid), "No valid")
101+
expect_error(cell_to_sf(cell_id = c(NA, NA), grid = grid), "No valid")
102+
})
103+
104+
test_that("grid_rect generates regional grid", {
105+
skip_if_not_installed("sf")
106+
107+
grid <- hex_grid(area_km2 = 50000)
108+
europe <- grid_rect(c(-10, 35, 30, 60), grid)
109+
110+
expect_s3_class(europe, "sf")
111+
expect_gt(nrow(europe), 0)
112+
})
113+
114+
test_that("grid_rect accepts sf bbox input", {
115+
skip_if_not_installed("sf")
116+
117+
grid <- hex_grid(area_km2 = 50000)
118+
france <- hexify_world[hexify_world$name == "France", ]
119+
hexes <- grid_rect(france, grid)
120+
121+
expect_s3_class(hexes, "sf")
122+
expect_gt(nrow(hexes), 0)
123+
})
124+
125+
test_that("grid_global generates global grid", {
126+
skip_if_not_installed("sf")
127+
128+
# Use very coarse grid to keep test fast
129+
grid <- hex_grid(area_km2 = 500000)
130+
global <- grid_global(grid)
131+
132+
expect_s3_class(global, "sf")
133+
expect_gt(nrow(global), 10) # Should have at least some cells
134+
})
135+
136+
test_that("grid_global warns for large grids", {
137+
skip_if_not_installed("sf")
138+
139+
# Small cells = many cells = warning
140+
grid <- hex_grid(area_km2 = 100) # Very small cells
141+
expect_warning(grid_global(grid), "cells")
142+
})
143+
144+
test_that("grid_clip clips to boundary", {
145+
skip_if_not_installed("sf")
146+
147+
grid <- hex_grid(area_km2 = 20000)
148+
france <- hexify_world[hexify_world$name == "France", ]
149+
clipped <- grid_clip(france, grid)
150+
151+
expect_s3_class(clipped, "sf")
152+
expect_gt(nrow(clipped), 0)
153+
})
154+
155+
test_that("grid_clip with crop = FALSE keeps full hexagons", {
156+
skip_if_not_installed("sf")
157+
158+
grid <- hex_grid(area_km2 = 20000)
159+
france <- hexify_world[hexify_world$name == "France", ]
160+
clipped <- grid_clip(france, grid, crop = FALSE)
161+
162+
expect_s3_class(clipped, "sf")
163+
})
164+
165+
test_that("extract_grid works with HexGridInfo", {
166+
grid <- hex_grid(area_km2 = 1000)
167+
g <- hexify:::extract_grid(grid)
168+
169+
expect_s4_class(g, "HexGridInfo")
170+
})
171+
172+
test_that("extract_grid works with HexData", {
173+
df <- data.frame(lon = c(0, 10), lat = c(45, 50))
174+
result <- hexify(df, lon = "lon", lat = "lat", area_km2 = 1000)
175+
g <- hexify:::extract_grid(result)
176+
177+
expect_s4_class(g, "HexGridInfo")
178+
})
179+
180+
test_that("extract_grid works with legacy hexify_grid", {
181+
grid <- hexify_grid(area = 1000, aperture = 3)
182+
g <- hexify:::extract_grid(grid)
183+
184+
expect_s4_class(g, "HexGridInfo")
185+
})
186+
187+
test_that("extract_grid errors on invalid input", {
188+
expect_error(hexify:::extract_grid(list(a = 1)), "Cannot extract grid")
189+
expect_error(hexify:::extract_grid(data.frame()), "Cannot extract grid")
190+
})

0 commit comments

Comments
 (0)