# sq_escape() and sq_unescape() ----
test_that("sq_escape() and sq_unescape() pass NULL through", {
  expect_null(sq_escape(NULL))
  expect_null(sq_unescape(NULL))
})

test_that("sq_escape() does nothing if string already single-quoted", {
  x <- c("'abc'", "'ab'c'", "''")
  expect_identical(sq_escape(x), x)
})

test_that("sq_escape() duplicates single quotes and adds to start, end", {
  expect_identical(
    sq_escape(c("abc", "'abc", "abc'", "'a'bc", "'")),
    c("'abc'", "'''abc'", "'abc'''", "'''a''bc'", "''''")
  )
})

test_that("sq_unescape() does nothing if string is not single-quoted", {
  x <- c("abc", "'abc", "abc'", "a'bc", "'a'bc")
  expect_identical(sq_unescape(x), x)
})

test_that("sq_unescape() strips outer single quotes, de-duplicates inner", {
  expect_identical(
    sq_unescape(c("'abc'", "'''abc'", "'abc'''", "'''a''bc'", "''''")),
    c("abc", "'abc", "abc'", "'a'bc", "'")
  )
})

# qualified_A1() ----
test_that("qualified_A1 works", {
  expect_null(qualified_A1())
  expect_identical(qualified_A1("foo"), "'foo'")
  expect_identical(qualified_A1("foo", "A1"), "'foo'!A1")
  expect_identical(qualified_A1("'foo'"), "'foo'")
  expect_identical(qualified_A1(cell_range = "A1"), "A1")
})

# lookup_sheet_name() ----
test_that("lookup_sheet_name() requires sheet to be length-1 character or numeric", {
  expect_error(lookup_sheet_name(c("a", "b")), "length 1")
  expect_error(lookup_sheet_name(1:2), "length 1")
  expect_error(lookup_sheet_name(TRUE), "must be either")
})

test_that("lookup_sheet_name() errors if number is incompatible with sheet names", {
  sheets_df <- tibble::tibble(name = c("a", "foo", "z"))
  expect_error(lookup_sheet_name(4, sheets_df), "out-of-bounds")
  expect_error(lookup_sheet_name(0, sheets_df), "out-of-bounds")
})

test_that("lookup_sheet_name() consults sheet names, if given", {
  sheets_df <- tibble::tibble(name = c("a", "foo", "z"))
  expect_identical(lookup_sheet_name("foo", sheets_df), "foo")
  expect_error(
    lookup_sheet_name("nope", sheets_df),
    class = "googlesheets4_error_sheet_not_found"
  )
})

test_that("lookup_sheet_name() works with a number", {
  sheets_df <- tibble::tibble(name = c("a", "foo", "z"))
  expect_identical(lookup_sheet_name(2, sheets_df), "foo")
})

# resolve_limits() ----
test_that("resolve_limits() leaves these cases unchanged", {
  expect_no_change <- function(cl) expect_identical(resolve_limits(cl), cl)

  expect_no_change(cell_limits(c(2, 2), c(3, 3)))
  expect_no_change(cell_limits(c(NA, NA), c(NA, NA)))
  expect_no_change(cell_limits(c(2, NA), c(3, NA)))
  expect_no_change(cell_limits(c(NA, 2), c(NA, 3)))
  expect_no_change(cell_limits(c(2, 2), c(3, NA)))
  expect_no_change(cell_limits(c(2, 2), c(NA, 3)))
})

test_that("resolve_limits() completes a row- or column-only range", {
  expect_identical(
    resolve_limits(cell_limits(c(2, NA), c(NA, NA))),
    cell_limits(c(2, NA), c(10000000, NA))
  )
  expect_identical(
    # I now think it's a bug that cell_limits() fills in this start row
    resolve_limits(cell_limits(c(NA, NA), c(3, NA))),
    cell_limits(c(1, NA), c(3, NA))
  )
  expect_identical(
    resolve_limits(cell_limits(c(NA, 2), c(NA, NA))),
    cell_limits(c(NA, 2), c(NA, 18278))
  )
  expect_identical(
    # I now think it's a bug that cell_limits() fills in this start column
    resolve_limits(cell_limits(c(NA, NA), c(NA, 3))),
    cell_limits(c(NA, 1), c(NA, 3))
  )
})

test_that("resolve_limits() completes upper left cell", {
  expect_identical(
    resolve_limits(cell_limits(c(2, NA), c(NA, 3))),
    cell_limits(c(2, 1), c(NA, 3))
  )
  expect_identical(
    resolve_limits(cell_limits(c(NA, 2), c(3, NA))),
    cell_limits(c(1, 2), c(3, NA))
  )
  expect_identical(
    resolve_limits(cell_limits(c(NA, NA), c(3, 3))),
    cell_limits(c(1, 1), c(3, 3))
  )
  expect_identical(
    resolve_limits(cell_limits(c(2, NA), c(3, 3))),
    cell_limits(c(2, 1), c(3, 3))
  )
  expect_identical(
    resolve_limits(cell_limits(c(NA, 2), c(3, 3))),
    cell_limits(c(1, 2), c(3, 3))
  )
})

test_that("resolve_limits() populates column of lower right cell", {
  expect_identical(
    resolve_limits(cell_limits(c(2, 2), c(NA, NA))),
    cell_limits(c(2, 2), c(NA, 18278))
  )
})

# as_sheets_range ----

## "case numbers" refer to output produced by:
# tidyr::crossing(
#   start_row = c(NA, "start_row"), start_col = c(NA, "start_col"),
#   end_row = c(NA, "end_row"), end_col = c(NA, "end_col")
# )

test_that("as_sheets_range() works when all limits are given", {
  #  1 start_row start_col end_row end_col
  expect_identical(
    as_sheets_range(cell_limits(c(2, 2), c(3, 3))),
    "B2:C3"
  )
})

test_that("as_sheets_range() returns NULL when all limits are NA", {
  # 16 NA        NA        NA      NA
  expect_null(as_sheets_range(cell_limits()))
})

test_that("as_sheets_range() deals with row-only range", {
  #  6 start_row NA        end_row NA
  expect_identical(
    as_sheets_range(cell_limits(c(2, NA), c(3, NA))),
    "2:3"
  )
})

test_that("as_sheets_range() deals with column-only range", {
  # 11 NA        start_col NA      end_col
  expect_identical(
    as_sheets_range(cell_limits(c(NA, 2), c(NA, 3))),
    "B:C"
  )
})

test_that("as_sheets_range() deals when one of lr limits is missing", {
  #  2 start_row start_col end_row NA
  #  3 start_row start_col NA      end_col
  expect_identical(
    as_sheets_range(cell_limits(c(2, 2), c(3, NA))),
    "B2:3"
  )
  expect_identical(
    as_sheets_range(cell_limits(c(2, 2), c(NA, 3))),
    "B2:C"
  )
})

# TODO: I disabled this when switching to testthat 3e
# removing the mock of cellranger::cell_limits() didn't seem to hurt anything,
# which seems odd
#
# I have to think about cellranger soon, so revisit this when that happens
#
# commenting out, not skipping, because this is the only with_mock()

#test_that("as_sheets_range() errors for limits that should be fixed by resolve_limits()", {
  # I think cellranger::cell_limits() should do much less.
  # Already planning here for such a change there.
  # Here's a very crude version of what I have in mind.
  # cl <- function(ul, lr) {
  #   structure(
  #     list(ul = as.integer(ul), lr = as.integer(lr), sheet = NA_character_),
  #     class = c("cell_limits", "list")
  #   )
  # }
#   with_mock(
#     resolve_limits = function(x) x,
#     `cellranger:::cell_limits` = function(ul, lr, sheet) cl(ul, lr), {
#       #  5 start_row NA        end_row end_col
#       expect_error(as_sheets_range(cell_limits(c(2, NA), c(3, 3))))
#       #  9 NA        start_col end_row end_col
#       expect_error(as_sheets_range(cell_limits(c(NA, 2), c(3, 3))))
#       # 13 NA        NA        end_row end_col
#       expect_error(as_sheets_range(cell_limits(c(NA, NA), c(3, 3))))
#       #  8 start_row NA        NA      NA
#       expect_error(as_sheets_range(cell_limits(c(2, NA), c(NA, NA))))
#       # 14 NA        NA        end_row NA
#       expect_error(as_sheets_range(cell_limits(c(NA, NA), c(2, NA))))
#       # 12 NA        start_col NA      NA
#       expect_error(as_sheets_range(cell_limits(c(NA, 2), c(NA, NA))))
#       # 15 NA        NA        NA      end_col
#       expect_error(as_sheets_range(cell_limits(c(NA, NA), c(NA, 3))))
#       # 10 NA        start_col end_row NA
#       expect_error(as_sheets_range(cell_limits(c(NA, 2), c(3, NA))))
#       #  7 start_row NA        NA      end_col
#       expect_error(as_sheets_range(cell_limits(c(2, NA), c(NA, 3))))
#       #  4 start_row start_col NA      NA
#       expect_error(as_sheets_range(cell_limits(c(2, 2), c(NA, NA))))
#     }
#   )
# })
