tests/testthat/test_utils.R

## SETUP AND TEST FIXTURES -------------------------------------------------

# Basic invalid object types
null <- NULL
na <- NA
boolean <- TRUE
number_random <- sample(1:1000, 1)
string_random <- paste0(sample(letters, 5), collapse = "")
vector_strings <- c("foo", "bar")
list_strings <- list("foo", "bar")
df <- mtcars
matrix <- as.matrix(mtcars)

# Invalid JSON file (not a valid format)
fill <- list("a" = 1, "b" = 2)
json <- jsonlite::toJSON(fill)
madeup_json_file <- tempfile(fileext = ".json")
write(json, madeup_json_file)

## HELPER FUNCTIONS FOR TESTING --------------------------------------------

#' Test invalid inputs for image_to_pdf function
test_invalid_image_inputs <- function() {
  output_pdf <- file.path(tempdir(), "test.pdf")

  test_that("image_to_pdf() errors with non-vector 'files' parameter", {
    # These are not vectors, so fail the first check
    expect_error(image_to_pdf(df, output_pdf), "'files' input not a vector.")
    expect_error(image_to_pdf(matrix, output_pdf), "'files' input not a vector.")
  })

  test_that("image_to_pdf() errors with non-character vector 'files' parameter", {
    # These are vectors but not character vectors, so fail the second check
    expect_error(image_to_pdf(na, output_pdf), "'files' input not a character vector.")
    expect_error(image_to_pdf(boolean, output_pdf), "'files' input not a character vector.")
    expect_error(image_to_pdf(number_random, output_pdf), "'files' input not a character vector.")
    expect_error(image_to_pdf(list_strings, output_pdf), "'files' input not a character vector.")
  })

  test_that("image_to_pdf() errors with NULL 'files' parameter", {
    # NULL is a special case - it may behave differently
    expect_error(image_to_pdf(null, output_pdf))
  })

  test_that("image_to_pdf() errors with invalid 'pdf_name' parameter", {
    image <- testthat::test_path("examples", "image.jpg")

    # Non-.pdf extensions
    expect_error(image_to_pdf(image, "output.txt"), "Destination filename not .pdf")
    expect_error(image_to_pdf(image, "output.png"), "Destination filename not .pdf")
    expect_error(image_to_pdf(image, "output.jpg"), "Destination filename not .pdf")
    expect_error(image_to_pdf(image, "output"), "Destination filename not .pdf")
    expect_error(image_to_pdf(image, "output.PDF"), "Destination filename not .pdf")
  })
}

#' Test invalid inputs for validation functions (is_pdf, is_json, is_colour)
test_invalid_validation_inputs <- function(func_name, test_func) {
  test_that(paste0(func_name, " handles invalid inputs"), {
    # These shouldn't crash but return FALSE or handle gracefully
    expect_no_error(test_func(null))
    expect_no_error(test_func(na))
    expect_no_error(test_func(number_random))
    expect_no_error(test_func(string_random))
  })
}

## IMAGE_TO_PDF ----------------------------------------------------------------

test_invalid_image_inputs()

test_that("image_to_pdf() creates a PDF file from single image", {
  skip_on_cran()
  skip_on_ci()

  output <- file.path(tempdir(), "output.pdf")
  image <- testthat::test_path("examples", "image.jpg")

  # Clean up any existing file
  if (file.exists(output)) unlink(output, force = TRUE)

  image_to_pdf(image, output)

  expect_true(file.exists(output))
  expect_true(daiR::is_pdf(output))

  unlink(output, force = TRUE)
})

test_that("image_to_pdf() handles different image formats", {
  skip_on_cran()
  skip_on_ci()

  output <- file.path(tempdir(), "output.pdf")

  # Helper function to check if conversion works
  renders <- function(file) {
    if (file.exists(output)) unlink(output, force = TRUE)
    image_to_pdf(file, output)

    if (file.exists(output)) {
      result <- suppressMessages(try(pdftools::pdf_info(output), silent = TRUE))
      return(!inherits(result, "try-error"))
    }
    return(FALSE)
  }

  # Helper function to convert images to different formats
  convert <- function(path_in, type_out) {
    img <- magick::image_read(path_in)
    no_ext <- stringr::str_extract(basename(path_in), ".*(?=\\.\\w{3,4}$)")
    filepath <- file.path(tempdir(), glue::glue("{no_ext}.{type_out}"))
    magick::image_write(img, filepath, format = type_out)
    return(filepath)
  }

  # Convert example file to different formats
  jpg <- testthat::test_path("examples", "image.jpg")
  types <- c("jpeg", "png", "bmp", "gif", "tiff")
  files <- purrr::map_chr(types, ~ convert(jpg, .x))

  # Test on each image type
  expect_true(all(purrr::map_lgl(files, renders)))

  # Cleanup
  tmp_files <- c(files, output)
  unlink(tmp_files, force = TRUE)
})

test_that("image_to_pdf() handles vector of multiple image files", {
  skip_on_cran()
  skip_on_ci()

  output <- file.path(tempdir(), "output_multi.pdf")

  # Helper to convert images
  convert <- function(path_in, type_out) {
    img <- magick::image_read(path_in)
    no_ext <- stringr::str_extract(basename(path_in), ".*(?=\\.\\w{3,4}$)")
    filepath <- file.path(tempdir(), glue::glue("{no_ext}.{type_out}"))
    magick::image_write(img, filepath, format = type_out)
    return(filepath)
  }

  # Create multiple image files
  jpg <- testthat::test_path("examples", "image.jpg")
  types <- c("png", "jpeg", "bmp")
  files <- purrr::map_chr(types, ~ convert(jpg, .x))

  # Clean up any existing output
  if (file.exists(output)) unlink(output, force = TRUE)

  # Convert vector of files
  image_to_pdf(files, output)

  expect_true(file.exists(output))
  expect_true(daiR::is_pdf(output))

  # Cleanup
  tmp_files <- c(files, output)
  unlink(tmp_files, force = TRUE)
})

## IS_PDF ----------------------------------------------------------------------

test_invalid_validation_inputs("is_pdf()", is_pdf)

test_that("is_pdf() correctly identifies non-PDF files", {
  image <- testthat::test_path("examples", "image.jpg")
  fake <- tempfile(fileext = ".pdf")
  fs::file_create(fake)
  nonexist <- "nonexistent_file.pdf"

  expect_false(is_pdf(image))
  expect_false(is_pdf(fake))
  expect_false(is_pdf(nonexist))
  expect_false(is_pdf(madeup_json_file))

  unlink(fake, force = TRUE)
})

test_that("is_pdf() correctly identifies valid PDF files", {
  pdf <- testthat::test_path("examples", "sample.pdf")
  expect_true(is_pdf(pdf))
})

test_that("is_pdf() handles edge cases", {
  # Empty string
  expect_false(is_pdf(""))

  # File with .pdf extension but wrong content
  fake_pdf <- tempfile(fileext = ".pdf")
  writeLines("This is not a PDF", fake_pdf)
  expect_false(is_pdf(fake_pdf))
  unlink(fake_pdf, force = TRUE)
})

## IS_JSON ----------------------------------------------------------------------

test_invalid_validation_inputs("is_json()", is_json)

test_that("is_json() correctly identifies non-JSON files", {
  image <- testthat::test_path("examples", "image.jpg")
  pdf <- testthat::test_path("examples", "sample.pdf")

  # Create various non-JSON files
  txt <- file.path(tempdir(), "foo.txt")
  write("Lorem ipsum", txt)

  csv <- file.path(tempdir(), "bar.csv")
  write("Lorem,ipsum", csv)

  empty <- tempfile(fileext = ".json")
  fs::file_create(empty)

  nonexist <- "nonexistent_file.json"

  expect_false(is_json(image))
  expect_false(is_json(pdf))

  # Text-based files
  expect_false(is_json(txt))
  expect_false(is_json(csv))
  expect_false(is_json(empty))
  expect_false(is_json(nonexist))

  unlink(c(txt, csv, empty), force = TRUE)
})

test_that("is_json() correctly identifies valid JSON files", {
  json1 <- testthat::test_path("examples", "output.json")
  json2 <- testthat::test_path("examples", "output_blank.json")
  json3 <- testthat::test_path("examples", "sample_v1.json")
  json4 <- testthat::test_path("examples", "sample3pg.json")

  expect_true(is_json(json1))
  expect_true(is_json(json2))
  expect_true(is_json(json3))
  expect_true(is_json(json4))
  expect_true(is_json(madeup_json_file))
})

test_that("is_json() handles edge cases", {
  # Empty string
  expect_false(is_json(""))

  # File with .json extension but invalid JSON content
  fake_json <- tempfile(fileext = ".json")
  writeLines("This is not JSON {invalid}", fake_json)
  expect_false(is_json(fake_json))
  unlink(fake_json, force = TRUE)

  # File with valid JSON but wrong extension
  valid_json_wrong_ext <- tempfile(fileext = ".txt")
  write(jsonlite::toJSON(list(a = 1, b = 2)), valid_json_wrong_ext)
  expect_true(is_json(valid_json_wrong_ext))
  unlink(valid_json_wrong_ext, force = TRUE)
})

## IS_COLOUR -------------------------------------------------------------------

test_invalid_validation_inputs("is_colour()", is_colour)

test_that("is_colour() correctly identifies valid color names", {
  # Standard R color names
  expect_true(is_colour("red"))
  expect_true(is_colour("blue"))
  expect_true(is_colour("green"))
  expect_true(is_colour("white"))
  expect_true(is_colour("black"))
  expect_true(is_colour("yellow"))
  expect_true(is_colour("purple"))
  expect_true(is_colour("orange"))
  expect_true(is_colour("pink"))
  expect_true(is_colour("brown"))

  # More obscure but valid R colors
  expect_true(is_colour("cornflowerblue"))
  expect_true(is_colour("darkseagreen"))
  expect_true(is_colour("lightgoldenrodyellow"))
})

test_that("is_colour() correctly identifies valid hex colors", {
  # 6-digit hex codes
  expect_true(is_colour("#FF0000"))
  expect_true(is_colour("#00FF00"))
  expect_true(is_colour("#0000FF"))
  expect_true(is_colour("#FFFFFF"))
  expect_true(is_colour("#000000"))
  expect_true(is_colour("#123456"))
  expect_true(is_colour("#ABCDEF"))

  # Lowercase hex codes
  expect_true(is_colour("#ff0000"))
  expect_true(is_colour("#abcdef"))

  # 3-digit hex codes
  expect_true(is_colour("#FFF"))
  expect_true(is_colour("#000"))
  expect_true(is_colour("#F00"))
  expect_true(is_colour("#0F0"))
})

test_that("is_colour() correctly identifies invalid colors", {
  # Invalid color names
  expect_false(is_colour("notacolor"))
  expect_false(is_colour("redd"))
  expect_false(is_colour("colour"))
  expect_false(is_colour(string_random))

  # Invalid hex codes
  expect_false(is_colour("#12345")) # 5 digits
  expect_false(is_colour("#1234567")) # 7 digits
  expect_false(is_colour("#GGGGGG")) # Invalid hex characters
  expect_false(is_colour("FF0000")) # Missing #
  expect_false(is_colour("#")) # Just #
  expect_false(is_colour("##FF0000")) # Double #

  # Empty and special cases
  expect_false(is_colour(""))
  expect_false(is_colour(" "))
})

test_that("is_colour() handles vectors appropriately", {
  # Single valid color
  expect_true(is_colour("red"))

  # Note: col2rgb can handle vectors, so this might return TRUE
  # depending on implementation - testing actual behavior
  multi_colors <- c("red", "blue")
  result <- is_colour(multi_colors)
  expect_type(result, "logical")
  expect_length(result, 1)
})

test_that("is_colour() recognizes numeric palette indices", {
  expect_true(is_colour("1"))
  expect_true(is_colour("123"))
  expect_true(is_colour("8"))

  # But very large numbers might not work
  # (palette has limited colors, but col2rgb handles overflow)
  expect_true(is_colour("999"))
})

## PDF_TO_BINBASE --------------------------------------------------------------

test_that("pdf_to_binbase() rejects non-PDF files", {
  skip_on_cran()
  skip_on_ci()

  image <- testthat::test_path("examples", "image.jpg")
  expect_error(pdf_to_binbase(image), "Input file not a pdf.")

  # Test with JSON file
  expect_error(pdf_to_binbase(madeup_json_file), "Input file not a pdf.")
})

test_that("pdf_to_binbase() produces a valid base64 string", {
  skip_on_cran()
  skip_on_ci()

  image <- testthat::test_path("examples", "image.jpg")
  output <- file.path(tempdir(), "output.pdf")

  image_to_pdf(image, output)
  base <- pdf_to_binbase(output)

  expect_type(base, "character")
  expect_length(base, 1)
  expect_match(base, "^[a-zA-Z0-9+/]+={0,2}$")
  expect_true(nchar(base) > 0)

  unlink(output, force = TRUE)
})

test_that("pdf_to_binbase() handles actual PDF files", {
  skip_on_cran()
  skip_on_ci()

  pdf <- testthat::test_path("examples", "sample.pdf")
  base <- pdf_to_binbase(pdf)

  expect_type(base, "character")
  expect_length(base, 1)
  expect_match(base, "^[a-zA-Z0-9+/]+={0,2}$")
})

test_that("pdf_to_binbase() handles edge cases", {
  skip_on_cran()
  skip_on_ci()

  # Nonexistent file
  expect_error(pdf_to_binbase("nonexistent.pdf"))

  # Empty file with .pdf extension
  fake_pdf <- tempfile(fileext = ".pdf")
  fs::file_create(fake_pdf)
  expect_error(pdf_to_binbase(fake_pdf), "Input file not a pdf.")
  unlink(fake_pdf, force = TRUE)
})

## IMG_TO_BINBASE --------------------------------------------------------------

test_that("img_to_binbase() rejects PDF files", {
  skip_on_cran()
  skip_on_ci()

  image <- testthat::test_path("examples", "image.jpg")
  output <- file.path(tempdir(), "output.pdf")

  image_to_pdf(image, output)
  expect_error(img_to_binbase(output), "Input file is .pdf.")

  unlink(output, force = TRUE)
})

test_that("img_to_binbase() rejects actual PDF files", {
  skip_on_cran()
  skip_on_ci()

  pdf <- testthat::test_path("examples", "sample.pdf")
  expect_error(img_to_binbase(pdf), "Input file is .pdf.")
})

test_that("img_to_binbase() produces a valid base64 string from images", {
  skip_on_cran()
  skip_on_ci()

  image <- testthat::test_path("examples", "image.jpg")
  base <- img_to_binbase(image)

  expect_type(base, "character")
  expect_length(base, 1)
  expect_match(base, "^[a-zA-Z0-9+/]+={0,2}$")
  expect_true(nchar(base) > 0)
})

test_that("img_to_binbase() handles different image formats", {
  skip_on_cran()
  skip_on_ci()

  # Helper to convert images
  convert <- function(path_in, type_out) {
    img <- magick::image_read(path_in)
    no_ext <- stringr::str_extract(basename(path_in), ".*(?=\\.\\w{3,4}$)")
    filepath <- file.path(tempdir(), glue::glue("{no_ext}.{type_out}"))
    magick::image_write(img, filepath, format = type_out)
    return(filepath)
  }

  # Create images in different formats
  jpg <- testthat::test_path("examples", "image.jpg")
  types <- c("png", "bmp", "tiff", "gif")
  files <- purrr::map_chr(types, ~ convert(jpg, .x))

  # Test each format
  for (file in files) {
    base <- img_to_binbase(file)
    expect_type(base, "character")
    expect_match(base, "^[a-zA-Z0-9+/]+={0,2}$")
  }

  # Cleanup
  unlink(files, force = TRUE)
})

test_that("img_to_binbase() handles edge cases", {
  skip_on_cran()
  skip_on_ci()

  # Nonexistent file
  expect_error(img_to_binbase("nonexistent.jpg"))
})

## INTEGRATION TESTS -----------------------------------------------------------

test_that("conversion functions work together properly", {
  skip_on_cran()
  skip_on_ci()

  # Create a PDF from image
  image <- testthat::test_path("examples", "image.jpg")
  pdf_output <- file.path(tempdir(), "integration_test.pdf")

  image_to_pdf(image, pdf_output)

  # Verify it's a valid PDF
  expect_true(is_pdf(pdf_output))
  expect_false(is_json(pdf_output))

  # Convert to base64
  base64_result <- pdf_to_binbase(pdf_output)
  expect_type(base64_result, "character")
  expect_true(nchar(base64_result) > 0)

  # Original image should also convert to base64
  img_base64 <- img_to_binbase(image)
  expect_type(img_base64, "character")
  expect_true(nchar(img_base64) > 0)

  # Cleanup
  unlink(pdf_output, force = TRUE)
})

test_that("validation functions are consistent", {
  pdf <- testthat::test_path("examples", "sample.pdf")
  image <- testthat::test_path("examples", "image.jpg")
  json <- testthat::test_path("examples", "output.json")

  # PDF file
  expect_true(is_pdf(pdf))
  expect_false(is_json(pdf))

  # Image file
  expect_false(is_pdf(image))
  expect_false(is_json(image))

  # JSON file
  expect_false(is_pdf(json))
  expect_true(is_json(json))
})

## CLEANUP ---------------------------------------------------------------------

unlink(madeup_json_file, force = TRUE)

# Clean up any remaining test files in tempdir
test_files <- list.files(tempdir(),
  pattern = "^(output|dai_temp|integration_test)",
  full.names = TRUE
)
unlink(test_files, force = TRUE)

Try the daiR package in your browser

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

daiR documentation built on Nov. 18, 2025, 5:06 p.m.