# if running manually, please run the following line first: # source("tests/testthat/setup.R") tester <- function( travel_matrix = smaller_matrix, land_use_data = get("land_use_data", envir = parent.frame()), opportunity = "jobs", travel_cost = "travel_time", demand = "population", decay_function = decay_exponential(0.1), alpha = 1, group_by = "mode", fill_missing_ids = TRUE, detailed_results = FALSE ) { spatial_availability( travel_matrix, land_use_data, opportunity, travel_cost, demand, decay_function, alpha, group_by, fill_missing_ids, detailed_results ) } test_that("raises errors due to incorrect input", { expect_error(tester(alpha = "a")) expect_error(tester(alpha = -1)) expect_error(tester(alpha = c(1, 2))) expect_error(tester(alpha = Inf)) expect_error(tester(decay_function = "a")) expect_error(tester(decay_function = mean)) expect_error(tester(decay_function = get)) expect_error(tester(opportunity = 1)) expect_error(tester(opportunity = c("schools", "jobs"))) expect_error(tester(travel_cost = 1)) expect_error(tester(travel_cost = c("travel_time", "monetary_cost"))) expect_error(tester(demand = 1)) expect_error(tester(demand = c("population", "population"))) expect_error(tester(group_by = 1)) expect_error(tester(group_by = NA)) expect_error(tester(group_by = "from_id")) expect_error(tester(group_by = c("mode", "mode"))) expect_error(tester(fill_missing_ids = 1)) expect_error(tester(fill_missing_ids = c(TRUE, TRUE))) expect_error(tester(fill_missing_ids = NA)) expect_error(tester(detailed_results = 1)) expect_error(tester(detailed_results = c(TRUE, TRUE))) expect_error(tester(detailed_results = NA)) expect_error(tester(as.list(travel_matrix))) expect_error(tester(travel_matrix[, .(oi = from_id, to_id, travel_time)])) expect_error(tester(travel_matrix[, .(from_id, oi = to_id, travel_time)])) expect_error( tester( travel_matrix[, .(from_id, to_id, oi = travel_time)], travel_cost = "travel_time" ) ) expect_error( tester( travel_matrix[, .(from_id, to_id, travel_time, oi = mode)], group_by = "mode" ) ) expect_error(tester(as.list(land_use_data))) expect_error( tester(land_use_data = land_use_data[, .(oi = id, jobs, population)]) ) expect_error( tester( land_use_data = land_use_data[, .(id, oi = jobs, population)], opportunity = "jobs" ) ) expect_error( tester( land_use_data = land_use_data[, .(id, jobs, oi = population)], demand = "population" ) ) }) test_that("throws warning if travel_matrix has extra col", { # i.e. col not listed in travel_cost and by_col expect_warning(tester(group_by = character(0))) }) test_that("returns a dataframe whose class is the same as travel_matrix's", { result <- tester() expect_is(result, "data.table") result <- tester(land_use_data = as.data.frame(land_use_data)) expect_is(result, "data.table") result <- tester(as.data.frame(smaller_matrix)) expect_false(inherits(result, "data.table")) expect_is(result, "data.frame") result <- tester(as.data.frame(smaller_matrix), as.data.frame(land_use_data)) expect_false(inherits(result, "data.table")) expect_is(result, "data.frame") }) test_that("result has correct structure", { result <- tester() expect_true(ncol(result) == 3) expect_is(result$id, "character") expect_is(result$mode, "character") expect_is(result$jobs, "numeric") result <- tester(opportunity = "schools") expect_true(ncol(result) == 3) expect_is(result$id, "character") expect_is(result$mode, "character") expect_is(result$schools, "numeric") suppressWarnings(result <- tester(group_by = character(0))) expect_true(ncol(result) == 2) expect_is(result$id, "character") expect_is(result$jobs, "numeric") result <- tester( data.table::data.table( mode = character(), from_id = character(), to_id = character(), travel_time = integer() ) ) expect_true(ncol(result) == 3) expect_true(nrow(result) == 0) expect_is(result$id, "character") expect_is(result$mode, "character") expect_is(result$jobs, "numeric") }) test_that("input data sets remain unchanged", { original_smaller_matrix <- travel_matrix[1:10] original_land_use_data <- readRDS(file.path(data_dir, "land_use_data.rds")) result <- tester() # subsets in other functions tests set smaller_matrix index data.table::setindex(smaller_matrix, NULL) expect_equal(original_smaller_matrix, smaller_matrix) expect_equal(original_land_use_data, land_use_data) }) test_that("fill_missing_ids arg works correctly", { small_travel_matrix <- travel_matrix[ from_id %in% c("89a88cdb57bffff", "89a88cdb597ffff") ] small_travel_matrix <- small_travel_matrix[ !(from_id == "89a88cdb57bffff" & mode == "transit2") ] result <- tester(small_travel_matrix, fill_missing_ids = TRUE) result[, jobs := as.integer(jobs)] data.table::setkey(result, NULL) expect_identical( result, data.table::data.table( id = rep(c("89a88cdb57bffff", "89a88cdb597ffff"), each = 2), mode = rep(c("transit", "transit2"), times = 2), jobs = c(362330L, 0L, 133722L, 496053L) ) ) result <- tester(small_travel_matrix, fill_missing_ids = FALSE) result[, jobs := as.integer(jobs)] expect_identical( result, data.table::data.table( id = c("89a88cdb57bffff", "89a88cdb597ffff", "89a88cdb597ffff"), mode = c("transit", "transit", "transit2"), jobs = c(362330L, 133722L, 496053L) ) ) }) test_that("accepts custom decay function", { selected_ids <- c( "89a88cdb57bffff", "89a88cdb597ffff", "89a88cdb5b3ffff", "89a88cdb5cfffff", "89a88cd909bffff" ) smaller_travel_matrix <- travel_matrix[ from_id %in% selected_ids & to_id %in% selected_ids ] custom_function <- function(travel_cost) rep(1L, length(travel_cost)) result <- tester(smaller_travel_matrix, decay_function = custom_function) result[, jobs := round(jobs, digits = 0)] expect_identical( result, data.table::data.table( id = rep(selected_ids, 2), mode = rep(c("transit", "transit2"), each = 5), jobs = rep(c(94, 44, 218, 243, 0)) ) ) }) test_that("works even if smaller_matrix and land_use has specific colnames", { expected_result <- tester() smaller_matrix[, opportunity := "oi"] result <- suppressWarnings(tester(smaller_matrix)) expect_identical(expected_result, result) smaller_matrix[, opportunity := NULL] smaller_matrix[, travel_cost := "oi"] result <- suppressWarnings(tester(smaller_matrix)) expect_identical(expected_result, result) smaller_matrix[, travel_cost := NULL] smaller_matrix[, groups := "oi"] result <- suppressWarnings(tester(smaller_matrix)) expect_identical(expected_result, result) smaller_matrix[, groups := NULL] smaller_matrix[, demand := "oi"] result <- suppressWarnings(tester(smaller_matrix)) expect_identical(expected_result, result) smaller_matrix[, demand := NULL] land_use_data[, opportunity := "oi"] result <- suppressWarnings(tester(land_use_data = land_use_data)) expect_identical(expected_result, result) land_use_data[, opportunity := NULL] land_use_data[, demand := "oi"] result <- suppressWarnings(tester(land_use_data = land_use_data)) expect_identical(expected_result, result) land_use_data[, demand := NULL] }) test_that("calculates spatial availability correctly", { # data used in Soukhov et al. (2023), slightly modified paper_travel_matrix <- data.table::data.table( from_id = rep(c("A", "B", "C"), each = 3), to_id = as.character(rep(1:3, 3)), travel_time = c(15, 30, 100, 30, 15, 100, 100, 100, 15) ) paper_land_use_data <- data.table::data.table( id = c("A", "B", "C", "1", "2", "3"), population = c(50000, 150000, 10000, 0, 0, 0), jobs = c(0, 0, 0, 100000, 100000, 10000) ) result <- tester( paper_travel_matrix, paper_land_use_data, group_by = character(0) ) result[, jobs := round(jobs, digits = 0)] expect_identical( result, data.table::data.table( id = c("A", "B", "C"), jobs = c(66833, 133203, 9963) ) ) }) test_that("results are grouped by decay_function_arg when needed", { small_travel_matrix <- travel_matrix[ from_id %in% c("89a88cdb57bffff", "89a88cdb597ffff") & mode != "transit2" ] result <- tester( small_travel_matrix, decay_function = decay_exponential(c(0.5, 0.6)) ) result[, jobs := round(jobs, 1)] expect_identical( result, data.table::data.table( id = rep(c("89a88cdb57bffff", "89a88cdb597ffff"), times = 2), mode = rep("transit", 4), decay_function_arg = rep(c(0.5, 0.6), each = 2), jobs = c(388780.8, 107272.2, 389238.9, 106814.1) ) ) }) test_that("throws warning w/ fill_missing_ids = FALSE with detailed_results", { expect_warning(tester(fill_missing_ids = FALSE, detailed_results = TRUE)) }) test_that("result has correct structure with detailed_results = TRUE", { result <- tester(detailed_results = TRUE) expect_true(ncol(result) == 7) expect_is(result$mode, "character") expect_is(result$from_id, "character") expect_is(result$to_id, "character") expect_is(result$demand_bal_fac, "numeric") expect_is(result$impedance_bal_fac, "numeric") expect_is(result$combined_bal_fac, "numeric") expect_is(result$jobs, "numeric") result <- tester(detailed_results = TRUE, opportunity = "schools") expect_true(ncol(result) == 7) expect_is(result$mode, "character") expect_is(result$from_id, "character") expect_is(result$to_id, "character") expect_is(result$demand_bal_fac, "numeric") expect_is(result$impedance_bal_fac, "numeric") expect_is(result$combined_bal_fac, "numeric") expect_is(result$schools, "numeric") result <- tester(smaller_matrix[0], detailed_results = TRUE) expect_true(ncol(result) == 7) expect_true(nrow(result) == 0) expect_is(result$mode, "character") expect_is(result$from_id, "character") expect_is(result$to_id, "character") expect_is(result$demand_bal_fac, "numeric") expect_is(result$impedance_bal_fac, "numeric") expect_is(result$combined_bal_fac, "numeric") expect_is(result$jobs, "numeric") })