tests/test/phase1_tests.R

# =============================================================================
# Phase 1: Coverage Improvement Tests (Combined)
# =============================================================================
#
# Phase 1 Initial + Additional Tests - Combined into single file
# Functions tested: 17 total
#   - Phase 1 Initial: 10 functions
#   - Phase 1 Additional: 7 functions
# Target: 40% coverage (21/52 functions)
#
# =============================================================================

#' Run Phase 1 Tests (Combined)
#'
#' @param verbose Logical, print detailed output
#' @return Test results
#' @export
run_phase1_tests <- function(verbose = TRUE) {
  
  # Setup
  has_openai <- nzchar(Sys.getenv("OPENAI_API_KEY"))
  has_gemini <- nzchar(Sys.getenv("GoogleGemini_API_KEY"))
  has_dify <- nzchar(Sys.getenv("DIFY_API_KEY"))
  has_replicate <- nzchar(Sys.getenv("Replicate_API_TOKEN"))
  is_mac <- Sys.info()['sysname'] == 'Darwin'
  
  test_results <- list()
  test_start_time <- Sys.time()
  
  # Helper function
  run_test_safely <- function(test_name, test_code, skip_reason = NULL) {
    if (!is.null(skip_reason)) {
      if (verbose) cat(sprintf("[SKIP] %s - %s\n", test_name, skip_reason))
      return(list(
        function_name = test_name,
        status = "skipped",
        reason = skip_reason,
        error = NULL,
        duration = 0
      ))
    }
    
    if (verbose) cat(sprintf("[TEST] Running: %s\n", test_name))
    start_time <- Sys.time()
    
    result <- tryCatch({
      eval(parse(text = test_code))
      end_time <- Sys.time()
      duration <- as.numeric(difftime(end_time, start_time, units = "secs"))
      if (verbose) cat(sprintf("[PASS] %s (%.2f sec)\n", test_name, duration))
      list(function_name = test_name, status = "passed", error = NULL, duration = duration)
    }, error = function(e) {
      end_time <- Sys.time()
      duration <- as.numeric(difftime(end_time, start_time, units = "secs"))
      if (verbose) cat(sprintf("[FAIL] %s - %s (%.2f sec)\n", test_name, e$message, duration))
      list(function_name = test_name, status = "failed", error = e$message, duration = duration)
    })
    
    return(result)
  }
  
  if (verbose) {
    cat("═══════════════════════════════════════════════════════════════════════════\n")
    cat("Phase 1 Test Suite (Combined) - Coverage Improvement\n")
    cat("═══════════════════════════════════════════════════════════════════════════\n\n")
    cat(sprintf("OpenAI API:   %s\n", ifelse(has_openai, "✓", "✗")))
    cat(sprintf("Gemini API:   %s\n", ifelse(has_gemini, "✓", "✗")))
    cat(sprintf("Dify API:     %s\n", ifelse(has_dify, "✓", "✗")))
    cat(sprintf("Replicate:    %s\n", ifelse(has_replicate, "✓", "✗")))
    cat(sprintf("macOS:        %s\n\n", ifelse(is_mac, "✓", "✗")))
  }
  
  suppressPackageStartupMessages(library(chatAI4R))
  
  test_idx <- 1
  
  # ═════════════════════════════════════════════════════════════════════════
  # SECTION 1: Phase 1 Initial Tests (10 functions)
  # ═════════════════════════════════════════════════════════════════════════
  
  if (verbose) cat("\n─── Phase 1 Initial Tests ───\n\n")
  
  # Test 1: completions4R (deprecated but still functional)
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. completions4R", test_idx),
      'suppressWarnings({
         result <- completions4R(
           prompt = "Say hello in one word",
           Model = "gpt-3.5-turbo-instruct",
           max_tokens = 5
         )
       })
       stopifnot(!is.null(result))
       stopifnot(length(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. completions4R", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # Test 2: DifyChat4R
  if (has_dify) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. DifyChat4R", test_idx),
      'result <- DifyChat4R(query = "Hello", user = "test-user")
       stopifnot(!is.null(result))
       stopifnot(is.list(result))'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. DifyChat4R", test_idx),
      NULL,
      skip_reason = "Dify API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # Test 3: TextSummaryAsBullet (clipboard-based, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. TextSummaryAsBullet", test_idx),
    NULL,
    skip_reason = "Requires clipboard input (SelectedCode=TRUE)"
  )
  test_idx <- test_idx + 1
  
  # Test 4: proofreadEnglishText (clipboard-based, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. proofreadEnglishText", test_idx),
    NULL,
    skip_reason = "Requires clipboard input (SelectedCode=TRUE)"
  )
  test_idx <- test_idx + 1
  
  # Test 5: speakInEN (macOS only, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. speakInEN", test_idx),
    NULL,
    skip_reason = "Requires clipboard input and audio output"
  )
  test_idx <- test_idx + 1
  
  # Test 6: speakInJA (macOS only, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. speakInJA", test_idx),
    NULL,
    skip_reason = "Requires RStudio and clipboard input"
  )
  test_idx <- test_idx + 1
  
  # Test 7: speakInJA_v2 (macOS only, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. speakInJA_v2", test_idx),
    NULL,
    skip_reason = "Requires clipboard input and audio output"
  )
  test_idx <- test_idx + 1
  
  # Test 8: createImagePrompt_v1
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. createImagePrompt_v1", test_idx),
      'result <- createImagePrompt_v1(
         content = "A cat in a garden with flowers",
         Model = "gpt-4o-mini",
         len = 50
       )
       stopifnot(is.character(result))
       stopifnot(nchar(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. createImagePrompt_v1", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # Test 9: createImagePrompt_v2
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. createImagePrompt_v2", test_idx),
      'result <- createImagePrompt_v2(
         Base_prompt = "A realistic dog in a park",
         style_guidance = "photorealistic, 4K",
         Model = "gpt-4o-mini"
       )
       stopifnot(is.character(result))
       stopifnot(nchar(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. createImagePrompt_v2", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # Test 10: geminiGrounding4R
  if (has_gemini) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. geminiGrounding4R", test_idx),
      'result <- geminiGrounding4R(
         mode = "text",
         contents = "What is the weather today?",
         model = "gemini-2.0-flash"
       )
       stopifnot(is.list(result))'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. geminiGrounding4R", test_idx),
      NULL,
      skip_reason = "Gemini API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # ═════════════════════════════════════════════════════════════════════════
  # SECTION 2: Phase 1 Additional Tests (7 functions)
  # ═════════════════════════════════════════════════════════════════════════
  
  if (verbose) cat("\n─── Phase 1 Additional Tests ───\n\n")
  
  # Test 11: interpretResult
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. interpretResult", test_idx),
      'result <- interpretResult(
         analysis_type = "regression",
         result_text = "R-squared = 0.85, p < 0.001"
       )
       stopifnot(is.data.frame(result) || is.character(result))
       stopifnot(nrow(result) > 0 || length(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. interpretResult", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1

  # Test 12: discussion_flow_v1 (complex, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. discussion_flow_v1", test_idx),
    NULL,
    skip_reason = "Complex multi-turn conversation (API compatibility)"
  )
  test_idx <- test_idx + 1

  # Test 13: textFileInput4ai (requires temp file)
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. textFileInput4ai", test_idx),
      'tmpfile <- tempfile(fileext = ".txt")
       writeLines(c("Name,Age", "Alice,30", "Bob,25"), tmpfile)
       result <- textFileInput4ai(
         file_path = tmpfile,
         model = "gpt-4o-mini",
         system_prompt = "Summarize this data",
         max_tokens = 50,
         show_progress = FALSE
       )
       unlink(tmpfile)
       stopifnot(!is.null(result))
       stopifnot(length(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. textFileInput4ai", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # Test 15: replicatellmAPI4R (skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. replicatellmAPI4R", test_idx),
    NULL,
    skip_reason = "Replicate API compatibility issues"
  )
  test_idx <- test_idx + 1
  
  # Test 16: vision4R (requires image file, skip)
  test_results[[test_idx]] <- run_test_safely(
    sprintf("%02d. vision4R", test_idx),
    NULL,
    skip_reason = "Requires image file"
  )
  test_idx <- test_idx + 1
  
  # Test 17: autocreateFunction4R
  if (has_openai) {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. autocreateFunction4R", test_idx),
      'result <- autocreateFunction4R(
         Func_description = "Calculate the mean of a vector",
         packages = "base",
         max_tokens = 100,
         View = FALSE,
         verbose = FALSE
       )
       stopifnot(is.character(result))
       stopifnot(nchar(result) > 0)'
    )
  } else {
    test_results[[test_idx]] <- run_test_safely(
      sprintf("%02d. autocreateFunction4R", test_idx),
      NULL,
      skip_reason = "OpenAI API key not set"
    )
  }
  test_idx <- test_idx + 1
  
  # ═════════════════════════════════════════════════════════════════════════
  # Summary
  # ═════════════════════════════════════════════════════════════════════════
  
  test_end_time <- Sys.time()
  total_duration <- as.numeric(difftime(test_end_time, test_start_time, units = "secs"))
  
  total_tests <- length(test_results)
  passed_tests <- sum(sapply(test_results, function(x) x$status == "passed"))
  failed_tests <- sum(sapply(test_results, function(x) x$status == "failed"))
  skipped_tests <- sum(sapply(test_results, function(x) x$status == "skipped"))
  
  if (verbose) {
    cat("\n═══════════════════════════════════════════════════════════════════════════\n")
    cat("Phase 1 Test Summary (Combined)\n")
    cat("═══════════════════════════════════════════════════════════════════════════\n\n")
    cat(sprintf("Total Tests:     %d\n", total_tests))
    cat(sprintf("Passed:          %d (%.1f%%)\n", passed_tests, 100 * passed_tests / total_tests))
    cat(sprintf("Failed:          %d (%.1f%%)\n", failed_tests, 100 * failed_tests / total_tests))
    cat(sprintf("Skipped:         %d (%.1f%%)\n", skipped_tests, 100 * skipped_tests / total_tests))
    cat(sprintf("Duration:        %.2f seconds\n\n", total_duration))
    
    if (failed_tests > 0) {
      cat("Failed Tests:\n")
      for (result in test_results) {
        if (result$status == "failed") {
          cat(sprintf("  • %s: %s\n", result$function_name, result$error))
        }
      }
      cat("\n")
    }
    
    # Combined coverage
    base_coverage <- 11  # From run_all_tests.R
    phase1_coverage <- passed_tests
    total_coverage <- base_coverage + phase1_coverage
    
    cat(sprintf("Coverage Breakdown:\n"))
    cat(sprintf("  Base Tests:      %d/52 (21.2%%)\n", base_coverage))
    cat(sprintf("  Phase 1 Tests:   %d/52 (%.1f%%)\n", phase1_coverage, 100 * phase1_coverage / 52))
    cat(sprintf("  Combined Total:  %d/52 (%.1f%%)\n", total_coverage, 100 * total_coverage / 52))
    cat("═══════════════════════════════════════════════════════════════════════════\n\n")
  }
  
  return(invisible(list(
    test_results = test_results,
    summary = list(
      total = total_tests,
      passed = passed_tests,
      failed = failed_tests,
      skipped = skipped_tests,
      duration = total_duration
    )
  )))
}

# Auto-load when sourced
assign("run_phase1_tests", run_phase1_tests, envir = .GlobalEnv)

cat("═══════════════════════════════════════════════════════════════════════════\n")
cat("Phase 1 Test Suite Loaded (Combined)\n")
cat("═══════════════════════════════════════════════════════════════════════════\n\n")
cat("Total Tests: 17 functions\n")
cat("  • Phase 1 Initial: 10 functions\n")
cat("  • Phase 1 Additional: 7 functions\n\n")
cat("Usage: results <- run_phase1_tests()\n\n")

Try the chatAI4R package in your browser

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

chatAI4R documentation built on Jan. 10, 2026, 5:07 p.m.