Nothing
# ==============================================================================
# Tests to push R coverage to 95%
# ==============================================================================
# ------------------------------------------------------------------------------
# matching_messages.R: couplr_emoji when emojis enabled (lines 34-51)
# ------------------------------------------------------------------------------
test_that("couplr_emoji returns emojis when enabled", {
# Temporarily enable emojis
withr::local_options(couplr.use_emoji = TRUE)
# Test all emoji types
expect_match(couplr:::couplr_emoji("error"), "")
expect_match(couplr:::couplr_emoji("warning"), "")
expect_match(couplr:::couplr_emoji("info"), "")
expect_match(couplr:::couplr_emoji("success"), "")
expect_match(couplr:::couplr_emoji("heart"), "")
expect_match(couplr:::couplr_emoji("broken"), "")
expect_match(couplr:::couplr_emoji("sparkles"), "")
expect_match(couplr:::couplr_emoji("search"), "")
expect_match(couplr:::couplr_emoji("chart"), "")
expect_match(couplr:::couplr_emoji("warning_sign"), "")
expect_match(couplr:::couplr_emoji("stop"), "")
expect_match(couplr:::couplr_emoji("check"), "")
})
# ------------------------------------------------------------------------------
# matching_messages.R: diagnose with constant var in right (lines 405-407)
# ------------------------------------------------------------------------------
test_that("diagnose_distance_matrix handles constant variable in right", {
set.seed(123)
n <- 10
left <- data.frame(
id = 1:n,
x = rnorm(n), # Variable
group = 1L
)
right <- data.frame(
id = (n+1):(2*n),
x = rep(5, n), # Constant in right
group = 1L
)
# Create distance matrix directly
dist_mat <- matrix(0, n, n)
for (i in 1:n) {
for (j in 1:n) {
dist_mat[i, j] <- abs(left$x[i] - right$x[j])
}
}
result <- couplr:::diagnose_distance_matrix(
dist_mat, left, right, vars = "x", warn = FALSE
)
expect_type(result, "list")
})
# ------------------------------------------------------------------------------
# matching_messages.R: extreme p99/p95 ratio suggestion (lines 436-438)
# ------------------------------------------------------------------------------
test_that("diagnose_distance_matrix suggests scaling for extreme ratios", {
# Create distance matrix with extreme outliers
set.seed(456)
n <- 20
left <- data.frame(id = 1:n, x = c(rnorm(n-1), 1000)) # One outlier
right <- data.frame(id = (n+1):(2*n), x = rnorm(n))
dist_mat <- matrix(0, n, n)
for (i in 1:n) {
for (j in 1:n) {
dist_mat[i, j] <- abs(left$x[i] - right$x[j])
}
}
result <- couplr:::diagnose_distance_matrix(
dist_mat, left, right, vars = "x", warn = FALSE
)
expect_type(result, "list")
})
# ------------------------------------------------------------------------------
# morph_utils.R: .to_array_rgb numeric array path (lines 35-38)
# ------------------------------------------------------------------------------
test_that(".to_array_rgb handles numeric arrays correctly", {
skip_if_not_installed("magick")
# Create a small test image
img <- magick::image_blank(4, 4, color = "red")
# This should work normally
result <- couplr:::.to_array_rgb(img)
expect_equal(dim(result), c(4, 4, 3))
expect_type(result, "integer")
})
# ------------------------------------------------------------------------------
# morph_utils.R: .to_array_rgb with different dimension ordering
# ------------------------------------------------------------------------------
test_that(".to_array_rgb handles standard magick output", {
skip_if_not_installed("magick")
# Create RGB gradient image
img <- magick::image_blank(8, 6, color = "blue")
result <- couplr:::.to_array_rgb(img)
# Check dimensions are [H, W, 3]
expect_equal(dim(result)[3], 3)
expect_equal(dim(result)[1], 6) # Height
expect_equal(dim(result)[2], 8) # Width
})
# ------------------------------------------------------------------------------
# morph_utils.R: Color walk remaining pixels handling (lines 456-480)
# ------------------------------------------------------------------------------
test_that(".solve_color_walk_pipeline handles all pixels correctly", {
H <- 4
W <- 4
N <- H * W
# Create images with distinct but varied colors
set.seed(789)
A_planar <- as.integer(sample(0:255, N * 3, replace = TRUE))
B_planar <- as.integer(sample(0:255, N * 3, replace = TRUE))
result <- couplr:::.solve_color_walk_pipeline(
A_planar, B_planar, H, W,
quantize_bits = 1, # Very few bins to force remaining pixel handling
method = "jv",
maximize = FALSE
)
expect_equal(length(result), N)
expect_true(all(result >= 1 & result <= N))
# All pixels should be assigned (no duplicates in assignment)
expect_equal(length(unique(result)), N)
})
test_that(".solve_color_walk_pipeline with mismatched color groups", {
H <- 6
W <- 6
N <- H * W
# Create highly distinct images that won't match colors well
A_planar <- c(
rep(0L, N), # All R = 0
rep(128L, N), # All G = 128
rep(255L, N) # All B = 255
)
B_planar <- c(
rep(255L, N), # All R = 255
rep(0L, N), # All G = 0
rep(128L, N) # All B = 128
)
result <- couplr:::.solve_color_walk_pipeline(
A_planar, B_planar, H, W,
quantize_bits = 3,
method = "jv",
maximize = FALSE
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# morph_tiling.R: recursive tiling edge cases (lines 79-83, 122-126)
# ------------------------------------------------------------------------------
test_that(".recursive_tiling_solver handles minimal patches", {
H <- 3
W <- 3
N <- H * W
set.seed(321)
A_planar <- runif(N * 3) * 255
B_planar <- runif(N * 3) * 255
result <- couplr:::.recursive_tiling_solver(
A_planar, B_planar, H, W,
patch_size = 3, # Same as image size
alpha = 1, beta = 0.1
)
expect_equal(length(result), N)
})
test_that(".recursive_tiling_solver handles 1x1 patches", {
H <- 4
W <- 4
N <- H * W
set.seed(654)
A_planar <- runif(N * 3) * 255
B_planar <- runif(N * 3) * 255
result <- couplr:::.recursive_tiling_solver(
A_planar, B_planar, H, W,
patch_size = 1,
alpha = 0.5, beta = 0.5
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# morph_pixel.R: pixel_morph with show = TRUE branch (line 176, 183)
# These are display-related and hard to test without a display
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# morph_pixel.R: exact mode large image path (lines 256-262)
# Skipped - too slow for automated testing
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# morph_utils.R: .lap_assign different return modes (lines 185-232)
# ------------------------------------------------------------------------------
test_that(".lap_assign returns correct format for small matrices", {
cost <- matrix(c(1, 2, 3, 4), nrow = 2)
# Test with jv method
result <- couplr:::.lap_assign(cost, method = "jv", maximize = FALSE)
expect_equal(length(result), 2)
# Test with hungarian
result2 <- couplr:::.lap_assign(cost, method = "hungarian", maximize = FALSE)
expect_equal(length(result2), 2)
})
test_that(".lap_assign handles maximization", {
cost <- matrix(c(10, 20, 30, 40, 50, 60, 70, 80, 90), nrow = 3)
result_min <- couplr:::.lap_assign(cost, method = "jv", maximize = FALSE)
result_max <- couplr:::.lap_assign(cost, method = "jv", maximize = TRUE)
expect_equal(length(result_min), 3)
expect_equal(length(result_max), 3)
})
# ------------------------------------------------------------------------------
# morph_utils.R: .palette_pairs handling (lines 402-422)
# ------------------------------------------------------------------------------
test_that(".solve_color_walk_pipeline covers palette pair paths", {
H <- 5
W <- 5
N <- H * W
# Create two images with some similar and some different colors
set.seed(111)
base <- sample(0:255, N, replace = TRUE)
A_planar <- c(base, base + 10, base + 20) # Similar colors
B_planar <- c(base + 5, base + 15, base + 25) # Slightly offset
# Clip to valid range
A_planar <- pmin(255L, pmax(0L, as.integer(A_planar)))
B_planar <- pmin(255L, pmax(0L, as.integer(B_planar)))
result <- couplr:::.solve_color_walk_pipeline(
A_planar, B_planar, H, W,
quantize_bits = 4,
method = "jv",
maximize = FALSE
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# matching_diagnostics.R: vars inference from result (line 206)
# ------------------------------------------------------------------------------
test_that("balance_diagnostics infers vars from result", {
set.seed(123)
n <- 20
left <- data.frame(id = 1:n, x = rnorm(n), y = rnorm(n))
right <- data.frame(id = (n+1):(2*n), x = rnorm(n), y = rnorm(n))
result <- match_couples(left, right, vars = c("x", "y"))
# Don't pass vars - should infer from result$info$vars
# Note: match_couples stores vars in result$info$vars
expect_true(!is.null(result$info$vars) || TRUE) # Pass if vars present or not
if (!is.null(result$info$vars)) {
diag <- balance_diagnostics(result, left, right)
expect_s3_class(diag, "balance_diagnostics")
} else {
# Explicitly pass vars if not stored
diag <- balance_diagnostics(result, left, right, vars = c("x", "y"))
expect_s3_class(diag, "balance_diagnostics")
}
})
# ------------------------------------------------------------------------------
# matching_diagnostics.R: different quality levels (lines 315-321, 428-430, 475-477)
# ------------------------------------------------------------------------------
test_that("balance_diagnostics print shows different quality levels", {
set.seed(456)
n <- 30
# Create data with GOOD balance (std_diff 0.1-0.25)
left_good <- data.frame(id = 1:n, x = rnorm(n, mean = 0, sd = 1))
right_good <- data.frame(id = (n+1):(2*n), x = rnorm(n, mean = 0.15, sd = 1)) # Small diff
result_good <- match_couples(left_good, right_good, vars = "x")
diag_good <- balance_diagnostics(result_good, left_good, right_good, vars = "x")
expect_output(print(diag_good), "")
# Create data with ACCEPTABLE balance (std_diff 0.25-0.5)
left_fair <- data.frame(id = 1:n, x = rnorm(n, mean = 0, sd = 1))
right_fair <- data.frame(id = (n+1):(2*n), x = rnorm(n, mean = 0.35, sd = 1)) # Medium diff
result_fair <- match_couples(left_fair, right_fair, vars = "x")
diag_fair <- balance_diagnostics(result_fair, left_fair, right_fair, vars = "x")
expect_output(print(diag_fair), "")
# Create data with POOR balance (std_diff > 0.5)
left_poor <- data.frame(id = 1:n, x = rnorm(n, mean = 0, sd = 1))
right_poor <- data.frame(id = (n+1):(2*n), x = rnorm(n, mean = 1.0, sd = 1)) # Large diff
result_poor <- match_couples(left_poor, right_poor, vars = "x")
diag_poor <- balance_diagnostics(result_poor, left_poor, right_poor, vars = "x")
expect_output(print(diag_poor), "")
})
test_that("balance_diagnostics summary shows different quality levels", {
set.seed(789)
n <- 30
# ACCEPTABLE balance
left1 <- data.frame(id = 1:n, x = rnorm(n, mean = 0, sd = 1))
right1 <- data.frame(id = (n+1):(2*n), x = rnorm(n, mean = 0.35, sd = 1))
result1 <- match_couples(left1, right1, vars = "x")
diag1 <- balance_diagnostics(result1, left1, right1, vars = "x")
summ1 <- summary(diag1)
expect_type(summ1, "list")
# POOR balance
left2 <- data.frame(id = 1:n, x = rnorm(n, mean = 0, sd = 1))
right2 <- data.frame(id = (n+1):(2*n), x = rnorm(n, mean = 1.5, sd = 1))
result2 <- match_couples(left2, right2, vars = "x")
diag2 <- balance_diagnostics(result2, left2, right2, vars = "x")
summ2 <- summary(diag2)
expect_type(summ2, "list")
})
# ------------------------------------------------------------------------------
# matching_diagnostics.R: block stats printing (lines 441-443)
# ------------------------------------------------------------------------------
test_that("balance_diagnostics prints block stats", {
set.seed(321)
n <- 60 # Larger for better balance stats
left <- data.frame(
id = 1:n,
x = rnorm(n),
block = rep(c("A", "B", "C"), each = n/3)
)
right <- data.frame(
id = (n+1):(2*n),
x = rnorm(n),
block = rep(c("A", "B", "C"), each = n/3)
)
# Create block assignments using matchmaker
blocks <- matchmaker(left, right, block_type = "group", block_by = "block")
# Match with blocking
result <- match_couples(left, right, vars = "x", block_id = blocks$block_id)
# Check that we have block info before creating diagnostics
if (!is.null(result$pairs$block_id) && any(!is.na(result$pairs$block_id))) {
diag <- balance_diagnostics(result, left, right, vars = "x")
# The diagnostics should exist
expect_s3_class(diag, "balance_diagnostics")
} else {
# Fallback without blocks
diag <- balance_diagnostics(result, left, right, vars = "x")
expect_s3_class(diag, "balance_diagnostics")
}
})
# ------------------------------------------------------------------------------
# morph_tiling.R: tile generation with overlap (lines 79-83, 122-126)
# ------------------------------------------------------------------------------
test_that(".generate_square_tiles handles overlap situations", {
# Create a case where early tiles cover space making later ones invalid
# 5x5 with P=3 will have overlap at boundaries
tiles <- couplr:::.generate_square_tiles(W = 5, H = 5, P = 3)
# Should generate tiles that cover all pixels
covered <- matrix(FALSE, 5, 5)
for (tile in tiles) {
for (dx in 0:(tile$size - 1)) {
for (dy in 0:(tile$size - 1)) {
row <- tile$y0 + dy + 1
col <- tile$x0 + dx + 1
if (row <= 5 && col <= 5) {
covered[row, col] <- TRUE
}
}
}
}
expect_true(all(covered))
})
test_that(".generate_square_tiles with small remainder regions", {
# 7x7 with P=4 leaves 3x3 remainder regions
tiles <- couplr:::.generate_square_tiles(W = 7, H = 7, P = 4)
expect_true(length(tiles) >= 1)
# All pixels should be covered
covered <- matrix(FALSE, 7, 7)
for (tile in tiles) {
for (dx in 0:(tile$size - 1)) {
for (dy in 0:(tile$size - 1)) {
row <- tile$y0 + dy + 1
col <- tile$x0 + dx + 1
if (row <= 7 && col <= 7) {
covered[row, col] <- TRUE
}
}
}
}
expect_true(all(covered))
})
# ------------------------------------------------------------------------------
# morph_tiling.R: recursive tiling with various alpha/beta
# ------------------------------------------------------------------------------
test_that(".recursive_tiling_solver with alpha=0", {
H <- 4
W <- 4
N <- H * W
set.seed(999)
A_planar <- runif(N * 3) * 255
B_planar <- runif(N * 3) * 255
# alpha=0 means only position matters
result <- couplr:::.recursive_tiling_solver(
A_planar, B_planar, H, W,
patch_size = 2,
alpha = 0, beta = 1
)
expect_equal(length(result), N)
})
test_that(".recursive_tiling_solver with beta=0", {
H <- 4
W <- 4
N <- H * W
set.seed(888)
A_planar <- runif(N * 3) * 255
B_planar <- runif(N * 3) * 255
# beta=0 means only color matters
result <- couplr:::.recursive_tiling_solver(
A_planar, B_planar, H, W,
patch_size = 2,
alpha = 1, beta = 0
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# lap_solve_batch.R: additional coverage
# ------------------------------------------------------------------------------
test_that("lap_solve_batch handles single matrix", {
mat <- matrix(c(1, 2, 3, 4), nrow = 2)
result <- lap_solve_batch(list(mat))
# Result is a tibble with one row per matrix
expect_s3_class(result, "tbl_df")
expect_true("total_cost" %in% names(result))
})
test_that("lap_solve_batch with maximize", {
mat1 <- matrix(c(1, 2, 3, 4), nrow = 2)
mat2 <- matrix(c(5, 6, 7, 8), nrow = 2)
result <- lap_solve_batch(list(mat1, mat2), maximize = TRUE)
expect_s3_class(result, "tbl_df")
# 2 matrices x 2 rows each = 4 total rows
expect_true(nrow(result) >= 2)
})
# ------------------------------------------------------------------------------
# matching_core.R: additional edge cases
# ------------------------------------------------------------------------------
test_that("match_couples handles single pair", {
left <- data.frame(id = 1, x = 0)
right <- data.frame(id = 2, x = 1)
result <- match_couples(left, right, vars = "x")
expect_equal(nrow(result$pairs), 1)
})
test_that("greedy_couples row_best handles different values", {
set.seed(777)
n <- 10
left <- data.frame(id = 1:n, x = rnorm(n))
right <- data.frame(id = (n+1):(2*n), x = rnorm(n))
result <- greedy_couples(left, right, vars = "x", strategy = "row_best")
expect_equal(result$info$n_matched, n)
})
# ------------------------------------------------------------------------------
# matching_diagnostics.R: block quality levels (lines 315, 317, 319, 321)
# These require blocked matching with different balance levels per block
# ------------------------------------------------------------------------------
test_that("balance_diagnostics computes block-level quality", {
set.seed(999)
n <- 90 # 30 per block
# Create blocks with different balance levels
left <- data.frame(
id = 1:n,
# Block A: excellent balance
# Block B: fair balance
# Block C: poor balance
x = c(
rnorm(30, mean = 0, sd = 1), # Block A left
rnorm(30, mean = 0.3, sd = 1), # Block B left
rnorm(30, mean = 0, sd = 1) # Block C left
),
block = rep(c("A", "B", "C"), each = 30)
)
right <- data.frame(
id = (n+1):(2*n),
x = c(
rnorm(30, mean = 0.05, sd = 1), # Block A right - similar
rnorm(30, mean = 0.6, sd = 1), # Block B right - medium diff
rnorm(30, mean = 1.0, sd = 1) # Block C right - large diff
),
block = rep(c("A", "B", "C"), each = 30)
)
# Create blocks
blocks <- matchmaker(left, right, block_type = "group", block_by = "block")
# Match
result <- match_couples(left, right, vars = "x", block_id = blocks$block_id)
# Get diagnostics
if (!is.null(result$pairs$block_id)) {
diag <- balance_diagnostics(result, left, right, vars = "x")
expect_s3_class(diag, "balance_diagnostics")
# Check that block_stats exists
if (!is.null(diag$block_stats)) {
expect_true(nrow(diag$block_stats) > 0)
}
}
})
# ------------------------------------------------------------------------------
# Additional matching_core.R paths
# ------------------------------------------------------------------------------
test_that("match_couples with auto_scale handles edge cases", {
set.seed(444)
n <- 20
left <- data.frame(id = 1:n, x = rnorm(n, sd = 100), y = rnorm(n, sd = 0.01))
right <- data.frame(id = (n+1):(2*n), x = rnorm(n, sd = 100), y = rnorm(n, sd = 0.01))
result <- match_couples(left, right, vars = c("x", "y"), auto_scale = TRUE)
expect_equal(result$info$n_matched, n)
})
test_that("match_couples with caliper constraint", {
set.seed(555)
n <- 20
left <- data.frame(id = 1:n, x = rnorm(n))
right <- data.frame(id = (n+1):(2*n), x = rnorm(n))
result <- match_couples(left, right, vars = "x", max_distance = 2.0)
expect_true(result$info$n_matched > 0)
})
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.