Nothing
# ==============================================================================
# Final push tests to maximize morph coverage
# ==============================================================================
# ------------------------------------------------------------------------------
# morph_pixel.R: mp4 output path (lines 394-414)
# ------------------------------------------------------------------------------
test_that("pixel_morph_animate saves mp4 when av available", {
skip_if_not_installed("magick")
skip_if_not_installed("av")
imgA <- system.file("extdata/icons/circleA_40.png", package = "couplr")
imgB <- system.file("extdata/icons/circleB_40.png", package = "couplr")
skip_if(imgA == "" || imgB == "")
outfile <- tempfile(fileext = ".mp4")
on.exit(unlink(outfile), add = TRUE)
result <- pixel_morph_animate(
imgA, imgB,
format = "mp4",
outfile = outfile,
n_frames = 3,
show = FALSE
)
expect_true(file.exists(outfile))
})
# ------------------------------------------------------------------------------
# morph_pixel.R: size warnings for exact mode (lines 224-234)
# ------------------------------------------------------------------------------
# Large exact mode warning tests skipped - they require large LAP computations
# that are too slow for automated testing. The warnings are tested via
# visual inspection during development.
# ------------------------------------------------------------------------------
# morph_pixel.R: size warnings for large tiles (lines 237-249)
# ------------------------------------------------------------------------------
test_that("pixel_morph_animate warns for large tiles", {
skip_if_not_installed("magick")
imgA <- system.file("extdata/icons/circleA_40.png", package = "couplr")
imgB <- system.file("extdata/icons/circleB_40.png", package = "couplr")
skip_if(imgA == "" || imgB == "")
expect_warning(
pixel_morph_animate(
imgA, imgB,
mode = "exact",
patch_size = 25, # 25x25 = 625 pixels per tile > 400
n_frames = 2,
show = FALSE
),
"Tile is large for LAP"
)
})
# ------------------------------------------------------------------------------
# morph_pixel.R: color_walk large image warning (lines 252-263)
# ------------------------------------------------------------------------------
# Large image color_walk test skipped - too slow for automated testing
# The warning threshold is 250000 pixels; we skip to avoid timeout
# ------------------------------------------------------------------------------
# morph_utils.R: .to_array_rgb error paths (lines 28, 55)
# These are hard to trigger through normal usage since magick always
# returns properly formatted data
# ------------------------------------------------------------------------------
# The error at line 28 requires magick to return non-3D data - very rare
# The error at line 55 requires unexpected dim ordering - also rare
# ------------------------------------------------------------------------------
# morph_utils.R: color walk pipeline - remaining A pixels path (lines 454-476)
# ------------------------------------------------------------------------------
test_that("morph_utils color walk handles remaining pixels", {
H <- 6
W <- 6
N <- H * W
# Create images where color groups don't perfectly align
set.seed(999)
A_planar <- sample(0:255, N * 3, replace = TRUE)
B_planar <- sample(0:255, N * 3, replace = TRUE)
result <- couplr:::.solve_color_walk_pipeline(
A_planar, B_planar, H, W,
quantize_bits = 2, # Very few colors = large groups
method = "jv",
maximize = FALSE
)
expect_equal(length(result), N)
# Should be a valid assignment
expect_true(all(result >= 1 & result <= N))
})
# ------------------------------------------------------------------------------
# morph_pixel.R: .solve_color_walk_pipeline remaining pixels (lines 1211-1218)
# ------------------------------------------------------------------------------
test_that("morph_pixel color walk handles sparse groups", {
H <- 8
W <- 8
N <- H * W
# Create images with very different colors to force remaining pixel handling
set.seed(42)
A_planar <- c(
sample(c(0, 128, 255), N, replace = TRUE), # R
sample(c(0, 128, 255), N, replace = TRUE), # G
sample(c(0, 128, 255), N, replace = TRUE) # B
)
B_planar <- c(
sample(c(32, 160, 224), N, replace = TRUE), # Different R range
sample(c(32, 160, 224), N, replace = TRUE), # Different G range
sample(c(32, 160, 224), N, replace = TRUE) # Different B range
)
result <- couplr:::.solve_color_walk_pipeline(
A_planar, B_planar, H, W,
quantize_bits = 4,
method = "jv",
maximize = FALSE
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# morph_tiling.R: .recursive_tiling_solver rest width/height (lines 1128-1162)
# ------------------------------------------------------------------------------
test_that(".recursive_tiling_solver handles images with odd dimensions", {
# 7x5 has rest_w=1 and rest_h=1 when divided by 2
H <- 5
W <- 7
N <- H * W
set.seed(123)
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 = 2,
alpha = 1, beta = 0.1
)
expect_equal(length(result), N)
# Should cover all pixels
expect_true(all(result >= 1 & result <= N))
})
test_that(".recursive_tiling_solver handles both rest_w and rest_h > 0", {
# 9x9 has rest_w=1 and rest_h=1 for 2x2 tiling
H <- 9
W <- 9
N <- H * W
set.seed(456)
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 = 2,
alpha = 0.5, beta = 0.5
)
expect_equal(length(result), N)
})
# ------------------------------------------------------------------------------
# morph_utils.R: .patch_cost_matrix with multiple patches (lines 261-275)
# ------------------------------------------------------------------------------
test_that(".patch_cost_matrix handles multiple patches", {
patches_a <- list(
colors = matrix(c(
100, 100, 100,
200, 50, 50,
50, 200, 50
), nrow = 3, ncol = 3, byrow = TRUE),
centers = matrix(c(
0, 0,
10, 0,
5, 10
), nrow = 3, ncol = 2, byrow = TRUE)
)
patches_b <- list(
colors = matrix(c(
105, 95, 100,
190, 60, 45,
55, 210, 55
), nrow = 3, ncol = 3, byrow = TRUE),
centers = matrix(c(
2, 1,
8, 2,
6, 9
), nrow = 3, ncol = 2, byrow = TRUE)
)
result <- couplr:::.patch_cost_matrix(patches_a, patches_b, alpha = 1, beta = 0.2, H = 20, W = 20)
expect_equal(dim(result), c(3, 3))
expect_true(all(is.finite(result)))
})
# ------------------------------------------------------------------------------
# morph_utils.R: .expand_patch_assignment with multiple patches (lines 280-291)
# ------------------------------------------------------------------------------
test_that(".expand_patch_assignment handles multiple patches", {
patch_assign <- list(2L, 1L, 3L) # Patch 1->B2, Patch 2->B1, Patch 3->B3
patches_a <- list(
indices = list(c(1L, 2L), c(3L, 4L), c(5L, 6L))
)
patches_b <- list(
indices = list(c(7L, 8L), c(9L, 10L), c(11L, 12L))
)
result <- couplr:::.expand_patch_assignment(patch_assign, patches_a, patches_b, N = 6)
expect_equal(length(result), 6)
# Patch 1 maps to B patch 2
expect_equal(result[1], 9L)
expect_equal(result[2], 10L)
# Patch 2 maps to B patch 1
expect_equal(result[3], 7L)
expect_equal(result[4], 8L)
})
# ------------------------------------------------------------------------------
# morph_tiling.R: .generate_square_tiles boundary conditions
# ------------------------------------------------------------------------------
test_that(".generate_square_tiles handles exact division", {
# 6x6 with P=2 divides exactly
tiles <- couplr:::.generate_square_tiles(W = 6, H = 6, P = 2)
# Should have 9 tiles of size 2
expect_equal(length(tiles), 9)
expect_true(all(sapply(tiles, function(t) t$size) == 2))
})
test_that(".generate_square_tiles handles P > both dimensions", {
tiles <- couplr:::.generate_square_tiles(W = 2, H = 3, P = 5)
# Should fill with smaller tiles
covered <- matrix(FALSE, 3, 2)
for (tile in tiles) {
for (dx in 0:(tile$size - 1)) {
for (dy in 0:(tile$size - 1)) {
covered[tile$y0 + dy + 1, tile$x0 + dx + 1] <- TRUE
}
}
}
expect_true(all(covered))
})
# ------------------------------------------------------------------------------
# morph_pixel.R: pixel_morph with downscale (lines 707-718)
# ------------------------------------------------------------------------------
test_that("pixel_morph works with downscale_steps", {
skip_if_not_installed("magick")
imgA <- system.file("extdata/icons/circleA_40.png", package = "couplr")
imgB <- system.file("extdata/icons/circleB_40.png", package = "couplr")
skip_if(imgA == "" || imgB == "")
result <- pixel_morph(
imgA, imgB,
downscale_steps = 1,
n_frames = 2,
show = FALSE
)
expect_s3_class(result, "magick-image")
})
# ------------------------------------------------------------------------------
# morph_pixel.R: fractional upscale path (lines 365-371, 757-763)
# ------------------------------------------------------------------------------
test_that("pixel_morph applies fractional upscale correctly", {
skip_if_not_installed("magick")
imgA <- system.file("extdata/icons/circleA_40.png", package = "couplr")
imgB <- system.file("extdata/icons/circleB_40.png", package = "couplr")
skip_if(imgA == "" || imgB == "")
result <- pixel_morph(
imgA, imgB,
upscale = 1.5, # Non-integer
n_frames = 2,
show = FALSE
)
info <- magick::image_info(result)
# 40 * 1.5 = 60
expect_equal(info$width, 60)
expect_equal(info$height, 60)
})
# ------------------------------------------------------------------------------
# morph_pixel.R: GIF format save (lines 419-420)
# ------------------------------------------------------------------------------
test_that("pixel_morph_animate saves GIF correctly", {
skip_if_not_installed("magick")
imgA <- system.file("extdata/icons/circleA_40.png", package = "couplr")
imgB <- system.file("extdata/icons/circleB_40.png", package = "couplr")
skip_if(imgA == "" || imgB == "")
outfile <- tempfile(fileext = ".gif")
on.exit(unlink(outfile), add = TRUE)
result <- pixel_morph_animate(
imgA, imgB,
format = "gif",
outfile = outfile,
n_frames = 2,
show = FALSE
)
expect_true(file.exists(outfile))
expect_true(file.size(outfile) > 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.