tests/testthat/test_autogen.R

# Tests
# RRV: 2017-11-20 for 1.1.1
context("autogen")

# 2020-06-17: this is just a cached spec from a few years ago, updating will require
# refactoring the tests.
spec <- readRDS("data/full_spec.rds")
paths <- spec$paths

# ---- example data from spec

# 1. Parameters: ref.   Responses: ref.
# 2. Parameters: list.  Responses: array ref.
# 3. Parameters: empty array. Responses: array ref.
# 4. Parameters: list.  Responses: none.
# 5. Parameters: list.  Responses: ref.
# 6. Parameters: none.  Responses: list containing arrays.
# 7. Parameters: list.  Responses: infinite reference.
# 8. Parameters: list with ref. Responses: ref.
# 9. Parameters: list with ref and arrays. Responses: list with ref and arrays.
# 10. Parameters: argument with empty list.

ex <- list(paths[["/admin/dump-memory"]]$post,
           paths[["/admin/announcements"]]$get,
           paths[["/admin/organizations"]]$get,
           paths[["/admin/announcements/{id}"]]$delete,
           paths[["/bocce_clusters/{id}/active_jobs"]]$get,
           paths[["/channels/"]]$get,
           paths[["/jobs/{id}/children"]]$get,
           paths[["/admin/announcements/{id}"]]$patch,
           paths[["/scripts/sql"]]$post,
           paths[["/notebooks/{id}"]]$put)



ex_ref <- lapply(ex, replace_ref, spec = spec)
ex_verb_names <- c("post", "get", "get", "delete", "get", "get", "get", "patch", "post", "put", "get", 'get')
ex_path_names <- c("/admin/dump-memory", "/admin/announcements", "/admin/organizations",
                   "/admin/announcements/{id}", "/bocce_clusters/{id}/active_jobs",
                   "/channels/",
                   "/jobs/{id}/children", "/admin/announcements/{id}", "/scripts/sql",
                   "/notebooks/{id}", "/aliases/{object_type}/{alias}", '/databases/{id}/tables-search')
ex_params <- lapply(ex_ref, parse_params)

# ----- test utils

str_detect_multiple <- function(string, pattern) {
  mapply(function(string, pattern) grepl(pattern, string),
    string = string, pattern = pattern)
  }


# ----- function spec ----

test_that("function names are correct", {
  # - test that 'post'/'put'/'patch' are used and not 'create' and 'partial_update'
  # - test that function names are singularized or not
  # - test that '-' is removed
  # - test that 'get'->'list'
  # - test that functions from io and models are correct

  # examples in list
  ex_names <- c("admin_post_dump_memory", "admin_list_announcements",
                "admin_list_organizations", "admin_delete_announcements",
                "bocce_clusters_list_active_jobs", "channels_list",
                "jobs_list_children", "admin_patch_announcements",
                "scripts_post_sql", "notebooks_put",
                'aliases_get_object_type', 'databases_list_tables_search')
  test_names <- mapply(build_function_name, verb_name = ex_verb_names,
                       path_name = ex_path_names)
  expect_equivalent(ex_names, test_names)

  pkg_names <- lsf.str("package:civis")

  # test on examples from io.R, models.R, etc
  sample_names <- c("scripts_post_sql_runs", "tables_list_projects", "notebooks_get", "workflows_get")
  expect_true(all(sample_names %in% pkg_names))
})

test_that("function_args are correct", {
  # - test that args are in correct order
  # - test that optional args have correct string default (currently NULL)
  # - test that args are present
  # - test that args are in snake_case

  ignore_str <- 'NULL'
  ex_arg_str <-
    list(" <- function(host_name = %s) {\n\n",
         " <- function(limit = %s, page_num = %s, order = %s, order_dir = %s) {\n\n",
         " <- function(name, sql, remote_host_id, credential_id, parent_id = %s, user_context = %s, params = %s, arguments = %s, schedule = %s, notifications = %s, next_run_at = %s, time_zone = %s, hidden = %s, target_project_id = %s, csv_settings = %s) {\n\n")
  ex_arg_str <- lapply(ex_arg_str, gsub, pattern = "%s", replacement = ignore_str)
  test_arg_str <- lapply(ex_params[c(1:2, 9)], build_function_args)
  expect_equal(ex_arg_str, test_arg_str)
})


# ----- function body -----
test_that("build_function_body", {
  # - test that path name is correct
  # - test that args are in the form camelCase = snake_case
  # - test api call exactly

  body_lines <- strsplit(build_function_body(ex_ref[[1]], ex_verb_names[[1]],
                                             ex_path_names[[1]], ex_params[[1]]), "\n")[[1]]
  path <- grep("path <- ", body_lines, value = TRUE)
  expect_match(path, ex_path_names[[1]])
  expect_match(grep("body_params", body_lines, value = TRUE)[1],
                                  "hostName = host_name")
  check_call <- paste0("  resp <- call_api(\"", toupper(ex_verb_names[[1]]), "\", ",
                       "path, path_params, query_params, body_params)")
  expect_equal(grep("resp <- ", body_lines, value = TRUE), check_call)
})

# ----- function docs -----

test_that("build_docs", {
  test_doc <- build_docs(ex_ref[[1]])
  expect_match(test_doc, "\\item\\{hostName\\}")
  expect_match(test_doc, "@param host_name")
  expect_match(test_doc, ex_ref[[1]]$summary)
  expect_match(test_doc, "@export")

  test_esc <- build_docs(replace_ref(spec$paths[['/media/dmas']]$get, spec))
  expect_match(test_esc, '\\%"')

  expect_match(build_docs(ex_ref[[4]]),
               "@return  An empty HTTP response\n#' @export\n")

})

test_that("build_params_docs", {

  # single object
  arg_str <- build_params_docs(ex_ref[[1]])
  ex_arg_str <- paste0("@param ",
    camel_to_snake(names(ex_ref[[1]]$parameters[[1]]$schema$properties)))
  expect_match(arg_str, ex_arg_str)
  expect_match(arg_str, "optional")
  expect_match(arg_str,
    ex_ref[[1]]$parameters[[1]]$schema$properties$hostName$description)

  # list of parameters
  arg_str <- strsplit(build_params_docs(ex_ref[[2]]), "\n")[[1]]
  param_lines <- grep("@param", arg_str, value = TRUE)
  check_names <- lapply(ex_ref[[2]]$parameters, function(x) camel_to_snake(x$name))
  check_descr <- lapply(ex_ref[[2]]$parameters, function(x) x$description)
  expect_true(all(str_detect_multiple(param_lines, check_names)))
  # 4 doesn't play well with regex.
  expect_true(all(str_detect_multiple(param_lines[1:3], check_descr[1:3])))

  # single param
  arg_str <- strsplit(build_params_docs(ex_ref[[4]]), "\n")[[1]][1]
  expect_match(arg_str, ex_ref[[4]]$parameters[[1]]$name)
  expect_match(arg_str, ex_ref[[4]]$parameters[[1]]$description)

  # nested object
  ex_param <- ex_ref[[9]]$parameters[[1]]

  #   level 1 arg names and order
  arg_str <- strsplit(build_params_docs(ex_ref[[9]]), "\n")[[1]]
  check <- names(ex_param$schema$properties)
  req <- unlist(ex_param$schema$required)
  check <- c(check[check %in% req], check[!(check %in% req)])
  check_ <- sapply(check, camel_to_snake)
  param_lines <- arg_str[grep("@param", arg_str)]
  expect_true(all(str_detect_multiple(param_lines, check_)))

  #   required/optional strings
  expect_true(all(str_detect_multiple(param_lines[check %in% req],
                                      rep("required", length(req)))))
  expect_true(all(str_detect_multiple(param_lines[!(check %in% req)],
                                      rep("optional", length(check) - length(req)))))

  #   all doc names in fun names: str_match is kind of magical here
  fun_arg_str <- build_function_args(ex_params[[9]])

  param_names <- gsub("@param ", "",
                      unlist(regmatches(param_lines,
                                        gregexpr("@param ([a-z_])*", param_lines))))
  check <- lapply(param_names, function(x) expect_match(fun_arg_str, x))

  #   array args
  expect_match(arg_str[7], "An array containing")
  check <- names(ex_param$schema$properties$params$items$properties)
  expect_true(all(str_detect_multiple(arg_str[9:15], check)))

  #   obj args
  expect_match(arg_str[18], "list optional. A list containing")
  check <-  names(ex_param$schema$properties$schedule$properties)
  expect_true(all(str_detect_multiple(arg_str[20:24], check)))

  # no args
  expect_equal(build_params_docs(ex_ref[[6]]), "")

})

test_that("build_response_docs", {
  resp_str <- strsplit(build_resp_docs(ex_ref[[9]]), "\n")[[1]]
  ex_resp <- ex_ref[[9]]$responses[[1]]

  expect_match(resp_str[1], "@return")

  # level 1 names: case and order
  check <- names(ex_resp$schema$properties)
  expect_true(all(str_detect_multiple(grep("\\item\\{", resp_str, value = T), check)))

  # array
  param_id <- grep("item\\{params\\}", resp_str)
  expect_match(resp_str[param_id], "An array containing")
  check <- names(ex_resp$schema$properties$params$items$properties)
  param_args <- (param_id + 2):(param_id + 1 + length(check))
  expect_true(all(str_detect_multiple(resp_str[param_args], check)))

  # obj
  expect_match(resp_str[7], "A list containing")
  check <- names(ex_resp$schema$properties$author$properties)
  expect_true(all(str_detect_multiple(resp_str[9:13], check)))

  # empty, array, object
  expect_match(build_resp_docs(ex_ref[[4]]), "@return  An empty HTTP response\n")
})

test_that("write_properties", {
  arg_prop <- get_obj_properties(ex_ref[[9]]$parameters[[1]])
  resp_prop <- get_obj_properties(ex_ref[[9]]$responses[[1]])

  arg_prop_str <- strsplit(
    write_properties(arg_prop, req_str = "required",
                     transform_name = camel_to_snake), "\n")[[1]]
  resp_prop_str <- strsplit(
    write_properties(resp_prop, fmt = "#' \\item{%s}{%s, %s%s}"), "\n")[[1]]

  # level 1 names, fmt, transform_name
  check <- sapply(names(arg_prop), camel_to_snake)
  expect_true(all(str_detect_multiple(grep("@param", arg_prop_str, value = TRUE), check)))

  check <- names(resp_prop)
  expect_true(all(
    str_detect_multiple(grep("\\item\\{", resp_prop_str, value = TRUE), check)))

  # req_str: write_properties doesn't get correct req_str, so just make sure it can be provided
  param_lines <- grep("@param", arg_prop_str, value = TRUE)
  expect_true(all(str_detect_multiple(param_lines, rep("req", length(param_lines)))))

  # test non-nested prop is not an array or list
  expect_true(!grepl("(array|list)", arg_prop_str[1]))

  # array
  expect_match(arg_prop_str[4], "An array containing")
  check_names <- names(arg_prop$params$items$properties)
  expect_true(all(str_detect_multiple(arg_prop_str[6:12], check_names)))

  check_descr <- lapply(arg_prop$params$items$properties, function(x) x$description)
  expect_true(all(str_detect_multiple(arg_prop_str[6:12], check_descr)))

  # obj
  expect_match(resp_prop_str[6], "A list containing")
  check_names <- names(resp_prop$author$properties)
  expect_true(all(str_detect_multiple(resp_prop_str[8:12], check_names)))

  check_descr <- lapply(resp_prop$author$properties, function(x) x$description)
  expect_true(all(str_detect_multiple(resp_prop_str[8:12], check_descr)))

  # not nested
  arg_prop <- get_obj_properties(ex_ref[[1]]$parameters[[1]])
  arg_prop_str <- write_properties(arg_prop, transform_name = camel_to_snake)
  check_name <- paste0("@param ", camel_to_snake(names(arg_prop)))
  check_descr <- arg_prop$hostName$description
  expect_match(arg_prop_str, check_name)
  expect_match(arg_prop_str, check_descr)
})

test_that("write_nested_docs", {
  # nested array
  ex_prop <- get_array_properties(ex_ref[[6]]$responses[[1]])
  ex_array <- ex_prop[[which(sapply(ex_prop, is_array))]]
  array_str <- strsplit(write_nested_docs(ex_array), "\n")[[1]]
  expect_match(array_str[1], "An array containing")

  item_lines <- grep("\\item ", array_str, value = TRUE)
  check_name <- names(ex_array$items$properties)
  check_descr <- ex_array$items$properties$name$description
  expect_match(item_lines, check_name)
  expect_match(item_lines, check_descr)

  # nested obj
  ex_prop <- get_obj_properties(ex_ref[[9]]$responses[[1]])
  ex_obj <- ex_prop[[which(sapply(ex_prop, is_obj))[2]]]
  obj_str <- strsplit(write_nested_docs(ex_obj), "\n")[[1]]
  expect_match(obj_str[1], "A list containing")

  item_lines <- grep("\\item ", obj_str, value = TRUE)
  check_names <- names(ex_obj$properties)
  check_descr <- lapply(ex_obj$properties, function(x) x$description)
  expect_true(all(str_detect_multiple(item_lines, check_names)))
  expect_true(all(str_detect_multiple(item_lines, check_descr)))
})

# ----- parse_params -----
test_that("parse_params", {
  # object
  param <- ex_ref[[1]]$parameters[[1]]
  check <- data.frame(name = names(param$schema$properties),
                      http_location = param$`in`,
                      required = param$required,
                      description = param$schema$properties$hostName$description,
                      type = param$schema$properties$hostName$type,
                      stringsAsFactors = FALSE)
  expect_equal(ex_params[[1]], check)

  # list
  param <- ex_ref[[2]]$parameters
  check <- do.call(rbind,
    lapply(ex_ref[[2]]$parameters, as.data.frame, stringsAsFactors = FALSE))
  colnames(check) <- c("name", "http_location", "required", "description", "type")
  expect_equivalent(ex_params[[2]], check) # ignore attributes

  # length 1
  param <- ex_ref[[4]]$parameters[[1]]
  check <- data.frame(param, stringsAsFactors = FALSE)
  colnames(check) <- c("name", "http_location", "required", "description", "type")
  expect_equivalent(ex_params[[4]], check)

  # empty
  param <- data.frame(ex_ref[[6]]$parameters, stringsAsFactors = FALSE)
  expect_equal(ex_params[[6]], param)

  # nested object (just get level 1)
  param <- ex_ref[[9]]$parameters[[1]]
  prop <- param$schema$properties
  name <- names(prop)
  http_location <- rep(param$`in`, length(prop))
  required <- name %in% param$schema$required
  desc <- unlist(lapply(prop, function(p) get_descr_str(p)))
  type <- unlist(lapply(prop, function(p) p$type))
  check <- data.frame(name = name,
                      http_location = http_location,
                      required = required,
                      description = unlist(desc),
                      type = type, stringsAsFactors = FALSE)
  check <- check[order(check$required, decreasing = TRUE), ]
  expect_equivalent(ex_params[[9]], check)
})

# ----- references -----
test_that("is_ref", {
  expect_true(all(sapply(ex[c(1, 5, 8)],
                         function(x) is_ref(x$responses[[1]]$schema))))
  expect_true(all(sapply(ex[c(2:3, 6)],
                         function(x) is_ref(x$responses[[1]]$schema$items))))
  expect_true(!is_ref(ex[[4]]$responses[[1]]))
})

test_that("get_ref", {
  expect_equal(spec$definitions$Object1,
               get_ref(ex[[1]]$responses[[1]]$schema, spec))
})

test_that("replace_ref", {
  # --- works for parameters and responses
  ex_ref <- lapply(ex, replace_ref, spec = spec)
  for (i in 1:9) expect_true(!any(grepl("#/definitions", ex_ref[[i]])))
})

# ----- utils
test_that("is_nested", {
  expect_true(is_nested(ex_ref[[9]]$parameters[[1]]))
  expect_true(is_nested(ex_ref[[9]]$responses[[1]]))
  expect_true(is_nested(ex_ref[[9]]$parameters[[1]]$schema$properties$params))
  expect_true(is_nested(ex_ref[[9]]$responses[[1]]$schema$properties$author))
  expect_false(is_nested(ex_ref[[9]]$parameters[[1]]$schema$properties$name))
  expect_false(is_nested(ex_ref[[2]]$parameters[[1]]))
})

test_that("is_array", {
  expect_true(is_array(ex_ref[[9]]$parameters[[1]]$schema$properties$params))
  expect_false(is_array(ex_ref[[9]]$parameters[[1]]$schema$properties$schedule))
  expect_false(is_array(ex_ref[[9]]$parameters[[1]]$schema$properties$name))
})

test_that("is_obj", {
  expect_true(is_obj(ex_ref[[9]]$parameters[[1]]$schema$properties$schedule))
  expect_false(is_obj(ex_ref[[9]]$parameters[[1]]$schema$properties$params))
  expect_false(is_obj(ex_ref[[9]]$parameters[[1]]$schema$properties$name))
})

test_that("get_descr_str", {
  expect_equal(get_descr_str(ex_ref[[1]]$parameters[[1]]$schema$properties$hostName),
               ex_ref[[1]]$parameters[[1]]$schema$properties$hostName$description)
  expect_equal(get_descr_str(ex_ref[[1]]$parameters[[1]]), "")
})

test_that("get_req_str", {
  expect_equal(get_req_str(ex_ref[[1]]$parameters[[1]]), "optional")
  expect_equal(get_req_str(ex_ref[[6]]$parameters), "")
})

test_that("returns_array", {
  expect_false(
    returns_array(ex_ref[[1]], verb_name = ex_verb_names[[1]],
                  path_name = ex_path_names[[1]]))
  expect_true(
    returns_array(ex_ref[[2]], verb_name = ex_verb_names[[2]],
                  path_name = ex_path_names[[2]]))
})

test_that("escape_percent", {
  expect_equal(escape_percent("%"), "\\%")
})

test_that("camel_to_snake", {
  expect_equal(camel_to_snake("TinaEatYourFood"), "tina_eat_your_food")
})

Try the civis package in your browser

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

civis documentation built on April 1, 2023, 12:01 a.m.