tests/testthat/test-spatialDetectionHistory.R

context("spatialDetectionHistory")


library(testthat)
library(secr)

# --- Test Setup ---

# 1. Load single-session data
data(recordTableIndividualSample)
data(camtraps)

# 2. Create a standard single-session camera operation matrix
camop_problem <- cameraOperation(CTtable      = camtraps,
                                 stationCol   = "Station",
                                 setupCol     = "Setup_date",
                                 retrievalCol = "Retrieval_date",
                                 hasProblems  = TRUE,
                                 dateFormat   = "dmy")

# 3. Load and prepare multi-session data
data(camtrapsMultiSeason)
# The function expects session IDs to be numeric (1, 2, ...)
camtrapsMultiSeason$session[camtrapsMultiSeason$session == 2009] <- 1
camtrapsMultiSeason$session[camtrapsMultiSeason$session == 2010] <- 2
data(recordTableIndividualSampleMultiSeason)

# 4. Create a multi-session camera operation matrix
camop_session <- cameraOperation(CTtable      = camtrapsMultiSeason,
                                 stationCol   = "Station",
                                 setupCol     = "Setup_date",
                                 sessionCol   = "session",
                                 retrievalCol = "Retrieval_date",
                                 hasProblems  = TRUE,
                                 dateFormat   = "dmy")


# --- Test Suite ---

testthat::describe("Core Functionality (Single Session)", {
  
  # Skip all tests in this file if secr is not installed
  skip_if_not_installed("secr")
  
  test_that("it creates a valid single-session capthist object", {
    sdh <- spatialDetectionHistory(
      recordTableIndividual = recordTableIndividualSample,
      species               = "LeopardCat",
      camOp                 = camop_problem,
      CTtable               = camtraps,
      output                = "binary",
      stationCol            = "Station",
      Xcol                  = "utm_x",
      Ycol                  = "utm_y",
      individualCol         = "Individual",
      recordDateTimeCol     = "DateTimeOriginal",
      recordDateTimeFormat  = "ymd HMS",
      occasionLength        = 10,
      day1                  = "survey",
      includeEffort         = TRUE,
      timeZone              = "Asia/Kuala_Lumpur"
    )
    
    # 1. Check main object class and structure
    expect_s3_class(sdh, "capthist")
    expect_false(is.list(sdh))  # Single-session is not a list
    
    # 2. Check dimensions and content
    expect_equal(dim(sdh), c(3,5,3))
    
    # 3. Check traps attribute
    traps_obj <- secr::traps(sdh)
    expect_s3_class(traps_obj, "traps")
    expect_equal(nrow(traps_obj), nrow(camtraps))
    
    # 4. Check usage (effort) attribute
    expect_true(!is.null(secr::usage(traps_obj)))
    expect_equal(dim(secr::usage(traps_obj)), c(nrow(camtraps), 5)) # stations x occasions
  })
})


testthat::describe("Multi-Session Functionality", {
  
  skip_if_not_installed("secr")
  
  test_that("it creates a valid multi-session capthist object", {
    sdh_multi <- spatialDetectionHistory(
      recordTableIndividual = recordTableIndividualSampleMultiSeason,
      species               = "LeopardCat",
      camOp                 = camop_session,
      CTtable               = camtrapsMultiSeason,
      sessionCol            = "session",
      output                = "binary",
      stationCol            = "Station",
      Xcol                  = "utm_x",
      Ycol                  = "utm_y",
      individualCol         = "Individual",
      occasionLength        = 10,
      timeZone              = "Asia/Kuala_Lumpur",
      day1                  = "station"
    )
    
    # 1. Check main object class and structure
    expect_s3_class(sdh_multi, "capthist")
    expect_true(is.list(sdh_multi))  # Multi-session IS a list
    expect_length(sdh_multi, 2)      # Two sessions in the data
    
    # 2. Check that list elements are valid capthist objects
    expect_s3_class(sdh_multi[[1]], "capthist")
    expect_s3_class(sdh_multi[[2]], "capthist")
    
  })
})


testthat::describe("Covariate Handling", {
  
  skip_if_not_installed("secr")
  
  test_that("it correctly attaches station and individual covariates", {
    sdh_cov <- spatialDetectionHistory(
      recordTableIndividual = recordTableIndividualSampleMultiSeason,
      species               = "LeopardCat",
      camOp                 = camop_session,
      CTtable               = camtrapsMultiSeason,
      sessionCol            = "session",
      Xcol                  = "utm_x",
      Ycol                  = "utm_y",
      individualCol         = "Individual",
      occasionLength        = 10,
      timeZone              = "Asia/Kuala_Lumpur",
      stationCovariateCols  = c("utm_x", "utm_y"), # Use a column from CTtable as a station covariate
      individualCovariateCols = c("Individual", "Species"), # Use columns as individual covariates
      day1                  = "survey"
    )
    
    # 1. Check for station covariates
    # In multi-session, check one of the sessions' traps
    station_covs <- secr::covariates(secr::traps(sdh_cov[[1]]))
    expect_s3_class(station_covs, "data.frame")
    expect_true(all(names(station_covs) %in% c("utm_y", "utm_x")))
    
    # For single covariate, column name is "value". Fix!
    
    
    # 2. Check for individual covariates
    ind_covs <- secr::covariates(sdh_cov)
    expect_s3_class(ind_covs[[1]], "data.frame")
    expect_true(all(c("Individual", "Species") %in% names(ind_covs[[1]])))
  })
})


testthat::describe("Output Modes and Other Options", {
  
  skip_if_not_installed("secr")
  
  test_that("output = 'count' works correctly", {
    sdh_count <- spatialDetectionHistory(
      recordTableIndividual = recordTableIndividualSample,
      species               = "LeopardCat",
      camOp                 = camop_problem,
      CTtable               = camtraps,
      output                = "count", # Key argument
      occasionLength        = 10,
      Xcol = "utm_x", Ycol = "utm_y", 
      individualCol = "Individual",
      timeZone = "Asia/Kuala_Lumpur",
      day1 = "station"
    )
    
    # The detector attribute should be 'count'
    expect_equal(secr::detector(secr::traps(sdh_count)), "count")
    
    # The sample data has an individual detected twice in one occasion,
    # so at least one cell value should be > 1.
    expect_true(any(sdh_count > 1))
  })
  
  test_that("makeRMarkInput = TRUE produces a data.frame", {
    rmark_df <- spatialDetectionHistory(
      recordTableIndividual = recordTableIndividualSample,
      species               = "LeopardCat",
      camOp                 = camop_problem,
      CTtable               = camtraps,
      makeRMarkInput        = TRUE, # Key argument
      occasionLength        = 10,
      Xcol                  = "utm_x", 
      Ycol                  = "utm_y", 
      individualCol         = "Individual",
      timeZone              = "Asia/Kuala_Lumpur",
      day1                  = "2009-04-05" 
    )
    
    # 1. Check output class
    expect_s3_class(rmark_df, "data.frame")
    expect_false(inherits(rmark_df, "capthist"))
    
    # 2. Check structure
    expect_true("ch" %in% names(rmark_df)) # Must have a capture history column
    expect_equal(nrow(rmark_df), 3) # One row per individual
    
    # 3. Check capture history string format
    expect_true(all(nchar(rmark_df$ch) == 5))
    expect_true(is.character(rmark_df$ch))
  })
})


testthat::describe("Input Validation", {
  
  test_that("it stops for missing or invalid inputs", {
    # Missing camOp
    expect_error(spatialDetectionHistory(recordTableIndividual = recordTableIndividualSample,
                                         species = "LeopardCat",
                                         CTtable = camtraps,
                                         occasionLength = 10,
                                         Xcol = "utm_x", 
                                         Ycol = "utm_y",
                                         individualCol = "Individual"),
                 "'camOp' is not defined")
    
    # Wrong column name
    expect_error(spatialDetectionHistory(recordTableIndividual = recordTableIndividualSample,
                                         species = "LeopardCat",
                                         camOp = camop_problem,
                                         CTtable = camtraps,
                                         occasionLength = 10,
                                         Xcol = "WRONG_X_COL", Ycol = "utm_y",
                                         individualCol = "Individual"),
                 "is not a column name in CTtable")
  })
})

Try the camtrapR package in your browser

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

camtrapR documentation built on Jan. 26, 2026, 1:07 a.m.