# Helpers ------------------------------------------------------------------ vv_chr <- function() vecvec(letters) vv_dbl <- function() vecvec(as.double(1:26)) vv_int <- function() vecvec(1:26) vv_date <- function() vecvec(Sys.Date() + 0:25) vv_mix <- function() vecvec(letters, as.double(1:26), 1:26, Sys.Date() + 0:25) # dim<- / array construction ----------------------------------------------- test_that("dim<- sets dim attribute on vecvec", { x <- vv_chr() dim(x) <- c(2L, 13L) expect_equal(dim(x), c(2L, 13L)) expect_true(is_vecvec(x)) }) test_that("array() wraps a single-type vecvec preserving class and dim", { x <- array(vv_int(), dim = c(2L, 13L)) expect_equal(dim(x), c(2L, 13L)) expect_true(is_vecvec(x)) }) test_that("array() wraps a mixed vecvec into a 2D array", { x <- array(vv_mix(), dim = c(8L, 13L)) expect_equal(dim(x), c(8L, 13L)) expect_true(is_vecvec(x)) }) test_that("array() wraps a mixed vecvec into a 3D array", { x <- array(vv_mix(), dim = c(8L, 3L, 4L)) expect_equal(dim(x), c(8L, 3L, 4L)) expect_true(is_vecvec(x)) }) test_that("dim<- round-trips: setting then reading dim is consistent", { x <- vv_dbl() dim(x) <- c(2L, 13L) expect_equal(dim(x), c(2L, 13L)) dim(x) <- NULL expect_null(dim(x)) }) test_that("length is unchanged after dim<- assignment", { x <- vv_chr() dim(x) <- c(2L, 13L) expect_equal(length(x), 26L) }) test_that("is_vecvec is TRUE for dim-annotated vecvec", { x <- vv_mix() dim(x) <- c(8L, 13L) expect_true(is_vecvec(x)) }) test_that("dim<- with a single dimension (vector form) is valid", { x <- vv_int() dim(x) <- 26L expect_equal(dim(x), 26L) expect_true(is_vecvec(x)) }) # dimnames<- --------------------------------------------------------------- test_that("dimnames<- assigns row and column names", { x <- array(vv_int(), dim = c(2L, 13L)) rn <- paste0("r", 1:2) cn <- paste0("c", 1:13) dimnames(x) <- list(rn, cn) expect_equal(dimnames(x), list(rn, cn)) }) test_that("dimnames<- with NULL clears names", { x <- array(vv_int(), dim = c(2L, 13L)) dimnames(x) <- list(paste0("r", 1:2), paste0("c", 1:13)) dimnames(x) <- NULL expect_null(dimnames(x)) }) test_that("dimnames<- preserves vecvec class and length", { x <- array(vv_int(), dim = c(2L, 13L)) dimnames(x) <- list(paste0("r", 1:2), paste0("c", 1:13)) expect_true(is_vecvec(x)) expect_equal(length(x), 26L) }) test_that("dimnames<- works for 3D array", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) dn <- list( paste0("r", 1:2), paste0("c", 1:3), paste0("z", 1:4) ) dimnames(x) <- dn expect_equal(dimnames(x), dn) expect_true(is_vecvec(x)) }) # as.matrix ---------------------------------------------------------------- test_that("as.matrix on a character vecvec gives a column matrix", { m <- as.matrix(vv_chr()) expect_true(is_vecvec(m)) expect_equal(dim(m), c(26L, 1L)) }) test_that("as.matrix on a double vecvec gives a column matrix", { m <- as.matrix(vv_dbl()) expect_true(is_vecvec(m)) expect_equal(dim(m), c(26L, 1L)) }) test_that("as.matrix preserves element values via [[", { m <- as.matrix(vv_chr()) expect_equal(m[[1L]], "a") expect_equal(m[[26L]], "z") }) test_that("as.matrix on a mixed vecvec produces correct dim", { m <- as.matrix(vv_mix()) expect_true(is_vecvec(m)) expect_equal(dim(m), c(104L, 1L)) }) test_that("as.matrix preserves Date elements via [[", { m <- as.matrix(vv_date()) expect_s3_class(m[[1L]], "Date") }) # t (transpose) ------------------------------------------------------------ test_that("t() transposes a column matrix to a row matrix", { m <- as.matrix(vv_chr()) mt <- t(m) expect_equal(dim(mt), c(1L, 26L)) expect_true(is_vecvec(mt)) }) test_that("t() on a 2-row integer matrix transposes dim correctly", { x <- array(vv_int(), dim = c(2L, 13L)) xt <- t(x) expect_equal(dim(xt), c(13L, 2L)) expect_true(is_vecvec(xt)) }) test_that("t() preserves element values in transposed positions (via format)", { x <- array(vv_int(), dim = c(2L, 13L)) xt <- t(x) f <- format(xt) # column-major: original [1,1]=1, [2,1]=2; after t: [1,1]=1, [1,2]=2 expect_equal(trimws(f[1L, 1L]), "1") expect_equal(trimws(f[1L, 2L]), "2") expect_equal(trimws(f[2L, 1L]), "3") }) test_that("t(t(x)) round-trips dim to original", { x <- array(vv_int(), dim = c(2L, 13L)) expect_equal(dim(t(t(x))), dim(x)) }) # flat [[]] indexing on dim-annotated vecvec -------------------------------- test_that("[[i]] on a dim-annotated single-type vecvec returns scalar", { x <- array(vv_int(), dim = c(2L, 13L)) expect_equal(x[[1L]], 1L) expect_equal(x[[26L]], 26L) }) test_that("[[i]] on a dim-annotated mixed vecvec returns correct type", { x <- array(vv_mix(), dim = c(8L, 13L)) expect_equal(x[[1L]], "a") expect_equal(x[[26L]], "z") expect_equal(x[[27L]], 1) # first double expect_s3_class(x[[79L]], "Date") # first Date }) test_that("[[i]] on a 1x1 array returns the single element", { x <- array(vecvec(42L), dim = c(1L, 1L)) expect_equal(x[[1L]], 42L) }) # [i] flat indexing preserves class and dim -------------------------------- # [, j] column subset (note: [i, ] and [i, j] currently error) ----------- test_that("[, j] on a dim-annotated vecvec returns a vecvec", { x <- array(vv_int(), dim = c(2L, 13L)) col1 <- x[, 1L] expect_true(is_vecvec(col1)) }) test_that("[i, ] on a dim-annotated vecvec returns the correct row as a vecvec", { x <- array(vv_int(), dim = c(2L, 13L)) row1 <- x[1L, ] expect_true(is_vecvec(row1)) expect_equal(as.integer(row1), seq(1L, 25L, by = 2L)) }) test_that("[i, j] on a dim-annotated vecvec returns the correct scalar element", { x <- array(vv_int(), dim = c(2L, 13L)) expect_equal(x[1L, 1L], vecvec(1L)) expect_equal(x[2L, 1L], vecvec(2L)) expect_equal(x[1L, 2L], vecvec(3L)) }) # format ------------------------------------------------------------------- test_that("format() on a 2D dim-annotated vecvec returns a character matrix", { x <- array(vv_int(), dim = c(2L, 13L)) f <- format(x) expect_true(is.character(f)) expect_equal(dim(f), c(2L, 13L)) }) test_that("format() on 3D mixed vecvec array returns a character array", { x <- array(vv_mix(), dim = c(8L, 3L, 4L)) f <- format(x) expect_true(is.character(f)) expect_equal(dim(f), c(8L, 3L, 4L)) }) test_that("format() values match underlying elements (character slot)", { x <- array(vv_chr(), dim = c(2L, 13L)) f <- format(x) expect_equal(trimws(f[1L, 1L]), "a") expect_equal(trimws(f[2L, 1L]), "b") expect_equal(trimws(f[1L, 2L]), "c") }) # as.vector ---------------------------------------------------------------- test_that("as.vector on a dim-annotated vecvec retains the dim attribute", { # Current behaviour: as.vector is identity for vecvec (dim preserved) x <- array(vv_chr(), dim = c(2L, 13L)) v <- as.vector(x) expect_true(is_vecvec(v)) expect_equal(length(v), 26L) }) # as.character / as.double / as.integer coercion -------------------------- test_that("as.character on a dim-annotated character vecvec returns letters", { x <- array(vv_chr(), dim = c(2L, 13L)) ch <- as.character(x) expect_equal(ch, letters) }) test_that("as.integer on a dim-annotated integer vecvec returns 1:26", { x <- array(vv_int(), dim = c(2L, 13L)) expect_equal(as.integer(x), 1:26) }) test_that("as.double on a dim-annotated double vecvec returns correct values", { x <- array(vv_dbl(), dim = c(2L, 13L)) expect_equal(as.double(x), as.double(1:26)) }) # [i, j, ...] replacement ------------------------------------------------- test_that("[i, j]<- replaces a single element in a 2D integer vecvec", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, 1L] <- 99L expect_equal(x[[1L]], 99L) }) test_that("[i, j]<- replaces an element that is not the first, in a 2D integer vecvec", { x <- array(vv_int(), dim = c(2L, 13L)) x[2L, 1L] <- 99L expect_equal(x[[2L]], 99L) }) test_that("[i, j]<- preserves surrounding elements in a 2D array", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, 1L] <- 99L expect_equal(x[[2L]], 2L) expect_equal(x[[3L]], 3L) }) test_that("[i, j]<- preserves dim after replacement", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, 2L] <- 99L expect_equal(dim(x), c(2L, 13L)) }) test_that("[i, j]<- preserves vecvec class after replacement", { x <- array(vv_int(), dim = c(2L, 13L)) x[2L, 3L] <- 99L expect_true(is_vecvec(x)) }) test_that("[i, j]<- preserves length after replacement", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, 1L] <- 99L expect_equal(length(x), 26L) }) test_that("[, j]<- replaces an entire column in a 2D array", { x <- array(vv_int(), dim = c(2L, 13L)) x[, 1L] <- c(91L, 92L) expect_equal(x[[1L]], 91L) expect_equal(x[[2L]], 92L) expect_equal(x[[3L]], 3L) # column 2, row 1 unchanged }) test_that("[i, ]<- replaces an entire row in a 2D array", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, ] <- 0L # row 1: positions 1, 3, 5, ... (odd flat indices) expect_equal(x[[1L]], 0L) expect_equal(x[[3L]], 0L) expect_equal(x[[2L]], 2L) # row 2, col 1 unchanged }) test_that("[i, j]<- can replace with a different type (character into integer vecvec)", { x <- array(vv_int(), dim = c(2L, 13L)) x[1L, 1L] <- "hello" expect_equal(x[[1L]], "hello") expect_equal(x[[2L]], 2L) }) test_that("[i, j]<- can replace with a Date value", { x <- array(vv_int(), dim = c(2L, 13L)) d <- Sys.Date() x[1L, 1L] <- d expect_s3_class(x[[1L]], "Date") expect_equal(x[[1L]], d) }) test_that("[i, j]<- works on a 2D mixed vecvec", { x <- array(vv_mix(), dim = c(8L, 13L)) x[1L, 1L] <- 999L expect_equal(x[[1L]], 999L) expect_equal(dim(x), c(8L, 13L)) expect_true(is_vecvec(x)) }) test_that("[i, j, k]<- replaces a single element in a 3D integer vecvec", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) x[1L, 1L, 1L] <- 99L expect_equal(x[[1L]], 99L) }) test_that("[i, j, k]<- replaces an element not at position 1 in a 3D array", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) # flat index for [2,3,4] in column-major: 2 + (3-1)*2 + (4-1)*6 = 2+4+18 = 24 x[2L, 3L, 4L] <- 99L expect_equal(x[[24L]], 99L) }) test_that("[i, j, k]<- preserves dim after replacement in a 3D array", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) x[1L, 2L, 3L] <- 99L expect_equal(dim(x), c(2L, 3L, 4L)) }) test_that("[i, j, k]<- preserves vecvec class and length in a 3D array", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) x[2L, 2L, 2L] <- 0L expect_true(is_vecvec(x)) expect_equal(length(x), 24L) }) test_that("[i, j, k]<- preserves surrounding elements in a 3D array", { x <- array(vv_int(), dim = c(2L, 3L, 4L)) x[1L, 1L, 1L] <- 99L expect_equal(x[[2L]], 2L) expect_equal(x[[3L]], 3L) }) test_that("[i, j, k]<- works on a 3D mixed vecvec", { x <- array(vv_mix(), dim = c(8L, 3L, 4L)) x[1L, 1L, 1L] <- "replaced" expect_equal(x[[1L]], "replaced") expect_equal(dim(x), c(8L, 3L, 4L)) expect_true(is_vecvec(x)) }) test_that("[i]<- on a 1D dim-annotated vecvec replaces the element and preserves dim", { x <- vv_int() dim(x) <- 26L x[3L] <- 99L expect_equal(x[[3L]], 99L) expect_equal(dim(x), 26L) expect_true(is_vecvec(x)) }) # Edge cases --------------------------------------------------------------- test_that("zero-length vecvec with dim c(0, 0) is valid", { x <- vecvec() dim(x) <- c(0L, 0L) expect_equal(dim(x), c(0L, 0L)) expect_equal(length(x), 0L) expect_true(is_vecvec(x)) }) test_that("1x1 array of vecvec has correct dim and element", { x <- array(vecvec(42L), dim = c(1L, 1L)) expect_equal(dim(x), c(1L, 1L)) expect_true(is_vecvec(x)) expect_equal(x[[1L]], 42L) }) test_that("3D array of mixed vecvec: Date elements accessible via [[", { x <- array(vv_mix(), dim = c(8L, 3L, 4L)) # vv_mix: 26 chars + 26 doubles + 26 ints + 26 dates = 104 source elements; # array dim is 8×3×4 = 96 slots, so Date slot (starts at index 79) fills positions 79–96. expect_s3_class(x[[79L]], "Date") expect_s3_class(x[[96L]], "Date") })