# ============================================================================== # Coverage tests for matching_parallel.R and matching_join.R # ============================================================================== # ------------------------------------------------------------------------------ # matching_parallel.R edge cases # ------------------------------------------------------------------------------ test_that("can_parallelize returns TRUE when packages available", { # Both packages should be installed expect_true(couplr:::can_parallelize()) }) test_that("setup_parallel returns early for FALSE", { result <- couplr:::setup_parallel(parallel = FALSE) expect_false(result$setup) expect_null(result$original_plan) }) test_that("setup_parallel with TRUE and available packages", { skip_on_cran() result <- couplr:::setup_parallel(parallel = TRUE, n_workers = 2) expect_true(result$setup) expect_true(!is.null(result$original_plan)) # Restore couplr:::restore_parallel(result) }) test_that("setup_parallel with character plan name", { skip_on_cran() result <- couplr:::setup_parallel(parallel = "sequential") expect_true(is.list(result)) if (result$setup) { couplr:::restore_parallel(result) } }) test_that("restore_parallel does nothing when setup is FALSE", { state <- list(setup = FALSE, original_plan = NULL) expect_silent(couplr:::restore_parallel(state)) }) test_that("parallel_lapply uses future when parallel=TRUE", { skip_on_cran() result <- couplr:::parallel_lapply(1:3, function(x) x^2, parallel = TRUE) expect_equal(result, list(1, 4, 9)) }) test_that("parallel_lapply uses lapply when parallel=FALSE", { result <- couplr:::parallel_lapply(1:3, function(x) x^2, parallel = FALSE) expect_equal(result, list(1, 4, 9)) }) test_that("match_blocks_parallel handles empty left block", { # Block A: 3 left, 1 right -> 1 match # Block B: 0 left, 2 right -> 0 matches left <- data.frame(id = 1:3, block = c("A", "A", "A"), x = 1:3) right <- data.frame(id = 4:6, block = c("A", "B", "B"), x = 4:6) result <- couplr:::match_blocks_parallel( blocks = c("A", "B"), left = left, right = right, left_ids = as.character(left$id), right_ids = as.character(right$id), block_col = "block", vars = "x", distance = "euclidean", weights = 1, scale = "none", max_distance = Inf, calipers = NULL, method = "jv", parallel = FALSE ) expect_equal(nrow(result$pairs), 1) # Only 1 right in A, so 1 match expect_true(length(result$unmatched$right) >= 2) # B's right units unmatched }) test_that("match_blocks_parallel handles empty right block", { left <- data.frame(id = 1:4, block = c("A", "A", "B", "B"), x = 1:4) right <- data.frame(id = 5:6, block = c("A", "A"), x = 5:6) # Block B has no right entries result <- couplr:::match_blocks_parallel( blocks = c("A", "B"), left = left, right = right, left_ids = as.character(left$id), right_ids = as.character(right$id), block_col = "block", vars = "x", distance = "euclidean", weights = 1, scale = "none", max_distance = Inf, calipers = NULL, method = "jv", parallel = FALSE ) expect_equal(nrow(result$pairs), 2) # Only A matches expect_true(length(result$unmatched$left) >= 2) # B's left units unmatched }) test_that("greedy_blocks_parallel handles empty left block", { # Block A: 3 left, 1 right -> 1 match # Block B: 0 left, 2 right -> 0 matches left <- data.frame(id = 1:3, block = c("A", "A", "A"), x = 1:3) right <- data.frame(id = 4:6, block = c("A", "B", "B"), x = 4:6) result <- couplr:::greedy_blocks_parallel( blocks = c("A", "B"), left = left, right = right, left_ids = as.character(left$id), right_ids = as.character(right$id), block_col = "block", vars = "x", distance = "euclidean", weights = 1, scale = "none", max_distance = Inf, calipers = NULL, strategy = "sorted", parallel = FALSE ) expect_equal(nrow(result$pairs), 1) # Only 1 right in A }) test_that("greedy_blocks_parallel handles empty right block", { left <- data.frame(id = 1:4, block = c("A", "A", "B", "B"), x = 1:4) right <- data.frame(id = 5:6, block = c("A", "A"), x = 5:6) result <- couplr:::greedy_blocks_parallel( blocks = c("A", "B"), left = left, right = right, left_ids = as.character(left$id), right_ids = as.character(right$id), block_col = "block", vars = "x", distance = "euclidean", weights = 1, scale = "none", max_distance = Inf, calipers = NULL, strategy = "sorted", parallel = FALSE ) expect_equal(nrow(result$pairs), 2) }) # ------------------------------------------------------------------------------ # matching_join.R edge cases # ------------------------------------------------------------------------------ test_that("join_matched errors on non-matching_result", { expect_error( couplr::join_matched(data.frame(), data.frame(id = 1), data.frame(id = 1)), "matching_result" ) }) test_that("join_matched errors on non-data frame left", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, list(x = 1), right), "data frames" ) }) test_that("join_matched errors on non-data frame right", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, list(x = 1)), "data frames" ) }) test_that("join_matched errors on missing left_id column", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, right, left_id = "missing_col"), "not found in left" ) }) test_that("join_matched errors on missing right_id column", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, right, right_id = "missing_col"), "not found in right" ) }) test_that("join_matched errors on wrong suffix length", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, right, suffix = "_only_one"), "length 2" ) }) test_that("join_matched warns on empty pairs", { # Create a result with empty pairs result <- list( pairs = tibble::tibble( left_id = character(0), right_id = character(0), distance = numeric(0) ), info = list() ) class(result) <- c("matching_result", "list") expect_warning( couplr::join_matched(result, data.frame(id = 1), data.frame(id = 2)), "No matched pairs" ) }) test_that("join_matched errors on missing left_vars", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, right, left_vars = c("x", "missing_var")), "not found in left" ) }) test_that("join_matched errors on missing right_vars", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") expect_error( couplr::join_matched(result, left, right, right_vars = c("x", "missing_var")), "not found in right" ) }) test_that("join_matched works with custom suffixes", { left <- data.frame(id = 1:3, x = 1:3, y = 4:6) right <- data.frame(id = 4:6, x = 7:9, z = 10:12) result <- couplr::match_couples(left, right, vars = "x") joined <- couplr::join_matched(result, left, right, suffix = c("_treated", "_control")) expect_true("x_treated" %in% names(joined)) expect_true("x_control" %in% names(joined)) expect_true("y_treated" %in% names(joined)) expect_true("z_control" %in% names(joined)) }) test_that("join_matched includes/excludes optional columns", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") # Without distance joined <- couplr::join_matched(result, left, right, include_distance = FALSE) expect_false("distance" %in% names(joined)) # Without pair_id joined <- couplr::join_matched(result, left, right, include_pair_id = FALSE) expect_false("pair_id" %in% names(joined)) }) test_that("join_matched handles numeric IDs correctly", { left <- data.frame(id = 1:3, x = c(1.0, 2.0, 3.0)) right <- data.frame(id = 4:6, x = c(1.1, 2.1, 3.1)) result <- couplr::match_couples(left, right, vars = "x") joined <- couplr::join_matched(result, left, right) expect_equal(nrow(joined), 3) expect_true(all(c("x_left", "x_right") %in% names(joined))) }) test_that("augment.matching_result works", { left <- data.frame(id = 1:3, x = 1:3) right <- data.frame(id = 4:6, x = 4:6) result <- couplr::match_couples(left, right, vars = "x") # Test via couplr::augment joined <- couplr::augment(result, left, right) expect_s3_class(joined, "tbl_df") expect_equal(nrow(joined), 3) }) test_that("join_matched with specific left_vars and right_vars", { left <- data.frame(id = 1:3, x = 1:3, y = 4:6, z = 7:9) right <- data.frame(id = 4:6, x = 10:12, a = 13:15, b = 16:18) result <- couplr::match_couples(left, right, vars = "x") joined <- couplr::join_matched( result, left, right, left_vars = c("x", "y"), right_vars = c("x", "a") ) expect_true("x_left" %in% names(joined)) expect_true("y_left" %in% names(joined)) expect_true("x_right" %in% names(joined)) expect_true("a_right" %in% names(joined)) expect_false("z_left" %in% names(joined)) expect_false("b_right" %in% names(joined)) })