context("surveyReport") # --- Test Setup --- # Create shared data and camera operation matrices once. data(camtraps) data(recordTableSample) # Camera operation matrix WITHOUT problems camop_no_problem <- cameraOperation( CTtable = camtraps, stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", hasProblems = FALSE, dateFormat = "dmy" ) # Camera operation matrix WITH problems camop_problem <- cameraOperation( CTtable = camtraps, stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", hasProblems = TRUE, dateFormat = "dmy" ) # camtrapR:::camopPlot(camop_problem) # --- Test Suite --- testthat::describe("Core Functionality and Return Value", { test_that("it returns a list of 5 data frames with correct structure", { report <- surveyReport( recordTable = recordTableSample, CTtable = camtraps, camOp = camop_no_problem, setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "dmy" ) # 1. Check the main output structure expect_true(class(report) == "list") expect_length(report, 5) expected_names <- c("survey_dates", "species_by_station", "events_by_species", "events_by_station", "events_by_station2") expect_named(report, expected_names) # 2. Check that each element is a data frame expect_s3_class(report$survey_dates, "data.frame") expect_s3_class(report$species_by_station, "data.frame") expect_s3_class(report$events_by_species, "data.frame") expect_s3_class(report$events_by_station, "data.frame") expect_s3_class(report$events_by_station2, "data.frame") }) test_that("calculations are correct for a survey without problems", { report <- surveyReport( recordTable = recordTableSample, CTtable = camtraps, setupCol = "Setup_date", retrievalCol = "Retrieval_date", camOp = camop_no_problem, CTDateFormat = "dmy" ) # Check key calculations in the survey_dates table survey_dates <- report$survey_dates stationA_dates <- survey_dates[survey_dates$Station == "StationA", ] # Setup: 2009-04-02, Retrieval: 2009-05-14. Total duration: 43 calendar days expect_equal(stationA_dates$n_calendar_days_total, 43) # No problems, so active days should be the same expect_equal(stationA_dates$n_calendar_days_active, 43) expect_equal(stationA_dates$n_calendar_days_inactive, 0) # Trap nights = active days * number of cameras (1) expect_equal(stationA_dates$n_trap_nights_active, 42) # Check events_by_species events_species <- report$events_by_species pbe_events <- events_species[events_species$species == "PBE", ] expect_equal(as.numeric(pbe_events$n_events), 18) # 18 records for PBE expect_equal(as.numeric(pbe_events$n_stations), 3) # Detected at all three stations }) test_that("calculations are correct for a survey WITH problems", { report_problem <- surveyReport( recordTable = recordTableSample, CTtable = camtraps, setupCol = "Setup_date", retrievalCol = "Retrieval_date", camOp = camop_problem, CTDateFormat = "dmy" ) survey_dates_prob <- report_problem$survey_dates stationC_dates_prob <- survey_dates_prob[survey_dates_prob$Station == "StationC", ] # Station1 had a problem from May 12 to May 17 (6 days) # Total days = 44 # Inactive days = 6 # Active days = 38 expect_equal(stationC_dates_prob$n_calendar_days_total, 44) expect_equal(stationC_dates_prob$n_calendar_days_active, 38) expect_equal(stationC_dates_prob$n_calendar_days_inactive, 6) expect_equal(stationC_dates_prob$n_trap_nights_active, 37.5) }) }) testthat::describe("File Writing and Side Effects", { tmpdir <- tempdir() test_that("sinkpath argument creates a text report", { report <- surveyReport( recordTable = recordTableSample, CTtable = camtraps, setupCol = "Setup_date", retrievalCol = "Retrieval_date", camOp = camop_no_problem, CTDateFormat = "dmy", sinkpath = tmpdir #"." # Write to the temp directory ) # Check for the report file report_files <- list.files(tmpdir, pattern = paste0("survey_report_", Sys.Date(), ".txt"), full.names = T) expect_equal(length(report_files), 1) # Check that the file has content report_content <- readLines(report_files[1]) expect_gt(length(report_content), 10) expect_true(any(grepl("Total number of stations", report_content))) }) test_that("makezip = TRUE creates a valid zip file with expected contents", { testthat::skip_if_not_installed("overlap") report <- surveyReport( recordTable = recordTableSample, CTtable = camtraps, setupCol = "Setup_date", retrievalCol = "Retrieval_date", camOp = camop_no_problem, CTDateFormat = "dmy", Xcol = "utm_x", Ycol = "utm_y", sinkpath = tmpdir, #".", makezip = TRUE ) # 1. Check if the zip file was created zip_files <- list.files(tmpdir, pattern = paste0("surveyReport_", Sys.Date(), ".zip"), full.names = T) expect_equal(length(zip_files), 1) # 2. Check the contents of the zip file zip_contents <- utils::unzip(zip_files[1], list = TRUE) # Expected files/folders expect_true("camtrapR_scripts.R" %in% basename(zip_contents$Name)) # Check for specific files expect_true("recordTable.csv" %in% basename(zip_contents$Name)) n_species <- length(unique(recordTableSample$Species)) expect_equal(sum(grepl("activity_", zip_contents$Name)), n_species) expect_equal(sum(grepl("Presence", zip_contents$Name)), n_species) }) }) testthat::describe("Date/time column checks", { camtraps_setup_blank <- camtraps camtraps_retrieval_blank <- camtraps camtraps_setup_blank$Setup_date[1] <- "" camtraps_retrieval_blank$Retrieval_date[1] <- "" recordTableSample_datetime_blank <- recordTableSample recordTableSample_datetime_blank$DateTimeOriginal[1] <- "" camtraps_setup_NA <- camtraps_setup_blank camtraps_retrieval_NA <- camtraps_retrieval_blank recordTableSample_datetime_NA <- recordTableSample_datetime_blank camtraps_setup_NA$Setup_date[1] <- NA camtraps_retrieval_NA$Retrieval_date[1] <- NA recordTableSample_datetime_NA$DateTimeOriginal[1] <- NA # camera operation matrices camop_no_problem <- cameraOperation(CTtable = camtraps, stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", writecsv = FALSE, hasProblems = FALSE, dateFormat = "%d/%m/%Y" ) # with problems/malfunction camop_problem <- cameraOperation(CTtable = camtraps, stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", writecsv = FALSE, hasProblems = TRUE, dateFormat = "%d/%m/%Y" ) test_that("errors about blank values in Date/Time are correct", { expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps_setup_blank, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are blank values in CTtable[, setupCol]", fixed = TRUE) expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps_retrieval_blank, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are blank values in CTtable[, retrievalCol]", fixed = TRUE) expect_error(surveyReport (recordTable = recordTableSample_datetime_blank, CTtable = camtraps, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are blank values in recordTable[, recordDateTimeCol]", fixed = TRUE) }) test_that("errors about NAs in Date/Time are correct", { expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps_setup_NA, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are NAs in CTtable[, setupCol]", fixed = TRUE) expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps_retrieval_NA, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are NAs in CTtable[, retrievalCol]", fixed = TRUE) expect_error(surveyReport (recordTable = recordTableSample_datetime_NA, CTtable = camtraps, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y"), "there are NAs in recordTable[, recordDateTimeCol]", fixed = TRUE) }) test_that("errors about all NAs in Date/Time are correct", { expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d-%m-%Y"), # this is intentionally wrong "Cannot read date format in CTtable[, setupCol]. Output is all NA. expected: %d-%m-%Y actual: 02/04/2009", fixed = TRUE) expect_error(surveyReport (recordTable = recordTableSample, CTtable = camtraps, camOp = camop_no_problem, speciesCol = "Species", stationCol = "Station", setupCol = "Setup_date", retrievalCol = "Retrieval_date", CTDateFormat = "%d/%m/%Y", recordDateTimeFormat = "%Y/%m/%d %H:%M:%S"), # this is intentionally wrong "Cannot read datetime format in recordTable[, recordDateTimeCol]. Output is all NA. expected: %Y/%m/%d %H:%M:%S actual: 2009-04-21 00:40:00", fixed = TRUE) }) })