tests/testthat/test-integration-audio-prediction.R

# Skip the entire file if not in a full test environment
skip_if_not(is_full_test_env(), "Not in full test environment - skipping all integration tests")

# Setup once for all tests
tflite_model <- get_test_tflite_model(skip_if_not_available = FALSE)
audio_file <- test_audio_file()

test_that("predict_species works with default parameters", {
  predictions <- predict_species_from_audio_file(tflite_model, audio_file)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
})

test_that("birdnet_model structure is correct", {
  expect_s3_class(tflite_model, c("birdnet_model_tflite"))
  expect_s3_class(tflite_model$py_model, c("python.builtin.object", "birdnet.models.v2m4.model_v2m4_tflite.AudioModelV2M4TFLite"))
  expect_equal(tflite_model$model_version, "v2.4")
})

test_that("predict_species works with default parameters", {
  predictions <- predict_species_from_audio_file(tflite_model, audio_file)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
})

test_that("predict_species handles custom species list correctly", {
  # Single species
  custom_species_list <- c("Cyanocitta cristata_Blue Jay")
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, filter_species = custom_species_list, keep_empty = FALSE)
  expect_true(nrow(predictions) >= 0) # Since keep_empty = FALSE, it could be 0 if no match

  # Multiple species
  custom_species_list <- c("Cyanocitta cristata_Blue Jay", "Zenaida macroura_Mourning Dove")
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, filter_species = custom_species_list, keep_empty = FALSE)
  expect_true(nrow(predictions) >= 0) # As above, could be 0 if no match
})

test_that("predict_species handles bandpass filtering", {
  # With bandpass filter
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, use_bandpass = TRUE, bandpass_fmin = 500L, bandpass_fmax = 15000L)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)

  # Without bandpass filter
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, use_bandpass = FALSE)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
})

test_that("predict_species applies sigmoid function correctly", {
  # Apply sigmoid
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, apply_sigmoid = TRUE, sigmoid_sensitivity = 1)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)

  # No sigmoid application
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, apply_sigmoid = FALSE)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
})

test_that("predict_species respects minimum confidence threshold", {
  # Lower threshold
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, min_confidence = 0.05)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
  expect_true(max(predictions$confidence, na.rm = TRUE) >= 0.05)

  # Higher threshold
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, min_confidence = 0.5)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)
  expect_true(max(predictions$confidence, na.rm = TRUE) >= 0.5)
})

test_that("predict_species applies overlap", {
  # Lower threshold
  predictions <- predict_species_from_audio_file(tflite_model, audio_file, chunk_overlap_s = 1)
  expect_true(!is.null(predictions))
  expect_true(nrow(predictions) > 0)

  expect_equal(sort(unique(predictions$start))[1:4], c(0, 2, 4, 6))
})

test_that("predict_species keeps empty intervals when specified", {
  # Keep empty intervals
  predictions_with_empty <- predict_species_from_audio_file(tflite_model, audio_file, keep_empty = TRUE)
  expect_true(!is.null(predictions_with_empty))
  expect_true(nrow(predictions_with_empty) > 0)

  # Do not keep empty intervals
  predictions_wo_empty <- predict_species_from_audio_file(tflite_model, audio_file, keep_empty = FALSE)
  expect_true(!is.null(predictions_wo_empty))
  expect_true(nrow(predictions_wo_empty) >= 0) # Could be 0 if no species detected
  expect_true(nrow(predictions_with_empty) > nrow(predictions_wo_empty))
})

test_that("predict_species handles invalid inputs gracefully", {
  # Invalid species list type
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, filter_species = 123))
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, filter_species = list(c("A", "B"))))

  # Invalid bandpass frequencies
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, bandpass_fmin = -100L))
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, bandpass_fmin = 500L, bandpass_fmax = 100L))

  # Invalid sigmoid sensitivity
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, sigmoid_sensitivity = 2))

  # Invalid batch size
  expect_error(predict_species_from_audio_file(tflite_model, audio_file, batch_size = 0L))

  # Invalid file path
  expect_error(predict_species_from_audio_file(tflite_model, audio_file = "nonexistent_file.wav"))
})

test_that("using arrow produces the same predictions", {
  check_arrow <- getFromNamespace(".check_arrow", "birdnetR")
  skip_if(!all(check_arrow()), "Arrow is not available")

  predictions_no_arrow <- predict_species_from_audio_file(tflite_model, audio_file, use_arrow = FALSE)
  predictions_arrow <- predict_species_from_audio_file(tflite_model, audio_file, use_arrow = TRUE)

  expect_equal(predictions_no_arrow, predictions_arrow)
})

Try the birdnetR package in your browser

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

birdnetR documentation built on June 8, 2025, 10:29 a.m.