Nothing
# skip tests on CRAN because they take too much time
skip_if(Sys.getenv("TEST_ONE") != "")
testthat::skip_on_cran()
testthat::skip_if_not_installed("duckdb")
# helpers --------------------------------------------------------------
# create duckdb connection
conn_test <- duckspatial::ddbs_create_conn()
# helper function
tester <- function(x = points_sf,
y = countries_sf,
join = "intersects",
conn = NULL,
name = NULL,
mode = "sf",
overwrite = FALSE,
quiet = FALSE) {
ddbs_join(
x = x,
y = y,
join = join,
conn = conn,
name = name,
mode = mode,
overwrite = overwrite,
quiet = quiet
)
}
# expected behavior --------------------------------------------------------------
testthat::test_that("expected behavior", {
# option 1: passing sf objects
output1 <- tester(
x = points_sf,
y = countries_sf,
join = "within"
)
testthat::expect_true(is(output1 , 'sf'))
# option 2: passing the names of tables in a duckdb db, returing sf
# write sf to duckdb
ddbs_write_table(conn_test, points_sf, "points", overwrite = TRUE)
ddbs_write_table(conn_test, countries_sf, "countries", overwrite = TRUE)
# spatial join
output2 <- tester(
conn = conn_test,
x = "points",
y = "countries",
join = "within"
)
testthat::expect_true(is(output2 , 'sf'))
# option 3: passing the names of tables in a duckdb db, creating new table in db
output3 <- tester(
conn = conn_test,
x = "points",
y = "countries",
join = "within",
name = "test_result",
overwrite = TRUE
)
testthat::expect_true(output3)
output3 <- ddbs_read_table(conn_test, "test_result")
testthat::expect_true(is(output3 , 'sf'))
ddbs_read_table(conn = conn_test, name = "test_result")
# show and suppress messages
testthat::expect_no_message( tester() )
testthat::expect_no_message( tester(quiet = TRUE))
})
testthat::test_that("error if table already exists", {
# write table for the 1st time
testthat::expect_true(tester(x = "points",
y = "countries",
conn = conn_test,
name = 'banana',
overwrite = FALSE)
)
# expected error if overwrite = FALSE
testthat::expect_error(tester(x = "points",
y = "countries",
conn = conn_test,
name = 'banana',
overwrite = FALSE))
# overwrite table
testthat::expect_true(tester(x = "points",
y = "countries",
conn = conn_test,
name = 'banana',
overwrite = TRUE))
})
# expected errors --------------------------------------------------------------
testthat::test_that("errors with incorrect input", {
testthat::expect_error(tester(x = 999))
testthat::expect_error(tester(y = 999))
testthat::expect_error(tester(join = 999))
testthat::expect_error(tester(conn = 999))
testthat::expect_error(tester(overwrite = 999))
testthat::expect_error(tester(quiet = 999))
testthat::expect_error(tester(x = "999", conn = conn_test))
testthat::expect_error(tester(y = "999", conn = conn_test))
testthat::expect_error(tester(conn = conn_test, name = c('banana', 'banana')))
})
# duckspatial_df inputs --------------------------------------------------------
testthat::test_that("ddbs_join works with duckspatial_df inputs", {
countries_path <- system.file("spatial/countries.geojson", package = "duckspatial")
# Create a distinct connection for this test to avoid interference
# Use the internal helper visible in other tests
conn <- ddbs_temp_conn()
# Load as duckspatial_df
countries_ds <- ddbs_open_dataset(countries_path, conn = conn)
# Create points as sf
# Helper defined in test-utils.R or we just create sf manually
points_sf <- sf::st_as_sf(
data.frame(id = 1:10, x = 1:10, y = 1:10),
coords = c("x", "y"),
crs = 4326
)
# Register points to the same connection as a duckspatial_df for consistent testing
ddbs_write_table(conn, points_sf, "test_points")
points_ds <- ddbs_read_table(conn, "test_points")
# 1. duckspatial_df x duckspatial_df
# Using intersects
result1 <- ddbs_join(points_ds, countries_ds, join = "intersects")
expect_s3_class(result1, "duckspatial_df")
expect_true(nrow(dplyr::collect(result1)) >= 0)
# 2. duckspatial_df x sf
# Note: Cross-connection join might occur if sf implicit connection is different, but here we expect it to work
result2 <- ddbs_join(points_ds, countries_sf, join = "intersects")
expect_s3_class(result2, "duckspatial_df")
# 3. sf x duckspatial_df
withr::with_options(list(duckspatial.mode = "sf"), {
r_sf <- ddbs_join(points_sf, countries_ds, join = "intersects")
expect_s3_class(r_sf, "sf")
})
})
# predicates -------------------------------------------------------------------
testthat::test_that("ddbs_join works with different predicates", {
# We test a few key ones to ensure parameter passing works
# Use simple data where we know the answer
# Polygon: square (0,0) to (10,10)
p1 <- sf::st_polygon(list(matrix(c(0,0, 10,0, 10,10, 0,10, 0,0), ncol=2, byrow=TRUE)))
poly_sf <- sf::st_sf(id = 1, geometry = sf::st_sfc(p1), crs=4326)
# Points: inside (5,5), edge (0,0), outside (20,20)
pts <- matrix(c(5,5, 0,0, 20,20), ncol=2, byrow=TRUE)
pts_sf <- sf::st_sf(id = 1:3, geometry = sf::st_sfc(lapply(1:3, function(i) sf::st_point(pts[i,]))), crs=4326)
res_within <- ddbs_join(pts_sf, poly_sf, join = "within") |> dplyr::collect()
expect_true(1 %in% res_within$id)
expect_false(3 %in% res_within$id)
res_disjoint <- ddbs_join(pts_sf, poly_sf, join = "disjoint") |> dplyr::collect()
expect_true(3 %in% res_disjoint$id)
expect_false(1 %in% res_disjoint$id)
res_intersects <- ddbs_join(pts_sf, poly_sf, join = "intersects") |> dplyr::collect()
expect_true(1 %in% res_intersects$id)
expect_true(2 %in% res_intersects$id)
expect_false(3 %in% res_intersects$id)
})
# output parameters ------------------------------------------------------------
testthat::test_that("ddbs_join respects output parameter", {
result_sf <- ddbs_join(points_sf, countries_sf, mode = "sf")
expect_s3_class(result_sf, "sf")
result_ds <- ddbs_join(points_sf, countries_sf, mode = "duckspatial")
expect_s3_class(result_ds, "duckspatial_df")
})
# error handling ---------------------------------------------------------------
testthat::test_that("ddbs_join throws error on CRS mismatch", {
points_3857 <- sf::st_transform(points_sf, 3857)
expect_error(
ddbs_join(points_3857, countries_sf),
"Coordinates Reference System"
)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.