test_that("test doc_riskmetrics", {
  
  # set CRAN repo 
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "stringr-1.5.1.tar.gz",
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  # Defer cleanup: remove test package from temp dirs
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    pkg_desc <- get_pkg_desc(pkg_source_path, 
                             fields = c("Package", 
                                        "Version"))
    
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    doc_riskmetric_test <- 
      doc_riskmetric(pkg_name, pkg_ver, pkg_source_path)
    
    expect_identical(length(doc_riskmetric_test), 12L)
    expect_true(checkmate::check_list(doc_riskmetric_test, all.missing = FALSE))
    expect_true(checkmate::check_list(doc_riskmetric_test, any.missing = TRUE))
  }
})


test_that("doc_riskmetric handles missing R folder", {
  
  # Stub fs::dir_exists to simulate missing R folder
  mockery::stub(doc_riskmetric, "fs::dir_exists", function(path) FALSE)
  
  # Stub fs::path to return a dummy path
  mockery::stub(doc_riskmetric, "fs::path", function(...) "mock/path/R")
  
  # Stub assess_description_file_elements to return expected structure
  mockery::stub(doc_riskmetric, "assess_description_file_elements", function(pkg_name, pkg_source_path) {
    list(
      has_bug_reports_url = TRUE,
      has_source_control = TRUE,
      has_maintainer = TRUE,
      has_website = TRUE
    )
  })
  
  # Stub other assess_* functions to return dummy values
  mockery::stub(doc_riskmetric, "assess_export_help", function(...) TRUE)
  mockery::stub(doc_riskmetric, "assess_vignettes", function(...) TRUE)
  mockery::stub(doc_riskmetric, "assess_examples", function(...) TRUE)
  mockery::stub(doc_riskmetric, "assess_news", function(...) TRUE)
  mockery::stub(doc_riskmetric, "assess_news_current", function(...) TRUE)
  
  
  # Stub assess_examples to avoid tools::Rd_db
  mockery::stub(doc_riskmetric, "assess_examples", function(...) {
    list(data = data.frame(function_name = "fun", example = "no example"), example_score = 50)
  })
  
  
  # Stub assess_exported_functions_docs to avoid tools::Rd_db
  mockery::stub(doc_riskmetric, "assess_exported_functions_docs", function(...) {
    list(data = data.frame(function_name = "fun", documentation_name = "topic", documentation_location = "man/topic.Rd"),
         documentation_score = 75)
  })
  
  
  pkg_name <- "mockpkg"
  pkg_ver <- "0.1.0"
  pkg_source_path <- "mock/path"
  
  expect_message(
    doc_scores <- doc_riskmetric(pkg_name, pkg_ver, pkg_source_path),
    glue::glue("{pkg_name} has no R folder to assess codebase size"),
    fixed = TRUE
  )
  
  expect_equal(doc_scores$size_codebase, 0)
})

test_that("get_pkg_author returns correct structure without funder", {
  # Mocked return values
  mock_creator <- list(list(email = "krlmlr+r@mailbox.org"))
  mock_authors <- list(
    list(email = "krlmlr+r@mailbox.org"),
    list(email = "jenny@rstudio.com")
  )
  
  # Create a fake description object with the required methods
  fake_desc <- list(
    has_fields = function(field) TRUE
  )
  class(fake_desc) <- "description"
  
  # Stub all necessary functions
  mockery::stub(get_pkg_author, "description$new", function(file) fake_desc)
  mockery::stub(get_pkg_author, "desc::desc_get_author", function(role, file) {
    if (role == "cre") return(mock_creator)
    if (role == "fnd") return(NULL)
  })
  mockery::stub(get_pkg_author, "desc::desc_get_authors", function(file) mock_authors)
  
  result <- get_pkg_author("test", "fake/path")
  
  expect_equal(result$maintainer[[1]]$email, "krlmlr+r@mailbox.org")
  expect_null(result$funder)
  expect_equal(length(result$authors), 2)
  expect_equal(result$authors[[1]]$email, "krlmlr+r@mailbox.org")
  expect_equal(result$authors[[2]]$email, "jenny@rstudio.com")
  
})


test_that("get_pkg_author returns correct structure with funder", {
  # Mocked return values
  mock_creator <- list(list(email = "hadley@posit.co"))
  mock_funder <- "Posit Software, PBC [cph, fnd]"
  mock_authors <- list(
    list(email = "hadley@posit.co"),
    list(email = "another@posit.co")
  )
  
  # Create a fake description object with the required methods
  fake_desc <- list(
    has_fields = function(field) TRUE
  )
  class(fake_desc) <- "description"
  
  # Stub all necessary functions
  mockery::stub(get_pkg_author, "description$new", function(file) fake_desc)
  mockery::stub(get_pkg_author, "desc::desc_get_author", function(role, file) {
    if (role == "cre") return(mock_creator)
    if (role == "fnd") return(mock_funder)
  })
  mockery::stub(get_pkg_author, "desc::desc_get_authors", function(file) mock_authors)
  
  result <- get_pkg_author("test", "fake/path")
  
  
  expect_equal(result$maintainer[[1]]$email, "hadley@posit.co")
  expect_equal(as.character(result$funder), mock_funder)
  expect_equal(length(result$authors), 2)
  expect_equal(result$authors[[1]]$email, "hadley@posit.co")
})


test_that("get_pkg_author handles missing creator and author", {
  
  # Stub description$new to return an object with has_fields method
  mock_desc_obj <- list(
    has_fields = function(field) FALSE
  )
  class(mock_desc_obj) <- "description"
  
  mockery::stub(get_pkg_author, "description$new", function(file) mock_desc_obj)
  
  # Stub desc_coerce_authors_at_r to do nothing
  mockery::stub(get_pkg_author, "desc_coerce_authors_at_r", function(file) NULL)
  
  # Stub desc::desc_get_author to return empty vector for both roles
  mockery::stub(get_pkg_author, "desc::desc_get_author", function(role, file) character(0))
  
  # Stub desc::desc_get_authors to return empty vector
  mockery::stub(get_pkg_author, "desc::desc_get_authors", function(file) character(0))
  
  pkg_name <- "mockpkg"
  pkg_source_path <- "mock/path"
  
  result <- get_pkg_author(pkg_name, pkg_source_path)
  
  expect_null(result$maintainer)
  expect_null(result$authors)
  expect_null(result$funder)
})



test_that("parse authors for mocked package folder works correctly", {
  mock_dir <- withr::local_tempdir()
  dir.create(file.path(mock_dir, "R"), showWarnings = FALSE)
  
  desc_text <- "Package: here
Title: A Simpler Way to Find Your Files
Version: 1.0.2.9000
Date: 2025-09-15
Authors@R:
    c(person(given = \"Kirill\",
             family = \"M\\u00fcller\",
             role = c(\"aut\", \"cre\"),
             email = \"kirill@cynkra.com\",
             comment = c(ORCID = \"0000-0002-1416-3412\")),
      person(given = \"Jennifer\",
             family = \"Bryan\",
             role = \"ctb\",
             email = \"jenny@rstudio.com\",
             comment = c(ORCID = \"0000-0002-6983-2759\")))
Description: Constructs paths to your project's files.
    Declare the relative path of a file within your project with 'i_am()'.
    Use the 'here()' function as a drop-in replacement for 'file.path()',
    it will always locate the files relative to your project root.
License: MIT + file LICENSE
URL: https://here.r-lib.org/, https://github.com/r-lib/here
BugReports: https://github.com/r-lib/here/issues
Imports:
    rprojroot (>= 2.1.0)
Suggests:
    conflicted,
    covr,
    fs,
    knitr,
    palmerpenguins,
    plyr,
    readr,
    rlang,
    rmarkdown,
    testthat,
    uuid,
    withr
VignetteBuilder:
    knitr
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3.9000
Config/testthat/edition: 3
Config/Needs/website: tidyverse/tidytemplate
"
  
  writeLines(desc_text, file.path(mock_dir, "DESCRIPTION"), useBytes = TRUE)
  writeLines("exportPattern(\"^[[:alpha:]]+\")", file.path(mock_dir, "NAMESPACE"))
  
  result <- get_pkg_author("test", mock_dir)
  
  expect_equal(result$maintainer[[1]]$email, "kirill@cynkra.com")
  expect_null(result$funder)
  
  expect_true(!is.null(result$authors))
  expect_equal(length(result$authors), 2)
  expect_equal(result$authors[[1]]$email, "kirill@cynkra.com")
  expect_equal(result$authors[[2]]$email, "jenny@rstudio.com")
})



test_that("parse authors for mocked package folder works correctly 2", {
  mock_dir <- withr::local_tempdir()
  dir.create(file.path(mock_dir, "R"), showWarnings = FALSE)
  
  desc_text <- "Package: stringr
Title: Simple, Consistent Wrappers for Common String Operations
Version: 1.5.2.9000
Authors@R: c(
    person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\", \"cph\")),
    person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"))
  )
Description: A consistent, simple and easy to use set of wrappers around
    the fantastic 'stringi' package. All function and argument names (and
    positions) are consistent, all functions deal with \"NA\"'s and zero
    length vectors in the same way, and the output from one function is
    easy to feed into the input of another.
License: MIT + file LICENSE
URL: https://stringr.tidyverse.org, https://github.com/tidyverse/stringr
BugReports: https://github.com/tidyverse/stringr/issues
Depends:
    R (>= 3.6)
Imports:
    cli,
    glue (>= 1.6.1),
    lifecycle (>= 1.0.3),
    magrittr,
    rlang (>= 1.0.0),
    stringi (>= 1.5.3),
    vctrs (>= 0.4.0)
Suggests:
    covr,
    dplyr,
    gt,
    htmltools,
    htmlwidgets,
    knitr,
    rmarkdown,
    testthat (>= 3.0.0),
    tibble
VignetteBuilder:
    knitr
Config/Needs/website: tidyverse/tidytemplate
Config/potools/style: explicit
Config/testthat/edition: 3
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
"
  
  writeLines(desc_text, file.path(mock_dir, "DESCRIPTION"), useBytes = TRUE)
  writeLines("exportPattern(\"^[[:alpha:]]+\")", file.path(mock_dir, "NAMESPACE"))
  
  result <- get_pkg_author("test", mock_dir)
  
  expect_equal(result$maintainer[[1]]$email, "hadley@posit.co")
  expect_equal(as.character(result$funder), "Posit Software, PBC [cph, fnd]")
  
  expect_equal(length(result$authors), 2)
  expect_equal(as.character(result$maintainer[[1]]$email), "hadley@posit.co")
})

test_that("parse license for tar file MIT", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  # Defer cleanup: remove test package from temp dirs
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    result <- extract_license_from_description(pkg_source_path)
    expect_equal(result, "MIT + file LICENSE")
  }
})


test_that("parse authors for tar file Apache License", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    result <- extract_license_from_description(pkg_source_path)
    expect_equal(result, "Apache License (>= 2)")
  }
})


test_that("parse license not present", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0007_0.1.0.tar.gz", 
                         package = "risk.assessr")
  
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    suppressWarnings(result <- extract_license_from_description(pkg_source_path))
    expect_true(is.na(result))
  }
})


# clean_license

test_that("clean_license splits and normalizes single license", {
  expect_equal(clean_license("MIT"), c("MIT"))
  expect_equal(clean_license("MIT + file LICENSE"), "MIT")
  expect_equal(clean_license("MIT file LICENSE"), "MIT")
  expect_equal(clean_license("Apache-2.0"), c("APACHE"))
  expect_equal(clean_license("NOT AVAILABLE"), c("NOTAVAILABLE"))
})

test_that("clean_license removes trailing file LICENSE", {
  expect_equal(clean_license("MIT file LICENSE"), c("MIT"))
  expect_equal(clean_license("Apache License"), c("APACHE"))
  expect_equal(clean_license("Apache file LICENSE and stuff"), c("APACHE"))
})

test_that("clean_license splits on commas, plus, and pipes", {
  expect_equal(clean_license("MIT, GPL"), c("MIT", "GPL"))
  expect_equal(clean_license("MIT + GPL"), c("MIT", "GPL"))
  expect_equal(clean_license("MIT | GPL"), c("MIT", "GPL"))
})

test_that("clean_license trims whitespace and normalizes to uppercase letters only", {
  expect_equal(clean_license(" mit "), c("MIT"))
  expect_equal(clean_license("Apache License 2.0"), c("APACHE"))
  expect_equal(clean_license("GPL-3.0"), c("GPL"))
})

test_that("clean_license ignores empty parts", {
  expect_equal(clean_license(", , MIT"), c("MIT"))
  expect_equal(clean_license("| | GPL |"), c("GPL"))
})

test_that("clean_license handles empty string input", {
  expect_equal(clean_license(""), NULL)
})

test_that("test assess_description_file_elements for all elements present", {
# check source control
  test_source_control_elements <- function() {
  # Define toy data for testing
    toy_data <- list(
      no_source_control = list(
        pkg_name = "pkg_no_source_control",
        desc_elements = list(URL = "http://example.com"),
        expected_message = "pkg_no_source_control does not have a source control",
        expected_has_source_control = 0
      ),
      has_github = list(
        pkg_name = "pkg_has_github",
        desc_elements = list(URL = "https://github.com/user/repo"),
        expected_message = "pkg_has_github has a source control",
        expected_has_source_control = 1
      ),
      has_ac_uk = list(
        pkg_name = "pkg_has_ac_uk",
        desc_elements = list(URL = "http://www.stats.ox.ac.uk/pub/MASS4/"),
        expected_message = "pkg_has_ac_uk has a source control",
        expected_has_source_control = 1
      ),
      has_bitbucket = list(
        pkg_name = "pkg_has_bitbucket",
        desc_elements = list(URL = "https://bitbucket.org/user/repo"),
        expected_message = "pkg_has_bitbucket has a source control",
        expected_has_source_control = 1
      ),
      has_gitlab = list(
        pkg_name = "pkg_has_gitlab",
        desc_elements = list(URL = "https://gitlab.com/user/repo"),
        expected_message = "pkg_has_gitlab has a source control",
        expected_has_source_control = 1
      ),
      has_cambridge_repo = list(
        pkg_name = "pkg_has_cambridge_repo",
        desc_elements = list(URL = "https://www.repository.cam.ac.uk/items/da5b9b21-ef5f-4ac8-80e4-553d99014aaf/full"),
        expected_message = "pkg_has_cambridge_repo has a source control",
        expected_has_source_control = 1
      ),
      has_wehi = list(
        pkg_name = "pkg_has_wehi",
        desc_elements = list(URL = "http://bioinf.wehi.edu.au/limma"),
        expected_message = "pkg_has_wehi has a source control",
        expected_has_source_control = 1
      ),
      has_bioconductor = list(
        pkg_name = "pkg_has_bioconductor",
        desc_elements = list(URL = "https://bioconductor.org/packages/IRanges"),
        expected_message = "pkg_has_bioconductor has a source control",
        expected_has_source_control = 1
      )
    )
    
    # Define the patterns
    patterns <- "github\\.com|bitbucket\\.org|gitlab\\.com|\\.ac\\.uk|\\.edu\\.au|bioconductor\\.org"
  
  # Test each scenario
    for (test_case in toy_data) {
      pkg_name <- test_case$pkg_name
      desc_elements <- test_case$desc_elements
      expected_message <- test_case$expected_message
      expected_has_source_control <- test_case$expected_has_source_control
      
      expect_message({
        if (is.null(desc_elements$URL) | (is.na(desc_elements$URL))) {
          message(glue::glue("{pkg_name} does not have a source control"))
          has_source_control <- 0
        } else {
          source_matches <- grep(patterns, desc_elements$URL, value = TRUE)
          if (length(source_matches) == 0) {
            message(glue::glue("{pkg_name} does not have a source control"))
            has_source_control <- 0
          } else {
            message(glue::glue("{pkg_name} has a source control"))
            has_source_control <- 1
          }
        }
      }, expected_message)
      
      expect_equal(has_source_control, expected_has_source_control)
    }
  }  

  test_source_control_elements()  
})

test_that("GitHub Pages URLs are detected as source control", {
  # Create a temporary package directory with DESCRIPTION file
  pkg_source_path <- tempfile(pattern = "testpkg")
  dir.create(pkg_source_path)
  on.exit(unlink(pkg_source_path, recursive = TRUE), add = TRUE)
  
  # org/user pages: *.github/* ; legacy project pages: *.pages.github.io
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  description_text <- paste0(
    "Package: testpkg\n",
    "Title: Test Package\n",
    "Version: 1.0.0\n",
    "URL: https://sanofi-public.github.io/risk.assessr/\n",
    "BugReports: https://github.com/Sanofi-Public/risk.assessr/issues\n"
  )
  writeLines(description_text, desc_path)
  
  # Test that GitHub Pages URL is detected
  result <- assess_description_file_elements("testpkg", pkg_source_path)
  expect_false(is.null(result$has_source_control))
  expect_true(length(result$has_source_control) > 0)
  expect_true(grepl("github\\.io", result$has_source_control))
})

test_that("BugReports URL is used as fallback when URL field doesn't match", {
  # Create a temporary package directory with DESCRIPTION file
  pkg_source_path <- tempfile(pattern = "testpkg")
  dir.create(pkg_source_path)
  on.exit(unlink(pkg_source_path, recursive = TRUE), add = TRUE)
  
  # Create DESCRIPTION with non-matching URL but GitHub BugReports
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  description_text <- paste0(
    "Package: testpkg\n",
    "Title: Test Package\n",
    "Version: 1.0.0\n",
    "URL: https://example.com/package\n",
    "BugReports: https://github.com/user/repo/issues\n"
  )
  writeLines(description_text, desc_path)
  
  # Test that BugReports URL is used as fallback
  result <- assess_description_file_elements("testpkg", pkg_source_path)
  expect_false(is.null(result$has_source_control))
  expect_true(length(result$has_source_control) > 0)
  expect_true(grepl("github\\.com", result$has_source_control))
})

test_that("test assess_description_file_elements for all elements present", {
  
  library(risk.assessr)
  # set CRAN repo 
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "stringr-1.5.1.tar.gz",
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  # Defer cleanup: remove test package from temp dirs
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
  
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has bug reports URL"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a source control"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a maintainer"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a website"),
      fixed = TRUE
    )
    desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path)
    expect_identical(length(desc_elements_test), 4L)
    expect_true(checkmate::check_list(desc_elements_test, all.missing = FALSE))
    expect_true(checkmate::check_list(desc_elements_test, any.missing = TRUE))
  }
})

test_that("test assess_description_file_elements for all elements present", {
  
  library(risk.assessr)
  # set CRAN repo 
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0007_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have bug reports URL"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have a source control"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a maintainer"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have a website"),
      fixed = TRUE
    )
    
    desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path)
    expect_identical(length(desc_elements_test), 4L)
    expect_true(checkmate::check_list(desc_elements_test, all.missing = FALSE))
    expect_true(checkmate::check_list(desc_elements_test, any.missing = TRUE))
  }
})


test_that("assess_description_file_elements handles missing maintainer", {
  
  
  # Stub desc_get_author to simulate no maintainer
  mockery::stub(assess_description_file_elements, "desc::desc_get_author", function(role, file) {
    character(0)
  })
  
  # Stub get_pkg_desc to return all required fields
  mockery::stub(assess_description_file_elements, "get_pkg_desc", function(path, fields) {
    list(
      Package = "mockpkg",
      BugReports = "https://example.com/bugs",
      Maintainer = NULL,
      URL = "https://example.com"
    )
  })
  
  pkg_name <- "mockpkg"
  pkg_source_path <- "mock/path"
  
  testthat::expect_message(
    desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
    glue::glue("{pkg_name} does not have a maintainer"),
    fixed = TRUE
  )
  
  # Optional: check output structure
  expect_true(checkmate::check_list(desc_elements_test, any.missing = TRUE))
})



# Authors

test_that("get_pkg_author retrieves all authors correctly", {
  # Create a temporary directory to simulate the package folder
  temp_dir <- tempdir()
  pkg_source_path <- file.path(temp_dir, "limma")
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  dir.create(pkg_source_path, recursive = TRUE, showWarnings = FALSE)
  
  # Provided DESCRIPTION text
  description_text <- "Package: here
Title: A Simpler Way to Find Your Files
Version: 1.0.1
Date: 2020-12-13
Authors@R: 
    c(person(given = 'Kirill',
             family = 'M\u00fcller',
             role = c('aut', 'cre'),
             email = 'krlmlr+r@mailbox.org',
             comment = c(ORCID = '0000-0002-1416-3412')),
      person(given = 'Jennifer',
             family = 'Bryan',
             role = 'ctb',
             email = 'jenny@rstudio.com',
             comment = c(ORCID = '0000-0002-6983-2759')))
Description: Constructs paths to your project's files.
    Declare the relative path of a file within your project with 'i_am()'.
    Use the 'here()' function as a drop-in replacement for 'file.path()',
    it will always locate the files relative to your project root.
License: MIT + file LICENSE
URL: https://here.r-lib.org/, https://github.com/r-lib/here
BugReports: https://github.com/r-lib/here/issues
Imports: rprojroot (>= 2.0.2)
Suggests: conflicted, covr, fs, knitr, palmerpenguins, plyr, readr,
        rlang, rmarkdown, testthat, uuid, withr
VignetteBuilder: knitr
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.1.1.9000
Config/testthat/edition: 3
NeedsCompilation: no
Packaged: 2020-12-13 06:59:33 UTC; kirill
Author: Kirill Müller [aut, cre] (<https://orcid.org/0000-0002-1416-3412>),
  Jennifer Bryan [ctb] (<https://orcid.org/0000-0002-6983-2759>)
Maintainer: Kirill Müller <krlmlr+r@mailbox.org>
Repository: CRAN
Date/Publication: 2020-12-13 07:30:02 UTC
"
  
  # Write the DESCRIPTION text to a file
  writeLines(description_text, desc_path)
  
  # Run the function with the mocked package path
  result <- get_pkg_author("limma", pkg_source_path)
  
  # Assertions
  expect_type(result, "list")
  expect_true(!is.null(result$maintainer))
  expect_true(!is.null(result$authors))
  expect_equal(result$maintainer[[1]]$given, "Kirill")
  expect_equal(result$maintainer[[1]]$family, "Müller")
  
  # Clean up the temporary directory
  unlink(pkg_source_path, recursive = TRUE)
})

test_that("get_pkg_author retrieves all authors correctly without @Author", {
  # Create a temporary directory to simulate the package folder
  temp_dir <- tempdir()
  pkg_source_path <- file.path(temp_dir, "limma")
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  dir.create(pkg_source_path, recursive = TRUE, showWarnings = FALSE)
  
  # Provided DESCRIPTION text
  description_text <- "Package: limma
Version: 2.10.7
Date: 2007/09/24
Title: Linear Models for Microarray Data
Author: Gordon Smyth with contributions from Matthew Ritchie, Jeremy Silver, James Wettenhall, Natalie Thorne, Mette Langaas, Egil Ferkingstad, Marcus Davy, Francois Pepin and Dongseok Choi.
Maintainer: Gordon Smyth <smyth@wehi.edu.au>
Depends: R (<= 2.5.1), methods
Suggests: affy, marray, MASS, splines, sma, statmod (>= 1.2.2), vsn
LazyLoad: yes
Description:  Data analysis, linear models and differential expression for microarray data.
License: LGPL
URL: http://bioinf.wehi.edu.au/limma
biocViews: Microarray, OneChannel, TwoChannel, DataImport, QualityControl, Preprocessing, Statistics, DifferentialExpression, MultipleComparisons, TimeCourse
Packaged: Mon Sep 24 13:01:39 2007; smyth
"
  
  # Write the DESCRIPTION text to a file
  writeLines(description_text, desc_path)
  
  # Run the function with the mocked package path
  result <- get_pkg_author("limma", pkg_source_path)
  
  # Assertions
  expect_type(result, "list")
  expect_true(!is.null(result$maintainer))
  expect_true(!is.null(result$authors))
  expect_equal(result$maintainer[[1]]$given, "Gordon")
  expect_equal(result$maintainer[[1]]$family, "Smyth")
  
  # Clean up the temporary directory
  unlink(pkg_source_path, recursive = TRUE)
})

test_that("test assess_description_file_elements for all elements present", {
  # check source control
  test_source_control_elements <- function() {
    # Define toy data for testing
    toy_data <- list(
      no_source_control = list(
        pkg_name = "pkg_no_source_control",
        desc_elements = list(URL = "http://example.com"),
        expected_message = "pkg_no_source_control does not have a source control",
        expected_has_source_control = 0
      ),
      has_github = list(
        pkg_name = "pkg_has_github",
        desc_elements = list(URL = "https://github.com/user/repo"),
        expected_message = "pkg_has_github has a source control",
        expected_has_source_control = 1
      ),
      has_ac_uk = list(
        pkg_name = "pkg_has_ac_uk",
        desc_elements = list(URL = "http://www.stats.ox.ac.uk/pub/MASS4/"),
        expected_message = "pkg_has_ac_uk has a source control",
        expected_has_source_control = 1
      ),
      has_bitbucket = list(
        pkg_name = "pkg_has_bitbucket",
        desc_elements = list(URL = "https://bitbucket.org/user/repo"),
        expected_message = "pkg_has_bitbucket has a source control",
        expected_has_source_control = 1
      ),
      has_gitlab = list(
        pkg_name = "pkg_has_gitlab",
        desc_elements = list(URL = "https://gitlab.com/user/repo"),
        expected_message = "pkg_has_gitlab has a source control",
        expected_has_source_control = 1
      ),
      has_cambridge_repo = list(
        pkg_name = "pkg_has_cambridge_repo",
        desc_elements = list(URL = "https://www.repository.cam.ac.uk/items/da5b9b21-ef5f-4ac8-80e4-553d99014aaf/full"),
        expected_message = "pkg_has_cambridge_repo has a source control",
        expected_has_source_control = 1
      ),
      has_wehi = list(
        pkg_name = "pkg_has_wehi",
        desc_elements = list(URL = "http://bioinf.wehi.edu.au/limma"),
        expected_message = "pkg_has_wehi has a source control",
        expected_has_source_control = 1
      ),
      has_bioconductor = list(
        pkg_name = "pkg_has_bioconductor",
        desc_elements = list(URL = "https://bioconductor.org/packages/IRanges"),
        expected_message = "pkg_has_bioconductor has a source control",
        expected_has_source_control = 1
      )
    )
    
    # Define the patterns
    patterns <- "github\\.com|bitbucket\\.org|gitlab\\.com|\\.ac\\.uk|\\.edu\\.au|bioconductor\\.org"
    
    # Test each scenario
    for (test_case in toy_data) {
      pkg_name <- test_case$pkg_name
      desc_elements <- test_case$desc_elements
      expected_message <- test_case$expected_message
      expected_has_source_control <- test_case$expected_has_source_control
      
      expect_message({
        if (is.null(desc_elements$URL) | (is.na(desc_elements$URL))) {
          message(glue::glue("{pkg_name} does not have a source control"))
          has_source_control <- 0
        } else {
          source_matches <- grep(patterns, desc_elements$URL, value = TRUE)
          if (length(source_matches) == 0) {
            message(glue::glue("{pkg_name} does not have a source control"))
            has_source_control <- 0
          } else {
            message(glue::glue("{pkg_name} has a source control"))
            has_source_control <- 1
          }
        }
      }, expected_message)
      
      expect_equal(has_source_control, expected_has_source_control)
    }
  }  
  
  test_source_control_elements()  
})

test_that("test assess_description_file_elements for all elements present", {
  
  library(risk.assessr)
  # set CRAN repo 
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "stringr-1.5.1.tar.gz",
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
  
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has bug reports URL"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a source control"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a maintainer"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a website"),
      fixed = TRUE
    )
    desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path)
    expect_identical(length(desc_elements_test), 4L)
    expect_true(checkmate::check_list(desc_elements_test, all.missing = FALSE))
    expect_true(checkmate::check_list(desc_elements_test, any.missing = TRUE))
  }
})

test_that("test assess_description_file_elements for all elements present", {
  
  library(risk.assessr)
  # set CRAN repo 
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0007_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have bug reports URL"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have a source control"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} has a maintainer"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path),
      glue::glue("{pkg_name} does not have a website"),
      fixed = TRUE
    )
    
    desc_elements_test <- assess_description_file_elements(pkg_name, pkg_source_path)
    expect_identical(length(desc_elements_test), 4L)
    expect_true(checkmate::check_list(desc_elements_test, all.missing = FALSE))
    expect_true(checkmate::check_list(desc_elements_test, any.missing = TRUE))
  }
})

# Authors

test_that("get_pkg_author retrieves all authors correctly", {
  # Create a temporary directory to simulate the package folder
  temp_dir <- tempdir()
  pkg_source_path <- file.path(temp_dir, "limma")
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  dir.create(pkg_source_path, recursive = TRUE, showWarnings = FALSE)
  
  # Provided DESCRIPTION text
  description_text <- "Package: here
Title: A Simpler Way to Find Your Files
Version: 1.0.1
Date: 2020-12-13
Authors@R: 
    c(person(given = 'Kirill',
             family = 'M\u00fcller',
             role = c('aut', 'cre'),
             email = 'krlmlr+r@mailbox.org',
             comment = c(ORCID = '0000-0002-1416-3412')),
      person(given = 'Jennifer',
             family = 'Bryan',
             role = 'ctb',
             email = 'jenny@rstudio.com',
             comment = c(ORCID = '0000-0002-6983-2759')))
Description: Constructs paths to your project's files.
    Declare the relative path of a file within your project with 'i_am()'.
    Use the 'here()' function as a drop-in replacement for 'file.path()',
    it will always locate the files relative to your project root.
License: MIT + file LICENSE
URL: https://here.r-lib.org/, https://github.com/r-lib/here
BugReports: https://github.com/r-lib/here/issues
Imports: rprojroot (>= 2.0.2)
Suggests: conflicted, covr, fs, knitr, palmerpenguins, plyr, readr,
        rlang, rmarkdown, testthat, uuid, withr
VignetteBuilder: knitr
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.1.1.9000
Config/testthat/edition: 3
NeedsCompilation: no
Packaged: 2020-12-13 06:59:33 UTC; kirill
Author: Kirill Müller [aut, cre] (<https://orcid.org/0000-0002-1416-3412>),
  Jennifer Bryan [ctb] (<https://orcid.org/0000-0002-6983-2759>)
Maintainer: Kirill Müller <krlmlr+r@mailbox.org>
Repository: CRAN
Date/Publication: 2020-12-13 07:30:02 UTC
"
  
  # Write the DESCRIPTION text to a file
  writeLines(description_text, desc_path)
  
  # Run the function with the mocked package path
  result <- get_pkg_author("limma", pkg_source_path)
  
  # Assertions
  expect_type(result, "list")
  expect_true(!is.null(result$maintainer))
  expect_true(!is.null(result$authors))
  expect_equal(result$maintainer[[1]]$given, "Kirill")
  expect_equal(result$maintainer[[1]]$family, "Müller")
  
  # Clean up the temporary directory
  unlink(pkg_source_path, recursive = TRUE)
})

test_that("get_pkg_author retrieves all authors correctly without @Author", {
  # Create a temporary directory to simulate the package folder
  temp_dir <- tempdir()
  pkg_source_path <- file.path(temp_dir, "limma")
  desc_path <- file.path(pkg_source_path, "DESCRIPTION")
  dir.create(pkg_source_path, recursive = TRUE, showWarnings = FALSE)
  
  # Provided DESCRIPTION text
  description_text <- "Package: limma
Version: 2.10.7
Date: 2007/09/24
Title: Linear Models for Microarray Data
Author: Gordon Smyth with contributions from Matthew Ritchie, Jeremy Silver, James Wettenhall, Natalie Thorne, Mette Langaas, Egil Ferkingstad, Marcus Davy, Francois Pepin and Dongseok Choi.
Maintainer: Gordon Smyth <smyth@wehi.edu.au>
Depends: R (<= 2.5.1), methods
Suggests: affy, marray, MASS, splines, sma, statmod (>= 1.2.2), vsn
LazyLoad: yes
Description:  Data analysis, linear models and differential expression for microarray data.
License: LGPL
URL: http://bioinf.wehi.edu.au/limma
biocViews: Microarray, OneChannel, TwoChannel, DataImport, QualityControl, Preprocessing, Statistics, DifferentialExpression, MultipleComparisons, TimeCourse
Packaged: Mon Sep 24 13:01:39 2007; smyth
"
  
  # Write the DESCRIPTION text to a file
  writeLines(description_text, desc_path)
  
  # Run the function with the mocked package path
  result <- get_pkg_author("limma", pkg_source_path)
  
  # Assertions
  expect_type(result, "list")
  expect_true(!is.null(result$maintainer))
  expect_true(!is.null(result$authors))
  expect_equal(result$maintainer[[1]]$given, "Gordon")
  expect_equal(result$maintainer[[1]]$family, "Smyth")
  
  # Clean up the temporary directory
  unlink(pkg_source_path, recursive = TRUE)
})

test_that("assess exports for tar file works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    export_calc <- assess_exports(pkg_source_path)
    
    expect_identical(length(export_calc), 1L)
    
    expect_vector(export_calc)
    
    expect_true(checkmate::check_numeric(export_calc, 
                                         any.missing = FALSE)
    )
    testthat::expect_equal(export_calc, 1)
  }
})

test_that("assess exports for tar file works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0006_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    export_calc <- assess_exports(pkg_source_path)
    
    expect_identical(length(export_calc), 1L)
    
    expect_vector(export_calc)
    
    expect_true(checkmate::check_numeric(export_calc, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(export_calc, 0) 
  }
  
})

test_that("assess exports for examples works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    
    testthat::expect_message(
      has_examples <- assess_examples(pkg_name, pkg_source_path),
      glue::glue("{(pkg_name)}: 75.00% of exported functions have examples"),
      fixed = TRUE
    )
    
    has_examples <- assess_examples(pkg_name, pkg_source_path)
    
    expect_identical(length(has_examples), 2L)
    
    expect_vector(has_examples)
    
    expect_true(checkmate::check_list(has_examples, 
                                         any.missing = TRUE)
    )
    
    testthat::expect_length(has_examples, 2L) 
  }
  
})


test_that("assess_examples returns 'No documentation found' and 'no Rd file' when find_rd_for_fun() returns NULL", {
  # Bind the function object
  fn <- assess_examples
  
  # Stub tools::Rd_db to return an empty Rd database (or minimal)
  mockery::stub(fn, "tools::Rd_db", function(dir) list())
  
  # Stub build_rd_index to return a dummy index
  mockery::stub(fn, "build_rd_index", function(db) list(alias_index = new.env(), topic_by_file = character(0)))
  
  # Stub find_rd_for_fun to always return NULL (simulate missing Rd doc)
  mockery::stub(fn, "find_rd_for_fun", function(fun, db, idx) NULL)
  
  # Stub extract_examples_text (won't be called because hit is NULL)
  mockery::stub(fn, "extract_examples_text", function(rd_doc) stop("Should not be called"))
  
  # Stub rd_name (won't be called because hit is NULL)
  mockery::stub(fn, "rd_name", function(rd) stop("Should not be called"))
  
  # Stub asNamespace and getNamespaceExports to simulate exported functions
  mockery::stub(fn, "asNamespace", function(pkg) pkg)
  mockery::stub(fn, "getNamespaceExports", function(ns) c("funA", "funB"))
  
  # Stub getExportedValue to return dummy functions
  mockery::stub(fn, "getExportedValue", function(ns, name) function() NULL)
  
  # Run the function
  result <- fn(pkg_name = "mockpkg", pkg_source_path = "mock/path")
  
  # Assertions
  expect_s3_class(result$data, "data.frame")
  expect_equal(nrow(result$data), 2) # two exported functions
  expect_true(all(result$data$documentation_name == "No documentation found"))
  expect_true(all(result$data$example == "no Rd file"))
  expect_true(all(is.na(result$data$documentation_location)))
  expect_equal(result$example_score, 0) # no examples found
})


test_that("assess_exported_functions_docs returns empty data frame when no exported functions", {
  fn <- assess_exported_functions_docs
  
  # Stub tools::Rd_db to return an empty Rd database
  mockery::stub(fn, "tools::Rd_db", function(dir) list())
  
  # Stub asNamespace and getNamespaceExports to simulate no exports
  mockery::stub(fn, "asNamespace", function(pkg) pkg)
  mockery::stub(fn, "getNamespaceExports", function(ns) character(0))
  
  # Run the function
  expect_message(
    result <- fn(pkg_name = "mockpkg", pkg_source_path = "mock/path"),
    regexp = "mockpkg: no exported functions found; documentation score = 0.00%"
  )
  
  # Assertions
  expect_s3_class(result$data, "data.frame")
  expect_equal(nrow(result$data), 0)
  expect_equal(result$has_docs_score, 0)
})


test_that("assess_exported_functions_docs returns 'No documentation found' when find_rd_for_fun returns NULL", {
  fn <- assess_exported_functions_docs
  
  # Stub tools::Rd_db to return a dummy Rd database
  mockery::stub(fn, "tools::Rd_db", function(dir) list())
  
  # Stub build_rd_index to return a dummy index
  mockery::stub(fn, "build_rd_index", function(db) list(alias_index = new.env(), topic_by_file = character(0)))
  
  # Stub find_rd_for_fun to always return NULL
  mockery::stub(fn, "find_rd_for_fun", function(fun, db, idx) NULL)
  
  # Stub asNamespace and getNamespaceExports to simulate exported functions
  mockery::stub(fn, "asNamespace", function(pkg) pkg)
  mockery::stub(fn, "getNamespaceExports", function(ns) c("funA", "funB"))
  
  # Stub getExportedValue to return dummy functions
  mockery::stub(fn, "getExportedValue", function(ns, name) function() NULL)
  
  # Run the function
  expect_message(
    result <- fn(pkg_name = "mockpkg", pkg_source_path = "mock/path"),
    regexp = "mockpkg: 0.00% of exported functions have documentation"
  )
  
  # Assertions
  expect_s3_class(result$data, "data.frame")
  expect_equal(nrow(result$data), 2)
  expect_true(all(result$data$documentation_name == "No documentation found"))
  expect_true(all(is.na(result$data$documentation_location)))
  expect_equal(result$has_docs_score, 0)
})


test_that("assess exports for missing examples works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  
  # Ensure installs during this test go to a temp lib that stays on .libPaths()
  temp_lib <- file.path(tempdir(), "testthat-lib")
  dir.create(temp_lib, recursive = TRUE, showWarnings = FALSE)
  withr::local_libpaths(new = temp_lib, action = "prefix")
  
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  testthat::skip_if(identical(dp_orig, ""), "Bundled test tarball not found")
  
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    
    
    # First attempt: should be found on .libPaths() because we prefixed temp_lib
    available <- requireNamespace(pkg_name, quietly = TRUE)
    
    # Fallback: load from source if not found (use pkgload if available)
    if (!available && dir.exists(pkg_source_path)) {
      testthat::skip_if_not_installed("pkgload")
      pkgload::load_all(pkg_source_path, quiet = TRUE, helpers = FALSE)
      available <- requireNamespace(pkg_name, quietly = TRUE)
    }
    
    testthat::skip_if_not(
      available,
      message = paste("Package", pkg_name, "not available in .libPaths() in CI")
    )
    
    
    testthat::expect_message(
      has_examples <- assess_examples(pkg_name, pkg_source_path),
      glue::glue("{(pkg_name)}: 0.00% of exported functions have examples"),
      fixed = TRUE
    )
    
    has_examples <- assess_examples(pkg_name, pkg_source_path)
    
    expect_identical(length(has_examples), 2L)
    
    expect_vector(has_examples)
    
    expect_true(checkmate::check_list(has_examples, 
                                      any.missing = TRUE)
    )
    
    testthat::expect_length(has_examples, 2L) 
  }
  
})

test_that("assess exports for packages - no exported functions works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0005_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    
    testthat::expect_message(
      has_examples <- assess_examples(pkg_name, pkg_source_path),
      glue::glue("{(pkg_name)}: no exported functions found; example score = 0.00%"),
      fixed = TRUE
    )
    
    has_examples <- assess_examples(pkg_name, pkg_source_path)
    
    expect_identical(length(has_examples), 2L)
    
    expect_vector(has_examples)
    
    expect_true(checkmate::check_list(has_examples, 
                                      any.missing = TRUE)
    )
    
    testthat::expect_length(has_examples, 2L) 
  }
  
})

test_that("assess exports for help files works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      export_help <- assess_export_help(pkg_name, pkg_source_path),
      glue::glue("All exported functions have corresponding help files in {(pkg_name)}"),
      fixed = TRUE
    )
    
    export_help <- assess_export_help(pkg_name, pkg_source_path)
    
    expect_identical(length(export_help), 1L)
    expect_vector(export_help)
    expect_true(checkmate::check_numeric(export_help, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(export_help, 1L) 
  }
  
})

test_that("assess exports for missing help files works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "stringr-1.5.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      export_help <- assess_export_help(pkg_name, pkg_source_path),
      glue::glue("Some exported functions are missing help files in {(pkg_name)}"),
      fixed = TRUE
    )
    
    export_help <- assess_export_help(pkg_name, pkg_source_path)
    
    expect_identical(length(export_help), 1L)
    expect_vector(export_help)
    expect_true(checkmate::check_numeric(export_help, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(export_help, 0L) 
  }
  
})

test_that("assess exports for no help files works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0006_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  # install package locally to ensure test works
  package_installed <- 
    install_package_local(pkg_source_path)
  package_installed <- TRUE
  
  if (package_installed == TRUE ) {	
    
    # ensure path is set to package source path
    rcmdcheck_args$path <- pkg_source_path
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    testthat::expect_message(
      export_help <- assess_export_help(pkg_name, pkg_source_path),
      glue::glue("No exported functions in {(pkg_name)}"),
      fixed = TRUE
    )
    
    export_help <- assess_export_help(pkg_name, pkg_source_path)
    
    expect_identical(length(export_help), 1L)
    expect_vector(export_help)
    expect_true(checkmate::check_numeric(export_help, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(export_help, 0L) 
  }
  
})

test_that("assess exports for news works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    
    testthat::expect_message(
      has_news <- assess_news(pkg_name, pkg_source_path),
      glue::glue("{(pkg_name)} has news"),
      fixed = TRUE
    )
    
    has_news <- assess_news(pkg_name, pkg_source_path)
    
    expect_identical(length(has_news), 1L)
    
    expect_vector(has_news)
    
    expect_true(checkmate::check_numeric(has_news, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(has_news, 1L) 
  }
  
})

test_that("assess exports for missing news works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, 
                             fields = c("Package", 
                                        "Version"))
    pkg_name <- pkg_desc$Package
    
    testthat::expect_message(
      has_news <- assess_news(pkg_name, pkg_source_path),
      glue::glue("{(pkg_name)} has no news"),
      fixed = TRUE
    )
    
    has_news <- assess_news(pkg_name, pkg_source_path)
    
    expect_identical(length(has_news), 1L)
    
    expect_vector(has_news)
    
    expect_true(checkmate::check_numeric(has_news, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(has_news, 0L) 
  }
  
})

test_that("assess exports for current news works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <-get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    
    testthat::expect_message(
      news_current <- assess_news_current(pkg_name, pkg_ver,pkg_source_path),
      glue::glue("{(pkg_name)} has current news"),
      fixed = TRUE
    )
    
    news_current <- assess_news_current(pkg_name, pkg_ver, pkg_source_path)
    
    expect_identical(length(news_current), 1L)
    
    expect_vector(news_current)
    
    expect_true(checkmate::check_numeric(news_current, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(news_current, 1L) 
  }
  
})

test_that("assess exports for missing news works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
 
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    
    # Get package name and version
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    
    testthat::expect_message(
      news_current <- assess_news_current(pkg_name, pkg_ver, pkg_source_path),
      glue::glue("{(pkg_name)} has no current news"),
      fixed = TRUE
    )
    
    testthat::expect_message(
      news_current <- assess_news_current(pkg_name, pkg_ver, pkg_source_path),
      glue::glue("{(pkg_name)} has no news"),
      fixed = TRUE
    )
    
    news_current <- assess_news_current(pkg_name, pkg_ver, pkg_source_path)
    
    expect_identical(length(news_current), 1L)
    
    expect_vector(news_current)
    
    expect_true(checkmate::check_numeric(news_current, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(news_current, 0L) 
  }
})

test_that("assess vignettes for tar file with vignettes works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "here-1.0.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    has_vignettes <- assess_vignettes(pkg_name, pkg_source_path)
    
    expect_identical(length(has_vignettes), 1L)
    
    expect_vector(has_vignettes)
    
    expect_true(checkmate::check_numeric(has_vignettes, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(has_vignettes, 1L) 
  }
  
})

test_that("assess vignettes for tar file with no vignettes works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  
  if (package_installed == TRUE ) {	
    
    pkg_desc <- get_pkg_desc(pkg_source_path, fields = c("Package", "Version"))
    pkg_name <- pkg_desc$Package
    pkg_ver <- pkg_desc$Version
    pkg_name_ver <- paste0(pkg_name, "_", pkg_ver)
    
    has_vignettes <- assess_vignettes(pkg_name, pkg_source_path)
    
    expect_identical(length(has_vignettes), 1L)
    
    expect_vector(has_vignettes)
    
    expect_true(checkmate::check_numeric(has_vignettes, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_equal(has_vignettes, 0L) 
  }
  
})

test_that("assess code base size for small package works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  # Copy test package to a temp file
  dp_orig <- system.file("test-data", 
                         "test.package.0001_0.1.0.tar.gz", 
                         package = "risk.assessr")
  dp <- tempfile(fileext = ".tar.gz")
  file.copy(dp_orig, dp)
  
  # Defer cleanup of copied tarball
  withr::defer(unlink(dp), envir = parent.frame())
  
  # Defer cleanup of unpacked source directory
  withr::defer(unlink(pkg_source_path, recursive = TRUE, force = TRUE),
               envir = parent.frame())
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  if (package_installed == TRUE ) {	
    size_codebase <- assess_size_codebase(pkg_source_path)
    
    expect_identical(length(size_codebase), 1L)
    
    expect_vector(size_codebase)
    
    expect_true(checkmate::check_numeric(size_codebase, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_gt(size_codebase, 0.010) 
  }
  
})

test_that("assess code base size for large package works correctly", {
  
  r = getOption("repos")
  r["CRAN"] = "http://cran.us.r-project.org"
  options(repos = r)
  
  dp <- system.file("test-data", "stringr-1.5.1.tar.gz", 
                    package = "risk.assessr")
  
  # set up package
  install_list <- set_up_pkg(dp)
  
  build_vignettes <- install_list$build_vignettes
  package_installed <- install_list$package_installed
  pkg_source_path <- install_list$pkg_source_path
  rcmdcheck_args <- install_list$rcmdcheck_args
  
  withr::defer({
    unlink(pkg_source_path, recursive = TRUE, force = TRUE)
  })
  
  if (package_installed == TRUE ) {	
    size_codebase <- assess_size_codebase(pkg_source_path)
    
    expect_identical(length(size_codebase), 1L)
    
    expect_vector(size_codebase)
    
    expect_true(checkmate::check_numeric(size_codebase, 
                                         any.missing = FALSE)
    )
    
    testthat::expect_gt(size_codebase, 0.85) 
  }
  
})


test_that("returns NA when both inputs are NA", {
  expect_true(is.na(create_has_ex_docs_score(NA_real_, NA_real_)))
})

test_that("returns the non-NA input when the other is NA", {
  expect_equal(create_has_ex_docs_score(0.75, NA_real_), 0.75)
  expect_equal(create_has_ex_docs_score(NA_real_, 1), 1)
})

test_that("computes the mean for numeric scalars", {
  expect_equal(create_has_ex_docs_score(0, 0), 0)
  expect_equal(create_has_ex_docs_score(1, 1), 1)
  expect_equal(create_has_ex_docs_score(0, 1), 0.5)
  expect_equal(create_has_ex_docs_score(0.75, 1), 0.875)
})

test_that("works with integer inputs", {
  expect_equal(create_has_ex_docs_score(0L, 1L), 0.5)
  expect_type(create_has_ex_docs_score(0L, 1L), "double")  # result should be double
})

test_that("vector inputs are concatenated and averaged (not elementwise)", {
  e <- c(0.2, 0.8)
  d <- c(0.4, 0.6)
  expected <- mean(c(e, d), na.rm = TRUE)  # = 0.5
  expect_equal(create_has_ex_docs_score(e, d), expected)
})

test_that("handles NA within vectors using na.rm=TRUE", {
  e <- c(0.2, NA_real_)
  d <- c(NA_real_, 0.8)
  # concatenated -> c(0.2, NA, NA, 0.8) -> mean of c(0.2, 0.8) = 0.5
  expect_equal(create_has_ex_docs_score(e, d), 0.5)
})

test_that("treats NaN like NA (removed when na.rm=TRUE)", {
  e <- c(0.2, NaN)
  d <- c(NA_real_, 0.8)
  expected <- mean(c(0.2, NaN, NA_real_, 0.8), na.rm = TRUE)  # = 0.5
  expect_equal(create_has_ex_docs_score(e, d), expected)
})

test_that("mixed vector + scalar works (scalar just joins the pool)", {
  e <- c(0.2, 0.8)
  d <- 0.5
  expected <- mean(c(e, d), na.rm = TRUE)  # = 0.5
  expect_equal(create_has_ex_docs_score(e, d), expected)
})

test_that("symmetry: order of arguments does not change the result", {
  e <- c(0.1, 0.5, 0.9)
  d <- c(0.3, NA_real_)
  expect_equal(create_has_ex_docs_score(e, d),
               create_has_ex_docs_score(d, e))
})

test_that("always returns a length-1 double", {
  res <- create_has_ex_docs_score(c(0.2, 0.3), c(0.4, 0.5))
  expect_equal(length(res), 1L)
  expect_type(res, "double")
})
