tests/testthat/test-parquet-backend.R

test_that("DataBackend is abstract and cannot be instantiated directly", {
  backend <- DataBackend$new()

  # Should throw errors for unimplemented methods
  expect_error(backend$get_matrix(1))
  expect_error(backend$get_all_matrices())
  expect_error(backend$length())
  expect_error(backend$get_dimensions())
})

test_that("ListBackend initializes correctly with valid matrices", {
  # Create test matrices
  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 3) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  backend <- ListBackend$new(mats)

  expect_s3_class(backend, "ListBackend")
  expect_equal(backend$length(), 3)
  expect_equal(backend$get_dimensions(), 3)
})

test_that("ListBackend validates input matrices", {
  # Non-list input
  expect_error(ListBackend$new(matrix(1:9, 3, 3)), "matrices must be a list")

  # Empty list
  expect_error(ListBackend$new(list()), "matrices list cannot be empty")

  # Non-dppMatrix objects
  mats <- list(matrix(1:9, 3, 3), matrix(1:9, 3, 3))
  expect_error(ListBackend$new(mats), "All matrices must be dppMatrix objects")
})

test_that("ListBackend get_matrix retrieves correct matrix", {
  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 3) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  backend <- ListBackend$new(mats)

  mat1 <- backend$get_matrix(1)
  expect_s4_class(mat1, "dppMatrix")
  expect_equal(as.vector(mat1@x), as.vector(mats[[1]]@x))

  mat2 <- backend$get_matrix(2)
  expect_equal(as.vector(mat2@x), as.vector(mats[[2]]@x))
})

test_that("ListBackend get_matrix validates index bounds", {
  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  backend <- ListBackend$new(mats)

  expect_error(backend$get_matrix(0), "Index .* out of bounds")
  expect_error(backend$get_matrix(3), "Index .* out of bounds")
  expect_error(backend$get_matrix(-1), "Index .* out of bounds")
})

test_that("ListBackend get_all_matrices returns all matrices", {
  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  backend <- ListBackend$new(mats)
  all_mats <- backend$get_all_matrices()

  expect_equal(length(all_mats), 2)
  expect_s4_class(all_mats[[1]], "dppMatrix")
  expect_s4_class(all_mats[[2]], "dppMatrix")
})

test_that("ParquetBackend initializes with valid directory", {
  skip_if_not_installed("arrow")

  # Create temporary directory with test data
  temp_dir <- tempfile()
  dir.create(temp_dir)

  # Create test matrices and write to Parquet
  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  write_connectomes_to_parquet(mats, temp_dir, overwrite = TRUE)

  # Initialize backend
  backend <- ParquetBackend$new(temp_dir, cache_size = 5)

  expect_s3_class(backend, "ParquetBackend")
  expect_equal(backend$length(), 2)
  expect_equal(backend$get_dimensions(), 3)

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend validates directory exists", {
  expect_error(ParquetBackend$new("/nonexistent/directory"), "Data directory does not exist")
})

test_that("ParquetBackend validates metadata.json exists", {
  skip_if_not_installed("arrow")

  # Create directory without metadata
  temp_dir <- tempfile()
  dir.create(temp_dir)

  expect_error(ParquetBackend$new(temp_dir), "Metadata file not found")

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend get_matrix loads from disk", {
  skip_if_not_installed("arrow")

  temp_dir <- tempfile()
  dir.create(temp_dir)

  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  write_connectomes_to_parquet(mats, temp_dir, overwrite = TRUE)
  backend <- ParquetBackend$new(temp_dir)

  mat1 <- backend$get_matrix(1)
  expect_s4_class(mat1, "dppMatrix")
  expect_equal(nrow(mat1), 3)

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend caches recently accessed matrices", {
  skip_if_not_installed("arrow")

  temp_dir <- tempfile()
  dir.create(temp_dir)

  mats <- replicate(5, diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(), simplify = FALSE)
  write_connectomes_to_parquet(mats, temp_dir, overwrite = TRUE)

  backend <- ParquetBackend$new(temp_dir, cache_size = 2)

  # Access first matrix
  mat1 <- backend$get_matrix(1)
  expect_equal(backend$get_cache_size(), 1)

  # Access second matrix
  mat2 <- backend$get_matrix(2)
  expect_equal(backend$get_cache_size(), 2)

  # Access third matrix (should evict first)
  mat3 <- backend$get_matrix(3)
  expect_equal(backend$get_cache_size(), 2)

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend clear_cache empties the cache", {
  skip_if_not_installed("arrow")

  temp_dir <- tempfile()
  dir.create(temp_dir)

  mats <- replicate(3, diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(), simplify = FALSE)
  write_connectomes_to_parquet(mats, temp_dir, overwrite = TRUE)

  backend <- ParquetBackend$new(temp_dir)

  # Load some matrices
  backend$get_matrix(1)
  backend$get_matrix(2)
  expect_gt(backend$get_cache_size(), 0)

  # Clear cache
  backend$clear_cache()
  expect_equal(backend$get_cache_size(), 0)

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend get_all_matrices loads all matrices", {
  skip_if_not_installed("arrow")

  temp_dir <- tempfile()
  dir.create(temp_dir)

  mats <- list(
    diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 2) |> Matrix::nearPD() |> _$mat |> Matrix::pack(),
    (diag(3) * 3) |> Matrix::nearPD() |> _$mat |> Matrix::pack()
  )

  write_connectomes_to_parquet(mats, temp_dir, overwrite = TRUE)
  backend <- ParquetBackend$new(temp_dir)

  all_mats <- backend$get_all_matrices()

  expect_equal(length(all_mats), 3)
  expect_true(all(sapply(all_mats, inherits, "dppMatrix")))

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

test_that("ParquetBackend get_metadata returns metadata", {
  skip_if_not_installed("arrow")

  temp_dir <- tempfile()
  dir.create(temp_dir)

  mats <- list(diag(3) |> Matrix::nearPD() |> _$mat |> Matrix::pack())
  write_connectomes_to_parquet(
    mats, temp_dir,
    subject_ids = "subj_1",
    provenance = list(study = "test"),
    overwrite = TRUE
  )

  backend <- ParquetBackend$new(temp_dir)
  metadata <- backend$get_metadata()

  expect_equal(metadata$n_matrices, 1)
  expect_equal(metadata$matrix_dim, 3)
  expect_equal(metadata$subject_ids, "subj_1")
  expect_equal(metadata$provenance$study, "test")

  # Clean up
  unlink(temp_dir, recursive = TRUE)
})

Try the riemtan package in your browser

Any scripts or data that you put into this service are public.

riemtan documentation built on Nov. 11, 2025, 1:06 a.m.