R Under development (unstable) (2026-01-18 r89306 ucrt) -- "Unsuffered Consequences" Copyright (C) 2026 The R Foundation for Statistical Computing Platform: x86_64-w64-mingw32/x64 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # ============================================================================= > # AUDITORÍA ELITE CRAN - ciecl package > # ============================================================================= > # Este script ejecuta pruebas exhaustivas para asegurar calidad CRAN > # ============================================================================= > > cat("=== AUDITORÍA ELITE CRAN - ciecl ===\n\n") === AUDITORÍA ELITE CRAN - ciecl === > > library(ciecl) > library(testthat) > > # Directorio de bases sintéticas > SYNTH_DIR <- "D:/01_PROYECTOS/PROY_BBDD_SINTETICAS/data/output" > > errors <- list() > warnings_found <- list() > > # ----------------------------------------------------------------------------- > # 1. PRUEBAS CON BASES SINTÉTICAS > # ----------------------------------------------------------------------------- > cat("1. PRUEBAS CON BASES SINTÉTICAS\n") 1. PRUEBAS CON BASES SINTÉTICAS > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > synth_files <- list.files(SYNTH_DIR, pattern = "\\.csv$", full.names = TRUE) > cat("Archivos encontrados:", length(synth_files), "\n\n") Archivos encontrados: 0 > > for (f in synth_files) { + fname <- basename(f) + cat(" Testing:", fname, "... ") + + tryCatch({ + # Leer muestra (primeras 1000 filas) + df <- read.csv(f, nrows = 1000, stringsAsFactors = FALSE) + + # Detectar columna de códigos + code_col <- NULL + for (col in names(df)) { + if (grepl("codigo|code|cie|diag", tolower(col))) { + code_col <- col + break + } + } + + if (is.null(code_col)) code_col <- names(df)[1] + + codes <- df[[code_col]] + + # Test cie_normalizar + norm_result <- suppressWarnings(cie_normalizar(codes[1:min(100, length(codes))])) + + # Test cie_lookup (solo códigos válidos) + valid_codes <- norm_result[grepl("^[A-Z]\\d", norm_result)] + if (length(valid_codes) > 0) { + lookup_result <- suppressWarnings(suppressMessages( + cie_lookup(valid_codes[1:min(10, length(valid_codes))]) + )) + } + + # Test cie_validate_vector + valid_result <- cie_validate_vector(codes[1:min(100, length(codes))]) + + cat("OK\n") + + }, error = function(e) { + cat("ERROR:", conditionMessage(e), "\n") + errors[[fname]] <<- conditionMessage(e) + }) + } > > # ----------------------------------------------------------------------------- > # 2. EDGE CASES EXTREMOS > # ----------------------------------------------------------------------------- > cat("\n2. EDGE CASES EXTREMOS\n") 2. EDGE CASES EXTREMOS > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > edge_cases <- list( + "NULL input" = function() cie_normalizar(NULL), + "Empty vector" = function() cie_normalizar(character(0)), + "All NA" = function() cie_normalizar(c(NA, NA, NA)), + "Very long string" = function() cie_normalizar(paste(rep("A", 1000), collapse = "")), + "Special chars" = function() cie_normalizar("E11.0™©®"), + "Unicode stress" = function() cie_normalizar("糖尿病E11.0диабет"), + "SQL injection attempt" = function() cie_normalizar("E11.0'; DROP TABLE--"), + "Newlines" = function() cie_normalizar("E11\n.0"), + "Tabs" = function() cie_normalizar("E11\t.0"), + "Only whitespace" = function() cie_normalizar(" "), + "Mixed encoding" = function() cie_normalizar(c("E11.0", "diabétes", "niño")), + "Huge vector" = function() cie_normalizar(rep("E11.0", 10000)), + "Numeric input coerced" = function() cie_normalizar(as.character(110)), + "Factor input" = function() cie_normalizar(factor(c("E11.0", "I10"))) + ) > > for (name in names(edge_cases)) { + cat(" Testing:", name, "... ") + tryCatch({ + result <- suppressWarnings(edge_cases[[name]]()) + cat("OK\n") + }, error = function(e) { + # Algunos errores son esperados + if (grepl("debe ser|cannot|NULL|vacio", conditionMessage(e), ignore.case = TRUE)) { + cat("Expected error OK\n") + } else { + cat("UNEXPECTED ERROR:", conditionMessage(e), "\n") + errors[[name]] <<- conditionMessage(e) + } + }) + } Testing: NULL input ... OK Testing: Empty vector ... OK Testing: All NA ... OK Testing: Very long string ... OK Testing: Special chars ... OK Testing: Unicode stress ... OK Testing: SQL injection attempt ... OK Testing: Newlines ... OK Testing: Tabs ... OK Testing: Only whitespace ... OK Testing: Mixed encoding ... OK Testing: Huge vector ... OK Testing: Numeric input coerced ... OK Testing: Factor input ... OK > > # ----------------------------------------------------------------------------- > # 3. PRUEBAS DE BÚSQUEDA FUZZY > # ----------------------------------------------------------------------------- > cat("\n3. PRUEBAS DE BÚSQUEDA FUZZY\n") 3. PRUEBAS DE BÚSQUEDA FUZZY > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > search_tests <- c( + "diabetes", + "diabetis", # typo + "DIABETES", + "DiAbEtEs", + "neumonia", + "neumonía", + "hipertension", + "hipertensión arterial", + "cancer", + "cáncer de mama", + "infarto", + "IAM", + "HTA", + "EPOC", + "VIH", + "tuberculosis", + "TBC", + "", # vacío + "xyzabc123", # sin resultados + "a", # muy corto + paste(rep("diabetes ", 100), collapse = "") # muy largo + ) > > for (term in search_tests) { + display_term <- if (nchar(term) > 30) paste0(substr(term, 1, 30), "...") else term + cat(" Searching:", sprintf("%-35s", paste0('"', display_term, '"')), "... ") + tryCatch({ + result <- suppressWarnings(suppressMessages( + cie_search(term, max_results = 5) + )) + cat("OK (", nrow(result), " results)\n", sep = "") + }, error = function(e) { + if (grepl("2 caracteres|vacio|debe ser", conditionMessage(e), ignore.case = TRUE)) { + cat("Expected error OK\n") + } else { + cat("ERROR:", conditionMessage(e), "\n") + errors[[paste0("search_", display_term)]] <<- conditionMessage(e) + } + }) + } Searching: "diabetes" ... ERROR: no such table: cie10_fts Searching: "diabetis" ... ERROR: no such table: cie10_fts Searching: "DIABETES" ... ERROR: no such table: cie10_fts Searching: "DiAbEtEs" ... ERROR: no such table: cie10_fts Searching: "neumonia" ... ERROR: no such table: cie10_fts Searching: "neumonía" ... ERROR: no such table: cie10_fts Searching: "hipertension" ... ERROR: no such table: cie10_fts Searching: "hipertensión arterial" ... ERROR: no such table: cie10_fts Searching: "cancer" ... ERROR: no such table: cie10_fts Searching: "cáncer de mama" ... ERROR: no such table: cie10_fts Searching: "infarto" ... ERROR: no such table: cie10_fts Searching: "IAM" ... ERROR: no such table: cie10_fts Searching: "HTA" ... ERROR: no such table: cie10_fts Searching: "EPOC" ... ERROR: no such table: cie10_fts Searching: "VIH" ... ERROR: no such table: cie10_fts Searching: "tuberculosis" ... ERROR: no such table: cie10_fts Searching: "TBC" ... ERROR: no such table: cie10_fts Searching: "" ... Expected error OK Searching: "xyzabc123" ... ERROR: no such table: cie10_fts Searching: "a" ... Expected error OK Searching: "diabetes diabetes diabetes dia..." ... ERROR: no such table: cie10_fts > > # ----------------------------------------------------------------------------- > # 4. PRUEBAS DE COMORBILIDAD > # ----------------------------------------------------------------------------- > cat("\n4. PRUEBAS DE COMORBILIDAD\n") 4. PRUEBAS DE COMORBILIDAD > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > # Crear datos de prueba > comorbid_data <- data.frame( + id = c(1, 1, 1, 2, 2, 3, 3, 3, 3), + codigo = c("I21.0", "E11.0", "I10", "J44.0", "E11.9", "C34.0", "I50.0", "N18.3", "E78.0") + ) > > cat(" Testing cie_comorbid Charlson... ") Testing cie_comorbid Charlson... > tryCatch({ + result <- suppressWarnings(cie_comorbid(comorbid_data, id = "id", code = "codigo", map = "charlson")) + cat("OK (", nrow(result), " patients)\n", sep = "") + }, error = function(e) { + cat("ERROR:", conditionMessage(e), "\n") + errors[["comorbid_charlson"]] <<- conditionMessage(e) + }) OK (3 patients) > > cat(" Testing cie_comorbid Elixhauser... ") Testing cie_comorbid Elixhauser... > tryCatch({ + result <- suppressWarnings(cie_comorbid(comorbid_data, id = "id", code = "codigo", map = "elixhauser")) + cat("OK (", nrow(result), " patients)\n", sep = "") + }, error = function(e) { + cat("ERROR:", conditionMessage(e), "\n") + errors[["comorbid_elixhauser"]] <<- conditionMessage(e) + }) OK (3 patients) > > # Test con datos vacíos > cat(" Testing cie_comorbid empty data... ") Testing cie_comorbid empty data... > tryCatch({ + empty_df <- data.frame(id = integer(0), codigo = character(0)) + result <- suppressWarnings(cie_comorbid(empty_df, id = "id", code = "codigo")) + cat("OK\n") + }, error = function(e) { + # El paquete comorbidity subyacente lanza error con datos vacíos - esto es esperado + if (grepl("vacio|empty|filas|non-missing", conditionMessage(e), ignore.case = TRUE)) { + cat("Expected error OK\n") + } else { + cat("ERROR:", conditionMessage(e), "\n") + errors[["comorbid_empty"]] <<- conditionMessage(e) + } + }) Expected error OK > > # ----------------------------------------------------------------------------- > # 5. PRUEBAS SQL > # ----------------------------------------------------------------------------- > cat("\n5. PRUEBAS SQL\n") 5. PRUEBAS SQL > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > sql_tests <- list( + "Basic SELECT" = "SELECT * FROM cie10 LIMIT 5", + "WHERE clause" = "SELECT * FROM cie10 WHERE codigo LIKE 'E11%' LIMIT 5", + "COUNT" = "SELECT COUNT(*) as n FROM cie10", + "GROUP BY" = "SELECT capitulo, COUNT(*) as n FROM cie10 GROUP BY capitulo LIMIT 5" + ) > > for (name in names(sql_tests)) { + cat(" Testing:", name, "... ") + tryCatch({ + result <- cie10_sql(sql_tests[[name]]) + cat("OK (", nrow(result), " rows)\n", sep = "") + }, error = function(e) { + cat("ERROR:", conditionMessage(e), "\n") + errors[[paste0("sql_", name)]] <<- conditionMessage(e) + }) + } Testing: Basic SELECT ... OK (5 rows) Testing: WHERE clause ... OK (5 rows) Testing: COUNT ... OK (1 rows) Testing: GROUP BY ... OK (5 rows) > > # SQL injection attempts (should fail) > sql_attacks <- c( + "DROP TABLE cie10", + "DELETE FROM cie10", + "UPDATE cie10 SET codigo = 'X'", + "INSERT INTO cie10 VALUES ('X', 'X')", + "SELECT * FROM cie10; DROP TABLE cie10" + ) > > cat(" Testing SQL injection protection:\n") Testing SQL injection protection: > for (attack in sql_attacks) { + display <- if (nchar(attack) > 40) paste0(substr(attack, 1, 40), "...") else attack + cat(" ", display, "... ") + tryCatch({ + result <- cie10_sql(attack) + cat("VULNERABILITY! Query executed!\n") + errors[[paste0("sql_injection_", substr(attack, 1, 20))]] <<- "Query should have been blocked" + }, error = function(e) { + cat("Blocked OK\n") + }) + } DROP TABLE cie10 ... Blocked OK DELETE FROM cie10 ... Blocked OK UPDATE cie10 SET codigo = 'X' ... Blocked OK INSERT INTO cie10 VALUES ('X', 'X') ... Blocked OK SELECT * FROM cie10; DROP TABLE cie10 ... Blocked OK > > # ----------------------------------------------------------------------------- > # 6. VERIFICACIÓN DE DOCUMENTACIÓN > # ----------------------------------------------------------------------------- > cat("\n6. VERIFICACIÓN DE DOCUMENTACIÓN\n") 6. VERIFICACIÓN DE DOCUMENTACIÓN > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > exported_fns <- c( + "cie_lookup", "cie_search", "cie_normalizar", "cie_expand", + + "cie_validate_vector", "cie_comorbid", "cie_map_comorbid", + "cie10_sql", "cie10_clear_cache", "cie11_search", + "cie_table", "cie_siglas", "cie_guia_busqueda", "generar_cie10_cl" + ) > > for (fn in exported_fns) { + cat(" Checking docs for:", fn, "... ") + tryCatch({ + help_file <- help(fn, package = "ciecl") + if (length(help_file) > 0) { + cat("OK\n") + } else { + cat("MISSING\n") + errors[[paste0("doc_", fn)]] <<- "Documentation missing" + } + }, error = function(e) { + cat("ERROR:", conditionMessage(e), "\n") + errors[[paste0("doc_", fn)]] <<- conditionMessage(e) + }) + } Checking docs for: cie_lookup ... OK Checking docs for: cie_search ... OK Checking docs for: cie_normalizar ... OK Checking docs for: cie_expand ... OK Checking docs for: cie_validate_vector ... OK Checking docs for: cie_comorbid ... OK Checking docs for: cie_map_comorbid ... OK Checking docs for: cie10_sql ... OK Checking docs for: cie10_clear_cache ... OK Checking docs for: cie11_search ... OK Checking docs for: cie_table ... OK Checking docs for: cie_siglas ... OK Checking docs for: cie_guia_busqueda ... OK Checking docs for: generar_cie10_cl ... OK > > # ----------------------------------------------------------------------------- > # 7. PRUEBAS DE RENDIMIENTO > # ----------------------------------------------------------------------------- > cat("\n7. PRUEBAS DE RENDIMIENTO\n") 7. PRUEBAS DE RENDIMIENTO > cat(paste(rep("-", 60), collapse = ""), "\n") ------------------------------------------------------------ > > cat(" cie_normalizar (10000 codes)... ") cie_normalizar (10000 codes)... > t1 <- system.time({ + result <- cie_normalizar(rep(c("E11.0", "i10", "J44 0", "a00"), 2500)) + }) > cat(sprintf("%.2fs\n", t1["elapsed"])) 3.20s > > cat(" cie_lookup (100 codes)... ") cie_lookup (100 codes)... > t2 <- system.time({ + result <- suppressMessages(cie_lookup(rep("E11.0", 100))) + }) > cat(sprintf("%.2fs\n", t2["elapsed"])) 0.02s > > cat(" cie_search (single term)... ") cie_search (single term)... > t3 <- system.time({ + result <- suppressMessages(cie_search("diabetes", max_results = 50)) + }) Error: no such table: cie10_fts Timing stopped at: 0 0 0 Execution halted