# test-api-mock.R
# Pruebas de API CIE-11 con mocks y validacion de parametros
# ============================================================
# PRUEBAS DE VALIDACION DE PARAMETROS cie11_search()
# ============================================================
# ============================================================
# PRUEBAS DE MANEJO DE ERRORES
# ============================================================
test_that("cie11_search maneja error de conexion gracefully", {
skip_if_not_installed("httr2")
# Con credenciales invalidas, debe dar warning y retornar tibble vacio
# (no debe crashear)
expect_warning(
resultado <- cie11_search("diabetes", api_key = "invalid:credentials"),
"Error API CIE-11"
)
# Debe retornar tibble vacio
expect_s3_class(resultado, "tbl_df")
expect_equal(nrow(resultado), 0)
})
test_that("cie11_search retorna tibble vacio en error", {
skip_if_not_installed("httr2")
# Cualquier error debe retornar estructura correcta
suppressWarnings({
resultado <- cie11_search("test", api_key = "bad:key")
})
expect_s3_class(resultado, "tbl_df")
expect_true("codigo" %in% names(resultado))
expect_true("titulo" %in% names(resultado))
expect_true("capitulo" %in% names(resultado))
expect_equal(nrow(resultado), 0)
})
# ============================================================
# PRUEBAS DE FORMATO DE API KEY
# ============================================================
test_that("cie11_search rechaza API key sin separador", {
skip_if_not_installed("httr2")
# Sin ":"
expect_error(
cie11_search("diabetes", api_key = "singletoken"),
"client_id:client_secret"
)
# Vacio
expect_error(
cie11_search("diabetes", api_key = ""),
"client_id:client_secret"
)
})
test_that("cie11_search acepta API key con formato correcto",
{
skip_if_not_installed("httr2")
# Formato correcto (fallara en autenticacion, no en formato)
# El error no debe mencionar "client_id:client_secret"
error_msg <- tryCatch({
suppressWarnings(cie11_search("diabetes", api_key = "id:secret"))
"no_error"
}, error = function(e) {
e$message
}, warning = function(w) {
"warning"
})
# Si hay error, no debe ser de formato
if (error_msg != "no_error" && error_msg != "warning") {
expect_false(grepl("client_id:client_secret", error_msg))
}
})
# ============================================================
# PRUEBAS DE VARIABLE DE ENTORNO
# ============================================================
test_that("cie11_search usa ICD_API_KEY de environment", {
skip_if_not_installed("httr2")
# Guardar valor original
old_key <- Sys.getenv("ICD_API_KEY", unset = NA)
on.exit({
if (is.na(old_key)) {
Sys.unsetenv("ICD_API_KEY")
} else {
Sys.setenv(ICD_API_KEY = old_key)
}
})
# Setear key de prueba
Sys.setenv(ICD_API_KEY = "env:key")
# Debe usar la key del environment (y fallar en autenticacion)
expect_warning(
resultado <- cie11_search("diabetes"),
"Error API CIE-11"
)
expect_s3_class(resultado, "tbl_df")
})
test_that("cie11_search prefiere argumento sobre environment", {
skip_if_not_installed("httr2")
# Guardar valor original
old_key <- Sys.getenv("ICD_API_KEY", unset = NA)
on.exit({
if (is.na(old_key)) {
Sys.unsetenv("ICD_API_KEY")
} else {
Sys.setenv(ICD_API_KEY = old_key)
}
})
# Setear key en environment
Sys.setenv(ICD_API_KEY = "env:key")
# Usar key de argumento (diferente)
expect_warning(
resultado <- cie11_search("diabetes", api_key = "arg:key"),
"Error API CIE-11"
)
# La funcion debe usar arg:key, no env:key
# (ambas fallaran, pero verificamos que acepta el argumento)
expect_s3_class(resultado, "tbl_df")
})
# ============================================================
# PRUEBAS DE DEPENDENCIA HTTR2
# ============================================================
test_that("cie11_search informa sobre httr2 faltante", {
# Este test solo funciona si httr2 NO esta instalado
# Lo saltamos si httr2 esta disponible
skip_if(requireNamespace("httr2", quietly = TRUE),
"httr2 esta instalado")
expect_error(
cie11_search("diabetes", api_key = "test:test"),
"httr2"
)
})
# ============================================================
# PRUEBAS CON HTTP MOCKING (local_mocked_bindings)
# Cubren lineas 41-95 de cie-api.R: OAuth token + search + parsing
# ============================================================
test_that("cie11_search retorna resultados con mock HTTP exitoso", {
skip_if_not_installed("httr2")
call_count <- 0L
local_mocked_bindings(
req_perform = function(req, ...) {
call_count <<- call_count + 1L
structure(list(call_id = call_count), class = "httr2_response")
},
resp_body_json = function(resp, ...) {
if (resp$call_id == 1L) {
# Token response
list(access_token = "mock_token_abc123")
} else {
# Search response con resultados
list(destinationEntities = data.frame(
theCode = c("5A00", "5A01", "5A02"),
title = c(
"Diabetes mellitus tipo 1",
"Diabetes mellitus tipo 2",
"Otra diabetes mellitus"
),
chapter = c("05", "05", "05"),
stringsAsFactors = FALSE
))
}
},
.package = "httr2"
)
resultado <- cie11_search("diabetes", api_key = "test_id:test_secret")
expect_s3_class(resultado, "tbl_df")
expect_equal(nrow(resultado), 3)
expect_equal(resultado$codigo, c("5A00", "5A01", "5A02"))
# Verificar que HTML tags fueron limpiados
expect_false(grepl("Hipertensi\u00f3n ",
"arterial esencial"),
chapter = "11",
stringsAsFactors = FALSE
))
}
},
.package = "httr2"
)
resultado <- cie11_search("hipertension", api_key = "id:secret")
expect_equal(nrow(resultado), 1)
expect_equal(resultado$titulo[1], "Hipertensi\u00f3n arterial esencial")
expect_false(grepl("