tests/testthat/test-unit-labels.R

# Mock model objects to avoid downloading actual models
create_mock_tflite_model <- function() {
  structure(
    list(
      py_model = NULL,
      model_version = "v2.4",
      language = "en_us",
      tflite_num_threads = NULL
    ),
    class = c("birdnet_model_tflite", "birdnet_model")
  )
}

create_mock_protobuf_model <- function() {
  structure(
    list(
      py_model = NULL,
      model_version = "v2.4",
      language = "en_us"
    ),
    class = c("birdnet_model_protobuf", "birdnet_model")
  )
}

create_mock_custom_model <- function() {
  structure(
    list(
      py_model = NULL,
      model_version = "v2.4",
      classifier_folder = "/path/to/classifier",
      classifier_name = "custom_classifier",
      tflite_num_threads = NULL
    ),
    class = c("birdnet_model_custom", "birdnet_model")
  )
}

test_that("available_languages returns expected language codes", {
  # Setup mock for evaluate_python_path
  testthat::local_mocked_bindings(
    evaluate_python_path = function(path) list("en_us", "fr", "de"),
    .env = environment()
  )

  # Mock create_module_map and get_element_from_module_map
  testthat::local_mocked_bindings(
    create_module_map = function(...) list(),
    .env = environment()
  )

  testthat::local_mocked_bindings(
    get_element_from_module_map = function(...) "mock_path",
    .env = environment()
  )

  # Create mock for py_builtins$list
  mock_py_builtins <- list(list = function(obj) c("en_us", "fr", "de"))
  testthat::local_mocked_bindings(
    py_builtins = mock_py_builtins,
    .env = environment()
  )

  # Test the function
  languages <- available_languages("v2.4")
  expect_type(languages, "character")
  expect_true(all(c("de", "en_us", "fr") %in% languages))
  expect_equal(length(languages), 3)
})

test_that("read_labels correctly reads species list from file", {
  # Create a temporary file with mock species data
  temp_file <- tempfile(fileext = ".txt")
  species_list <- c(
    "Accipiter cooperii_Cooper's Hawk",
    "Agelaius phoeniceus_Red-winged Blackbird",
    "Anas platyrhynchos_Mallard"
  )
  writeLines(species_list, temp_file)

  # Mock Python path and file reading
  mock_path_obj <- list(
    expanduser = function() {
      list(
        resolve = function(...) temp_file
      )
    }
  )

  mock_pathlib <- list(
    Path = function(...) mock_path_obj
  )

  mock_py_birdnet_utils <- list(
    get_species_from_file = function(...) list(items = species_list)
  )

  testthat::local_mocked_bindings(
    py_pathlib = mock_pathlib,
    .env = environment()
  )

  testthat::local_mocked_bindings(
    py_birdnet_utils = mock_py_birdnet_utils,
    .env = environment()
  )

  # Test the function
  result <- read_labels(temp_file)
  expect_equal(result, species_list)
  expect_length(result, 3)

  # Clean up
  unlink(temp_file)
})

test_that("get_language_path validates language and returns expected path", {
  # Skip test if function is not exported (internal function)
  skip_if_not_installed("birdnetR", "0.2.2")

  # Mock available_languages
  testthat::local_mocked_bindings(
    available_languages = function(...) c("en_us", "fr", "de"),
    .env = environment()
  )

  # Mock module_map related functions
  testthat::local_mocked_bindings(
    create_module_map = function(...) list(),
    .env = environment()
  )

  testthat::local_mocked_bindings(
    get_element_from_module_map = function(...) "mock_path",
    .env = environment()
  )

  # Mock evaluate_python_path
  testthat::local_mocked_bindings(
    evaluate_python_path = function(path) {
      if (grepl("version_app_data_folder", path)) {
        function() "/mock/app/folder"
      } else {
        function(path_obj) {
          list(get_language_path = function(lang) paste0("/mock/path/to/", lang, ".txt"))
        }
      }
    },
    .env = environment()
  )

  # Create a mock model
  mock_model <- list(model_version = "v2.4")

  # Test with valid language
  path <- get_language_path(mock_model, "en_us", "downloader_tflite", "TFLite")
  expect_type(path, "character")
  expect_match(path, "en_us.txt$")

  # Test with invalid language
  expect_error(
    get_language_path(mock_model, "invalid_lang", "downloader_tflite", "TFLite"),
    "`language` must be one of"
  )
})

test_that("labels_path dispatches to correct method based on model class", {
  # Mock get_language_path for tflite and protobuf models
  testthat::local_mocked_bindings(
    get_language_path = function(model, language, downloader_key, subfolder) {
      paste0("/mock/path/to/", language, ".txt")
    },
    .env = environment()
  )

  # Create mock models
  tflite_model <- create_mock_tflite_model()
  protobuf_model <- create_mock_protobuf_model()
  custom_model <- create_mock_custom_model()

  # Test tflite model
  path <- labels_path(tflite_model, "en_us")
  expect_match(path, "en_us.txt$")

  # Test protobuf model
  path <- labels_path(protobuf_model, "fr")
  expect_match(path, "fr.txt$")

  # Test custom model
  # The custom model should directly use the classifier folder and name
  path <- labels_path(custom_model)
  expect_equal(path, file.path(custom_model$classifier_folder, paste0(custom_model$classifier_name, ".txt")))
})

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.