# Tests for NIfTI extension support test_that("NiftiExtension constructor works correctly", { # Test with character data ext <- NiftiExtension(ecode = 6L, data = "test comment") expect_s4_class(ext, "NiftiExtension") expect_equal(ext@ecode, 6L) expect_true(ext@esize >= 16) expect_equal(ext@esize %% 16, 0) # Must be multiple of 16 # Test with raw data raw_data <- charToRaw("raw test") ext2 <- NiftiExtension(ecode = 6L, data = raw_data) expect_s4_class(ext2, "NiftiExtension") }) test_that("NiftiExtension padding is correct", { # Test various string lengths to verify padding for (len in c(1, 5, 10, 15, 20, 30)) { data <- paste(rep("x", len), collapse = "") ext <- NiftiExtension(ecode = 6L, data = data) expect_equal(ext@esize %% 16, 0, info = paste("Length", len)) expect_equal(length(ext@edata), ext@esize - 8L) } }) test_that("NiftiExtensionList works correctly", { # Empty list ext_list <- new("NiftiExtensionList") expect_s4_class(ext_list, "NiftiExtensionList") expect_equal(length(ext_list), 0) # List with extensions ext1 <- NiftiExtension(ecode = 6L, data = "comment 1") ext2 <- NiftiExtension(ecode = 6L, data = "comment 2") ext_list <- new("NiftiExtensionList", list(ext1, ext2)) expect_equal(length(ext_list), 2) }) test_that("NiftiExtensionList validation works", { # Should fail with non-NiftiExtension objects expect_error( new("NiftiExtensionList", list("not an extension")), "NiftiExtension" ) }) test_that("ecode_name returns correct names", { expect_equal(ecode_name(4L), "AFNI") expect_equal(ecode_name(6L), "comment") expect_equal(ecode_name(32L), "CIFTI") expect_equal(ecode_name(999L), "unknown") }) test_that("parse_extension works for comments", { ext <- NiftiExtension(ecode = 6L, data = "This is a test") parsed <- parse_extension(ext) expect_equal(parsed, "This is a test") }) test_that("parse_extension works for AFNI XML", { afni_xml <- '' ext <- NiftiExtension(ecode = 4L, data = afni_xml) parsed <- parse_extension(ext) if (requireNamespace("xml2", quietly = TRUE)) { expect_s3_class(parsed, "xml_document") } else { expect_type(parsed, "character") } }) test_that("total_extension_size calculates correctly", { # Empty list: just extender (4 bytes) expect_equal(neuroim2:::total_extension_size(NULL), 4L) expect_equal(neuroim2:::total_extension_size(new("NiftiExtensionList")), 4L) # With extensions ext1 <- NiftiExtension(ecode = 6L, data = "test") ext_list <- new("NiftiExtensionList", list(ext1)) expected_size <- 4L + ext1@esize expect_equal(neuroim2:::total_extension_size(ext_list), expected_size) }) test_that("extension method filters by ecode", { ext1 <- NiftiExtension(ecode = 6L, data = "comment") ext2 <- NiftiExtension(ecode = 4L, data = "") ext3 <- NiftiExtension(ecode = 6L, data = "another comment") ext_list <- new("NiftiExtensionList", list(ext1, ext2, ext3)) # Filter for comments comments <- extension(ext_list, 6L) expect_equal(length(comments), 2) # Filter for AFNI afni <- extension(ext_list, 4L) expect_equal(length(afni), 1) # Filter for non-existent none <- extension(ext_list, 999L) expect_equal(length(none), 0) }) test_that("has_extensions works correctly", { # Empty list ext_list <- new("NiftiExtensionList") expect_false(has_extensions(ext_list)) # Non-empty list ext <- NiftiExtension(ecode = 6L, data = "test") ext_list <- new("NiftiExtensionList", list(ext)) expect_true(has_extensions(ext_list)) # List with extensions field header <- list(extensions = ext_list) expect_true(has_extensions(header)) # List without extensions header <- list(other = "data") expect_false(has_extensions(header)) }) test_that("as_nifti_header includes extensions correctly", { # Create a simple volume vol_data <- array(rnorm(8 * 8 * 8), dim = c(8, 8, 8)) space <- NeuroSpace(dim = c(8L, 8L, 8L), origin = c(0, 0, 0), spacing = c(1, 1, 1)) vol <- DenseNeuroVol(vol_data, space) # Without extensions hdr1 <- as_nifti_header(vol, file_name = "test.nii") expect_equal(hdr1$vox_offset, 352) # 348 + 4 byte extender expect_equal(length(hdr1$extensions), 0) # With extensions ext <- NiftiExtension(ecode = 6L, data = "test") ext_list <- new("NiftiExtensionList", list(ext)) hdr2 <- as_nifti_header(vol, file_name = "test.nii", extensions = ext_list) expect_gt(hdr2$vox_offset, 352) expect_equal(length(hdr2$extensions), 1) expect_equal(hdr2$vox_offset, 348 + neuroim2:::total_extension_size(ext_list)) }) test_that("extensions round-trip through file I/O", { skip_on_cran() # Create volume vol_data <- array(rnorm(4 * 4 * 4), dim = c(4, 4, 4)) space <- NeuroSpace(dim = c(4L, 4L, 4L), origin = c(0, 0, 0), spacing = c(1, 1, 1)) vol <- DenseNeuroVol(vol_data, space) # Create extensions ext1 <- NiftiExtension(ecode = 6L, data = "Round trip test") ext2 <- NiftiExtension(ecode = 6L, data = "Second extension") ext_list <- new("NiftiExtensionList", list(ext1, ext2)) # Create header with extensions tmp_file <- tempfile(fileext = ".nii") hdr <- as_nifti_header(vol, file_name = tmp_file, extensions = ext_list) # Write file conn <- file(tmp_file, open = "wb") write_nifti_header(hdr, conn, close = FALSE) writer <- BinaryWriter(conn, hdr$vox_offset, "FLOAT", 4L, .Platform$endian) write_elements(writer, as.numeric(vol)) close(writer) # Read back hdr_read <- read_nifti_header(tmp_file) # Verify extensions expect_equal(length(hdr_read$extensions), 2) expect_equal(hdr_read$extensions[[1]]@ecode, 6L) expect_equal(hdr_read$extensions[[2]]@ecode, 6L) # Parse and verify content content1 <- parse_extension(hdr_read$extensions[[1]]) content2 <- parse_extension(hdr_read$extensions[[2]]) expect_equal(content1, "Round trip test") expect_equal(content2, "Second extension") # Clean up unlink(tmp_file) }) test_that("AFNI extension attributes can be extracted", { skip_if_not_installed("xml2") afni_xml <- paste0( '', '', 'Test history', 'Vol1~Vol2', '' ) ext <- NiftiExtension(ecode = 4L, data = afni_xml) # List attributes attrs <- list_afni_attributes(ext) expect_true("HISTORY_NOTE" %in% attrs) expect_true("BRICK_LABS" %in% attrs) # Get specific attribute history <- get_afni_attribute(ext, "HISTORY_NOTE") expect_equal(trimws(history), "Test history") }) test_that("NiftiExtensionCodes contains expected codes", { expect_true("AFNI" %in% names(NiftiExtensionCodes)) expect_true("comment" %in% names(NiftiExtensionCodes)) expect_true("CIFTI" %in% names(NiftiExtensionCodes)) expect_true("DICOM" %in% names(NiftiExtensionCodes)) expect_equal(NiftiExtensionCodes["AFNI"], c(AFNI = 4L)) expect_equal(NiftiExtensionCodes["comment"], c(comment = 6L)) })