tests/testthat/test-hdf5_utils.R

# test-hdf5_utils.R
# Direct unit tests for HDF5 wrapper functions in hdf5_utils.R

test_that(".hdf5_backend returns a valid backend string", {
  backend <- NEONiso:::.hdf5_backend()
  expect_true(backend %in% c("hdf5r", "rhdf5"))
})

test_that("h5_create_file creates a new HDF5 file and returns a handle", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)
  expect_true(file.exists(tmp))

  # Clean up handle
  NEONiso:::h5_close(fid)
})

test_that("h5_create_file overwrites an existing file", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  # Create file, add a group, close
  fid <- NEONiso:::h5_create_file(tmp)
  NEONiso:::h5_create_group(fid, "testgroup")
  NEONiso:::h5_close(fid)

  # Recreate - should start fresh
  # rhdf5 warns about concurrent file handles; suppress since this is expected
  suppressWarnings({
    fid2 <- NEONiso:::h5_create_file(tmp)
    contents <- NEONiso:::h5_ls(tmp)
  })
  # Fresh file should have no groups
  expect_equal(nrow(contents), 0)
  NEONiso:::h5_close(fid2)
})

test_that("h5_create_group and h5_open_group work", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)

  # Create nested groups
  grp <- NEONiso:::h5_create_group(fid, "level1")
  NEONiso:::h5_close_group(grp)
  grp2 <- NEONiso:::h5_create_group(fid, "level1/level2")
  NEONiso:::h5_close_group(grp2)

  # Open and verify
  grp_opened <- NEONiso:::h5_open_group(fid, "level1")
  # Should not error

  NEONiso:::h5_close_group(grp_opened)
  NEONiso:::h5_close(fid)

  # Verify with h5_ls
  contents <- NEONiso:::h5_ls(tmp)
  expect_true("level1" %in% contents$name)
})

test_that("h5_write_attr and h5_read_attrs round-trip correctly", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)
  grp <- NEONiso:::h5_create_group(fid, "mygroup")

  # Write attributes
  NEONiso:::h5_write_attr(grp, "site", "ONAQ")
  NEONiso:::h5_write_attr(grp, "nheights", 4L)
  NEONiso:::h5_write_attr(grp, "pi_value", 3.14159)

  NEONiso:::h5_close_group(grp)
  NEONiso:::h5_close(fid)

  # Read back
  attrs <- NEONiso:::h5_read_attrs(tmp, "mygroup")
  expect_type(attrs, "list")
  expect_true("site" %in% names(attrs))
  expect_true("nheights" %in% names(attrs))
  expect_true("pi_value" %in% names(attrs))
  # rhdf5 returns attributes as arrays with dim=1, so ignore_attr = TRUE
  expect_equal(attrs$site, "ONAQ", ignore_attr = TRUE)
  expect_equal(attrs$nheights, 4L, ignore_attr = TRUE)
  expect_equal(attrs$pi_value, 3.14159, tolerance = 1e-5, ignore_attr = TRUE)
})

test_that("h5_write_dataset writes data.frames correctly", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)
  grp <- NEONiso:::h5_create_group(fid, "data")

  # Write a data.frame
  df <- data.frame(
    timeBgn = c("2019-05-01T00:00:00.000Z", "2019-05-01T00:09:00.000Z"),
    timeEnd = c("2019-05-01T00:09:00.000Z", "2019-05-01T00:18:00.000Z"),
    mean = c(410.5, 412.3),
    vari = c(0.1, 0.2),
    stringsAsFactors = FALSE
  )

  NEONiso:::h5_write_dataset(grp, "test_dataset", df)
  NEONiso:::h5_close_group(grp)
  NEONiso:::h5_close(fid)

  # Verify the file has the dataset
  children <- NEONiso:::h5_ls_group(tmp, "data")
  expect_true("test_dataset" %in% children)
})

test_that("h5_ls returns top-level groups", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)
  NEONiso:::h5_create_group(fid, "ONAQ")
  NEONiso:::h5_create_group(fid, "ONAQ/dp01")
  NEONiso:::h5_close(fid)

  result <- NEONiso:::h5_ls(tmp)
  expect_s3_class(result, "data.frame")
  expect_true("name" %in% names(result))
  # Should only return top-level group
  expect_true("ONAQ" %in% result$name)
})

test_that("h5_ls_group returns children of a specific group", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  fid <- NEONiso:::h5_create_file(tmp)
  NEONiso:::h5_create_group(fid, "ONAQ")
  NEONiso:::h5_create_group(fid, "ONAQ/dp01")
  NEONiso:::h5_create_group(fid, "ONAQ/dp01/data")
  NEONiso:::h5_create_group(fid, "ONAQ/dp01/qfqm")
  NEONiso:::h5_create_group(fid, "ONAQ/dp01/ucrt")
  NEONiso:::h5_close(fid)

  children <- NEONiso:::h5_ls_group(tmp, "ONAQ/dp01")
  expect_type(children, "character")
  expect_setequal(children, c("data", "qfqm", "ucrt"))
})

test_that("h5_open opens file for read-write", {
  tmp <- tempfile(fileext = ".h5")
  on.exit(unlink(tmp), add = TRUE)

  # Create file with a group
  fid <- NEONiso:::h5_create_file(tmp)
  NEONiso:::h5_create_group(fid, "existing")
  NEONiso:::h5_close(fid)

  # Reopen and add another group
  fid2 <- NEONiso:::h5_open(tmp)
  NEONiso:::h5_create_group(fid2, "new_group")
  NEONiso:::h5_close(fid2)

  # Verify both groups exist
  contents <- NEONiso:::h5_ls(tmp)
  expect_true("existing" %in% contents$name)
  expect_true("new_group" %in% contents$name)
})

test_that("h5_ls on real NEON file returns site code", {
  fin <- system.file("extdata",
    "NEON.D15.ONAQ.DP4.00200.001.nsae.2019-05.basic.packed.h5",
    package = "NEONiso", mustWork = TRUE)

  result <- NEONiso:::h5_ls(fin)
  expect_true("ONAQ" %in% result$name)
})

test_that("h5_read_attrs on real NEON file returns site attributes", {
  fin <- system.file("extdata",
    "NEON.D15.ONAQ.DP4.00200.001.nsae.2019-05.basic.packed.h5",
    package = "NEONiso", mustWork = TRUE)

  attrs <- NEONiso:::h5_read_attrs(fin, "ONAQ")
  expect_type(attrs, "list")
  expect_true("LvlMeasTow" %in% names(attrs))
})

Try the NEONiso package in your browser

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

NEONiso documentation built on Feb. 22, 2026, 5:07 p.m.