tests/testthat/test-deparse.R

test_that("line_push() adds indentation", {
  out <- line_push("foo", "bar", width = 4, indent = 2)
  expect_identical(out, c("foo", "  bar"))
})

test_that("line_push() doesn't make a new line if current is only spaces", {
  expect_identical(line_push("    ", "foo", width = 2L), "    foo")
})

test_that("line_push() trims trailing spaces", {
  expect_identical(line_push("foo  ", "bar", width = 1L), c("foo", "bar"))
})

test_that("line_push() doesn't trim trailing spaces on sticky inputs", {
  expect_identical(line_push("tag", " = ", sticky = TRUE, width = 3L, indent = 2L), "tag = ")
})

test_that("sticky input sticks", {
  expect_identical(line_push("foo  ", "bar", sticky = TRUE, width = 1L), "foo  bar")
})

test_that("line_push() respects boundaries", {
  expect_identical(line_push("foo, ", "bar", boundary = 4L, width = 1L, indent = 2L), c("foo,", "  bar"))
  expect_identical(line_push("foo, ", "bar", sticky = TRUE, boundary = 4L, width = 1L, indent = 2L), c("foo,", "  bar"))
  expect_identical(line_push("foo, bar", "baz", boundary = 4L, width = 1L, indent = 2L), c("foo, bar", "  baz"))
})

test_that("line_push() handles the nchar(line) == boundary case", {
  expect_identical(line_push("  tag = ", "bar", sticky = TRUE, boundary = 8L, width = 3L, indent = 2L), "  tag = bar")
})

test_that("line_push() strips ANSI codes before computing overflow", {
  local_options(cli.num_colors = 8L)
  if (!has_ansi()) {
    skip("test needs cli")
  }
  expect_identical(length(line_push("foo", open_blue(), width = 3L)), 2L)
  expect_identical(length(line_push("foo", open_blue(), width = 3L, has_colour = TRUE)), 1L)
})

test_that("can push several lines (useful for default base deparser)", {
  expect_identical(new_lines()$push(c("foo", "bar"))$get_lines(), "foobar")
})

test_that("control flow is deparsed", {
  expect_identical(fn_call_deparse(expr(function(a, b) 1)), "function(a, b) 1")
  expect_identical(fn_call_deparse(expr(function(a = 1, b = 2) { 3; 4; 5 })), c("function(a = 1, b = 2) {", "  3", "  4", "  5", "}"))
  expect_identical(while_deparse(quote(while(1) 2)), "while (1) 2")
  expect_identical(for_deparse(quote(for(a in 2) 3)), "for (a in 2) 3")
  expect_identical(repeat_deparse(quote(repeat 1)), "repeat 1")
  expect_identical(if_deparse(quote(if (1) 2 else { 3 })), c("if (1) 2 else {", "  3", "}"))
})

test_that("functions defs increase indent", {
  ctxt <- new_lines(width = 3L)
  expect_identical(sexp_deparse(quote(function() 1), ctxt), c("function()", "  1"))

  ctxt <- new_lines(width = 3L)
  expect_identical(sexp_deparse(function() 1, ctxt), c("<function()", "  1>"))
})

test_that("blocks are deparsed", {
  expect_identical(braces_deparse(quote({1; 2; { 3; 4 }})), c("{", "  1", "  2", "  {", "    3", "    4", "  }", "}"))
  expect_identical_(sexp_deparse(quote({{ 1 }})), c("{", "  {", "    1", "  }", "}"))

  ctxt <- new_lines(width = 3L)
  expected_lines <- c("{", "  11111", "  22222", "  {", "    33333", "    44444", "  }", "}")
  expect_identical(braces_deparse(quote({11111; 22222; { 33333; 44444 }}), ctxt), expected_lines)
})

test_that("multiple openers on the same line only trigger one indent", {
  ctxt <- new_lines(width = 3L)
  expect_identical(sexp_deparse(quote(function() { 1 }), ctxt), c("function()", "  {", "    1", "  }"))

  ctxt <- new_lines(width = 12L)
  expect_identical(sexp_deparse(quote(function() { 1 }), ctxt), c("function() {", "  1", "}"))
})

test_that("multiple openers on the same line are correctly reset", {
  expect_identical(sexp_deparse(quote({ 1(2()) })), c("{", "  1(2())", "}"))
})

test_that("parentheses are deparsed", {
  expect_identical(parens_deparse(quote((1))), "(1)")
  expect_identical(parens_deparse(quote(({ 1; 2 }))), c("({", "  1", "  2", "})"))
  expect_identical(sexp_deparse(quote(({({ 1 })}))), c("({", "  ({", "    1", "  })", "})"))
})

test_that("spaced operators are deparsed", {
  expect_identical(spaced_op_deparse(quote(1 ? 2)), "1 ? 2")
  expect_identical(spaced_op_deparse(quote(1 <- 2)), "1 <- 2")
  expect_identical(spaced_op_deparse(quote(1 <<- 2)), "1 <<- 2")
  expect_identical(spaced_op_deparse(quote(`=`(1, 2))), "1 = 2")
  expect_identical(spaced_op_deparse(quote(1 := 2)), "1 := 2")
  expect_identical(spaced_op_deparse(quote(1 ~ 2)), "1 ~ 2")
  expect_identical(spaced_op_deparse(quote(1 | 2)), "1 | 2")
  expect_identical(spaced_op_deparse(quote(1 || 2)), "1 || 2")
  expect_identical(spaced_op_deparse(quote(1 & 2)), "1 & 2")
  expect_identical(spaced_op_deparse(quote(1 && 2)), "1 && 2")
  expect_identical(spaced_op_deparse(quote(1 > 2)), "1 > 2")
  expect_identical(spaced_op_deparse(quote(1 >= 2)), "1 >= 2")
  expect_identical(spaced_op_deparse(quote(1 < 2)), "1 < 2")
  expect_identical(spaced_op_deparse(quote(1 <= 2)), "1 <= 2")
  expect_identical(spaced_op_deparse(quote(1 == 2)), "1 == 2")
  expect_identical(spaced_op_deparse(quote(1 != 2)), "1 != 2")
  expect_identical(spaced_op_deparse(quote(1 + 2)), "1 + 2")
  expect_identical(spaced_op_deparse(quote(1 - 2)), "1 - 2")
  expect_identical(spaced_op_deparse(quote(1 * 2)), "1 * 2")
  expect_identical(spaced_op_deparse(quote(1 / 2)), "1 / 2")
  expect_identical(spaced_op_deparse(quote(1 %% 2)), "1 %% 2")
  expect_identical(spaced_op_deparse(quote(1 %>% 2)), "1 %>% 2")
  expect_identical(sexp_deparse(quote({ 1; 2 } + { 3; 4 })), c("{", "  1", "  2", "} + {", "  3", "  4", "}"))
})

test_that("unspaced operators are deparsed", {
  expect_identical(unspaced_op_deparse(quote(1:2)), "1:2")
  expect_identical(unspaced_op_deparse(quote(1^2)), "1^2")
  expect_identical(unspaced_op_deparse(quote(a$b)), "a$b")
  expect_identical(unspaced_op_deparse(quote(a@b)), "a@b")
  expect_identical(unspaced_op_deparse(quote(a::b)), "a::b")
  expect_identical(unspaced_op_deparse(quote(a:::b)), "a:::b")
})

test_that("operands are wrapped in parentheses to ensure correct predecence", {
  expect_identical_(sexp_deparse(expr(1 + !!quote(2 + 3))), "1 + (2 + 3)")
  expect_identical_(sexp_deparse(expr((!!quote(1^2))^3)), "(1^2)^3")

  skip_on_cran()
  skip_if(getRversion() < "4.0.0")
  expect_identical_(sexp_deparse(quote(function() 1 ? 2)), "(function() 1) ? 2")
  expect_identical_(sexp_deparse(expr(!!quote(function() 1) ? 2)), "(function() 1) ? 2")
})

test_that("unary operators are deparsed", {
  expect_identical(unary_op_deparse(quote(?1)), "?1")
  expect_identical(unary_op_deparse(quote(~1)), "~1")
  expect_identical(unary_op_deparse(quote(!1)), "!1")
  expect_identical_(unary_op_deparse(quote(!!1)), "!!1")
  expect_identical_(unary_op_deparse(quote(!!!1)), "!!!1")
  expect_identical_(unary_op_deparse(quote(`!!`(1))), "!!1")
  expect_identical_(unary_op_deparse(quote(`!!!`(1))), "!!!1")
  expect_identical(unary_op_deparse(quote(+1)), "+1")
  expect_identical(unary_op_deparse(quote(-1)), "-1")
})

test_that("brackets are deparsed", {
  expect_identical(sexp_deparse(quote(1[2])), c("1[2]"))
  expect_identical(sexp_deparse(quote(1[[2]])), c("1[[2]]"))

  ctxt <- new_lines(width = 1L)
  expect_identical(sexp_deparse(quote(1[2]), ctxt), c("1[", "  2]"))
  ctxt <- new_lines(width = 1L)
  expect_identical(sexp_deparse(quote(1[[2]]), ctxt), c("1[[", "  2]]"))
})

test_that("calls are deparsed", {
  expect_identical(call_deparse(quote(foo(bar, baz))), "foo(bar, baz)")
  expect_identical(call_deparse(quote(foo(one = bar, two = baz))), "foo(one = bar, two = baz)")
})

test_that("call_deparse() respects boundaries", {
  ctxt <- new_lines(width = 1L)
  expect_identical(call_deparse(quote(foo(bar, baz)), ctxt), c("foo(", "  bar,", "  baz)"))

  ctxt <- new_lines(width = 7L)
  expect_identical(call_deparse(quote(foo(bar, baz)), ctxt), c("foo(", "  bar,", "  baz)"))

  ctxt <- new_lines(width = 8L)
  expect_identical(call_deparse(quote(foo(bar, baz)), ctxt), c("foo(bar,", "  baz)"))

  ctxt <- new_lines(width = 1L)
  expect_identical(call_deparse(quote(foo(one = bar, two = baz)), ctxt), c("foo(", "  one = bar,", "  two = baz)"))
})

test_that("call_deparse() handles multi-line arguments", {
  ctxt <- new_lines(width = 1L)
  expect_identical(sexp_deparse(quote(foo(one = 1, two = nested(one = 1, two = 2))), ctxt), c("foo(", "  one = 1,", "  two = nested(", "    one = 1,", "    two = 2))"))

  ctxt <- new_lines(width = 20L)
  expect_identical(sexp_deparse(quote(foo(one = 1, two = nested(one = 1, two = 2))), ctxt), c("foo(one = 1, two = nested(", "  one = 1, two = 2))"))
})

test_that("call_deparse() delimits CAR when needed", {
  fn_call <- quote(function() x + 1)
  call <- expr((!!fn_call)())
  expect_identical(call_deparse(call), "(function() x + 1)()")

  roundtrip <- parse_expr(expr_deparse(call))
  exp <- call2(call("(", fn_call))

  # Zap srcref to work around https://github.com/r-lib/waldo/issues/59
  expect_equal(zap_srcref(roundtrip), zap_srcref(exp))

  call <- expr((!!quote(f + g))(x))
  expect_identical(call_deparse(call), "`+`(f, g)(x)")
  expect_identical(parse_expr(expr_deparse(call)), call)

  call <- expr((!!quote(+f))(x))
  expect_identical(call_deparse(call), "`+`(f)(x)")
  expect_identical(parse_expr(expr_deparse(call)), call)

  call <- expr((!!quote(while (TRUE) NULL))(x))
  expect_identical(call_deparse(call), "`while`(TRUE, NULL)(x)")
  expect_identical(parse_expr(expr_deparse(call)), call)

  call <- expr(foo::bar(x))
  expect_identical(call_deparse(call), "foo::bar(x)")
  expect_identical(parse_expr(expr_deparse(call)), call)
})

test_that("literal functions are deparsed", {
  expect_identical_(sexp_deparse(function(a) 1), "<function(a) 1>")
  expect_identical_(sexp_deparse(expr(foo(!!function(a) 1))), "foo(<function(a) 1>)")
})

test_that("literal dots are deparsed", {
  dots <- (function(...) env_get(, "..."))(NULL)
  expect_identical_(sexp_deparse(expr(foo(!!dots))), "foo(<...>)")
})

test_that("environments are deparsed", {
  expect_identical(sexp_deparse(expr(foo(!! env()))), "foo(<environment>)")
})

test_that("atomic vectors are deparsed", {
  expect_identical(sexp_deparse(set_names(c(TRUE, FALSE, TRUE), c("", "b", ""))), "<lgl: TRUE, b = FALSE, TRUE>")
  expect_identical(sexp_deparse(set_names(1:3, c("", "b", ""))), "<int: 1L, b = 2L, 3L>")
  expect_identical(sexp_deparse(set_names(c(1, 2, 3), c("", "b", ""))), "<dbl: 1, b = 2, 3>")
  expect_identical(sexp_deparse(set_names(as.complex(1:3), c("", "b", ""))), "<cpl: 1+0i, b = 2+0i, 3+0i>")
  expect_identical(sexp_deparse(set_names(as.character(1:3), c("", "b", ""))), "<chr: \"1\", b = \"2\", \"3\">")
  expect_identical(sexp_deparse(set_names(as.raw(1:3), c("", "b", ""))), "<raw: 01, b = 02, 03>")
})

test_that("boundaries are respected when deparsing vectors", {
  ctxt <- new_lines(width = 1L)
  vec <- set_names(1:3, c("", "b", ""))
  expect_identical_(sexp_deparse(expr(foo(!!vec)), ctxt), c("foo(", "  <int:", "    1L,", "    b = 2L,", "    3L>)"))

  ctxt <- new_lines(width = 12L)
  expect_identical(sexp_deparse(list(c("foo", "bar", "baz")), ctxt), c("<list: <chr:", "  \"foo\",", "  \"bar\",", "  \"baz\">>"))
})

test_that("scalar atomic vectors are simply printed", {
  expect_identical(sexp_deparse(TRUE), "TRUE")
  expect_identical(sexp_deparse(1L), "1L")
  expect_identical(sexp_deparse(1), "1")
  expect_identical(sexp_deparse(1i), "0+1i")
  expect_identical(sexp_deparse("1"), "\"1\"")
})

test_that("scalar raw vectors are printed in long form", {
  expect_identical(sexp_deparse(as.raw(1)), "<raw: 01>")
})

test_that("literal lists are deparsed", {
  expect_identical(sexp_deparse(list(TRUE, b = 2L, 3, d = "4", as.raw(5))), "<list: TRUE, b = 2L, 3, d = \"4\", <raw: 05>>")
})

test_that("long vectors are truncated by default", {
  expect_identical(sexp_deparse(1:10), "<int: 1L, 2L, 3L, 4L, 5L, ...>")
  expect_identical(sexp_deparse(as.list(1:10)), "<list: 1L, 2L, 3L, 4L, 5L, ...>")
})

test_that("long vectors are truncated when max_elements = 0L", {
  lines <- new_lines(max_elements = 0L)
  expect_identical(sexp_deparse(1:10, lines), "<int: ...>")

  lines <- new_lines(max_elements = 0L)
  expect_identical(sexp_deparse(as.list(1:10), lines), "<list: ...>")
})

test_that("long vectors are not truncated when max_elements = NULL", {
  lines <- new_lines(max_elements = NULL)
  expect_identical(sexp_deparse(1:10, lines), "<int: 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L>")

  lines <- new_lines(max_elements = NULL)
  expect_identical(sexp_deparse(as.list(1:10), lines), "<list: 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L>")
})

test_that("other objects are deparsed with base deparser", {
  expect_identical_(sexp_deparse(expr(foo((!!base::list)(1, 2)))), "foo(.Primitive(\"list\")(1, 2))")
  expect_identical_(sexp_deparse(expr(foo((!!base::`if`)(1, 2)))), "foo(.Primitive(\"if\")(1, 2))")
})

test_that("S3 objects are deparsed", {
  skip_on_cran()
  expr <- expr(list(!!factor(1:3), !!structure(list(), class = c("foo", "bar", "baz"))))
  expect_identical(sexp_deparse(expr), "list(<fct>, <foo>)")
})

test_that("successive indentations on a single line are only counted once", {
  ctxt <- new_lines(5L)
  broken_output <- c("<list:", "  <chr:", "    foo = \"bar\",", "    baz = \"bam\">>")
  expect_identical(sexp_deparse(list(c(foo = "bar", baz = "bam")), ctxt), broken_output)

  ctxt <- new_lines(12L)
  unbroken_output <- c("<list: <chr:", "  foo = \"bar\",", "  baz = \"bam\">>")
  expect_identical(sexp_deparse(list(c(foo = "bar", baz = "bam")), ctxt), unbroken_output)
})

test_that("successive indentations close off properly", {
  expect_identical(sexp_deparse(quote(1(2(), 3(4())))), "1(2(), 3(4()))")
  expect_identical(sexp_deparse(quote(1(2(), 3(4()))), new_lines(width = 1L)), c("1(", "  2(),", "  3(", "    4()))"))
  expect_identical(sexp_deparse(expr(c((1), function() { 2 }))), c("c((1), function() {", "  2", "})"))
})

test_that("empty quosures are deparsed", {
  expect_identical(strip_style(quo_deparse(quo())), "^")
})

test_that("missing values are deparsed", {
  expect_identical(expr_deparse(NA), "NA")
  expect_identical(expr_deparse(NaN), "NaN")
  expect_identical(expr_deparse(NA_integer_), "NA_integer_")
  expect_identical(expr_deparse(NA_real_), "NA_real_")
  expect_identical(expr_deparse(NA_complex_), "NA_complex_")
  expect_identical(expr_deparse(NA_character_), "NA_character_")

  expect_identical(expr_deparse(c(NaN, 2, NA)), "<dbl: NaN, 2, NA>")
  expect_identical(expr_deparse(c(foo = NaN)), "<dbl: foo = NaN>")
  expect_identical(sexp_deparse(c(name = NA)), "<lgl: name = NA>")

  expect_identical(sexp_deparse(c(NA, "NA")), "<chr: NA, \"NA\">")

  expect_identical(sexp_deparse(quote(call(NA))), "call(NA)")
  expect_identical(sexp_deparse(quote(call(NA_integer_))), "call(NA_integer_)")
  expect_identical(sexp_deparse(quote(call(NA_real_))), "call(NA_real_)")
  expect_identical(sexp_deparse(quote(call(NA_complex_))), "call(NA_complex_)")
  expect_identical(sexp_deparse(quote(call(NA_character_))), "call(NA_character_)")
})

test_that("needs_backticks() detects non-syntactic symbols", {
  expect_true(all(map_lgl(reserved_words, needs_backticks)))

  expect_false(any(map_lgl(c(".", "a", "Z"), needs_backticks)))

  expect_true(all(map_lgl(c("1", ".1", "~", "!"), needs_backticks)))
  expect_true(all(map_lgl(c("_", "_foo", "1foo"), needs_backticks)))
  expect_true(all(map_lgl(c(".fo!o", "b&ar", "baz <- _baz", "~quux.", "h~unoz_"), needs_backticks)))

  expect_false(any(map_lgl(c(".foo", "._1", "bar", "baz_baz", "quux.", "hunoz_", "..."), needs_backticks)))

  expect_false(needs_backticks(expr()))
})

test_that("expr_text() and expr_name() interpret unicode tags (#611)", {
  expect_identical(expr_text(quote(`<U+006F>`)), "o")
  expect_identical(expr_name(quote(`~f<U+006F><U+006F>`)), "~foo")
  expect_identical(as_label(quote(`~f<U+006F><U+006F>`)), "~foo")
})

test_that("expr_text() deparses non-syntactic symbols with backticks (#211)", {
  expect_identical(expr_text(sym("~foo")), "`~foo`")
  expect_identical(expr_text(sym("~f<U+006F><U+006F>")), "`~foo`")
  expect_identical(expr_text(call("~foo")), "`~foo`()")
})

test_that("expr_text() deparses empty arguments", {
  expect_identical(expr_text(expr()), "")
  expect_identical(quo_text(expr()), "")
  expect_identical(quo_text(quo()), "")
})

test_that("expr_name() deparses empty arguments", {
  expect_identical(expr_name(expr()), "")
  expect_identical(quo_name(quo()), "")
  expect_identical(names(quos_auto_name(quos(, ))), "<empty>")
  expect_identical(as_label(expr()), "<empty>")
})

test_that("expr_deparse() handles newlines in strings (#484)", {
  x <- "foo\n"

  expect_identical(expr_deparse(x), "\"foo\\n\"")
  expect_output(expr_print(x), "foo\\n", fixed = TRUE)

  roundtrip <- parse_expr(expr_deparse(x))
  expect_identical(x, roundtrip)
})

test_that("expr_deparse() handles ANSI escapes in strings", {
  expect_identical(expr_deparse("\\"), deparse("\\"))
  expect_identical(expr_deparse("\\a"), deparse("\\a"))
  expect_identical(expr_deparse("\\b"), deparse("\\b"))
  expect_identical(expr_deparse("\\f"), deparse("\\f"))
  expect_identical(expr_deparse("\\n"), deparse("\\n"))
  expect_identical(expr_deparse("\\r"), deparse("\\r"))
  expect_identical(expr_deparse("\\t"), deparse("\\t"))
  expect_identical(expr_deparse("\\v"), deparse("\\v"))
  expect_identical(expr_deparse("\\0"), deparse("\\0"))
})

test_that("as_label() and expr_name() handles .data pronoun", {
  expect_identical(expr_name(quote(.data[["bar"]])), "bar")
  expect_identical(quo_name(quo(.data[["bar"]])), "bar")
  expect_identical(as_label(quote(.data[["bar"]])), "bar")
  expect_identical(as_label(quo(.data[["bar"]])), "bar")
})

test_that("as_label() handles literals", {
  expect_identical(as_label(1:2), "<int>")
  expect_identical(as_label(c(1, 2)), "<dbl>")
  expect_identical(as_label(letters), "<chr>")
  expect_identical(as_label(base::list), "<fn>")
  expect_identical(as_label(base::mean), "<fn>")
})

test_that("as_label() handles objects", {
  skip_on_cran()
  expect_identical(as_label(mtcars), "<df[,11]>")
  expect_identical(as_label(structure(1, class = "foo")), "<foo>")
})

test_that("bracket deparsing is a form of argument deparsing", {
  expect_identical(expr_deparse(quote(foo[bar, , baz()])), "foo[bar, , baz()]")
  expect_identical(expr_deparse(quote(foo[[bar, , baz()]])), "foo[[bar, , baz()]]")

  skip_on_cran()
  expect_identical(expr_deparse(call("[", iris, missing_arg(), drop = FALSE)), "<df[,5]>[, drop = FALSE]")
})

test_that("non-syntactic symbols are deparsed with backticks", {
  expect_identical(expr_deparse(quote(`::foo`)), "`::foo`")
  expect_identical(expr_deparse(quote(x(`_foo`))), "x(`_foo`)")
  expect_identical(expr_deparse(quote(x[`::foo`])), "x[`::foo`]")
})

test_that("symbols with unicode are deparsed consistently (#691)", {
  skip_if(getRversion() < "3.2")

  expect_identical(expr_text(sym("\u00e2a")), "\u00e2a")
  expect_identical(expr_deparse(sym("\u00e2a")), "\u00e2a")

  expect_identical(expr_text(sym("a\u00e2")), "a\u00e2")
  expect_identical(expr_deparse(sym("a\u00e2")), "a\u00e2")
})

test_that("formal parameters are backticked if needed", {
  expect_identical(expr_deparse(function(`^`) {}), c("<function(`^`) { }>"))
})

test_that("empty blocks are deparsed on the same line", {
  expect_identical(expr_deparse(quote({ })), "{ }")
})

test_that("top-level S3 objects are deparsed", {
  skip_on_cran()
  f <- structure(function() { }, class = "lambda")
  expect_identical(expr_deparse(f), "<lambda>")
})

# This test causes a parsing failure in R CMD check >= 3.6
#
# test_that("binary operators with 0 or 1 arguments are properly deparsed", {
#   expect_identical_(expr_deparse(quote(`/`())), "`/`()")
#   expect_identical(expr_deparse(quote(`/`("foo"))), "`/`(\"foo\")")
#   expect_identical_(expr_deparse(quote(`::`())), "`::`()")
#   expect_identical(expr_deparse(quote(`::`("foo"))), "`::`(\"foo\")")
# })

test_that("as_label() supports symbols, calls, and literals", {
  expect_identical(as_label(quote(foo)), "foo")
  expect_identical(as_label(quote(foo(bar))), "foo(bar)")
  expect_identical(as_label(1L), "1L")
  expect_identical(as_label("foo"), "\"foo\"")
  expect_identical(as_label(function() NULL), "<fn>")
  expect_identical(as_label(expr(function() { a; b })), "function() ...")
  expect_identical(as_label(1:2), "<int>")
  expect_identical(as_label(env()), "<env>")
})

test_that("as_label() supports special objects", {
  expect_match(as_label(quote(foo := bar)), ":=")
  expect_identical(as_label(quo(foo)), "foo")
  expect_identical(as_label(quo(foo(!!quo(bar)))), "foo(bar)")
  expect_identical(as_label(~foo), "~foo")
  expect_identical(as_label(NULL), "NULL")
})

test_that("as_name() supports quosured symbols and strings", {
   expect_identical(as_name(quo(foo)), "foo")
   expect_identical(as_name(quo("foo")), "foo")
   expect_error(as_name(quo(foo())), "Can't convert a call to a string")
 })

test_that("named empty lists are marked as named", {
  expect_identical(expr_deparse(set_names(list(), chr())), "<named list>")
})

test_that("infix operators are sticky", {
  expect_identical(expr_deparse(quote(foo %>% bar), width = 3L), c("foo %>%", "  bar"))
  expect_identical(expr_deparse(quote(foo + bar), width = 3L), c("foo +", "  bar"))
})

test_that("argument names are backticked if needed (#950)", {
  expect_identical(expr_deparse(quote(list(`a b` = 1))), "list(`a b` = 1)")
})

test_that("`next` and `break` are deparsed", {
  expect_equal(expr_deparse(quote({ next; (break) })), c("{", "  next",  "  (break)", "}"))
  expect_equal(expr_deparse(quote(a <- next <- break)), c("a <- next <- break"))
})

test_that("double colon is never wrapped (#1072)", {
  expect_identical(
    expr_deparse(quote(some.very.long::construct), width = 20),
    "some.very.long::construct"
  )
  expect_identical(
    expr_deparse(quote(id_function <- base::identity), width = 15),
    c(
      "id_function <-",
      "  base::identity"
    )
  )
  expect_identical(
    expr_deparse(quote(id_fun <- base::identity), width = 20),
    "id_fun <- base::identity"
  )
})

test_that("triple colon is never wrapped (#1072)", {
  expect_identical(
    expr_deparse(quote(some.very.long:::construct), width = 20),
    "some.very.long:::construct"
  )
  expect_identical(
    expr_deparse(quote(id_function <- base:::identity), width = 15),
    c(
      "id_function <-",
      "  base:::identity"
    )
  )
  expect_identical(
    expr_deparse(quote(id_fun <- base:::identity), width = 20),
    "id_fun <- base:::identity"
  )
})

test_that("backslashes in strings are properly escaped (#1160)", {
  expect_equal(
    expr_deparse(sym("a\\b")),
    "`a\\\\b`"
  )

  # Escaping ensures this roundtrip
  expect_equal(
    parse_expr(expr_deparse(sym("a\\b"))),
    sym("a\\b")
  )

  # Argument names
  expect_equal(
    expr_deparse(quote(c("a\\b" = "c\\d"))),
    "c(`a\\\\b` = \"c\\\\d\")"
  )

  # Vector names
  expect_equal(
    expr_deparse(c("a\\b" = "c\\d")),
    "<chr: a\\\\b = \"c\\\\d\">"
  )
  expect_equal(
    expr_deparse(list("a\\b" = "c\\d")),
    "<list: a\\\\b = \"c\\\\d\">"
  )
})

test_that("formulas are deparsed (#1169)", {
  # Evaluated formulas are treated as objects
  expect_equal(
    expr_deparse(~foo),
    "<formula>"
  )

  # Unevaluated formulas with a symbol have no space
  expect_equal(
    expr_deparse(quote(~foo)),
    "~foo"
  )

  # Unevaluated formulas with expressions have a space
  expect_equal(
    expr_deparse(quote(~+foo)),
    "~ +foo"
  )
  expect_equal(
    expr_deparse(quote(~foo())),
    "~ foo()"
  )
})

test_that("matrices and arrays are formatted (#383)", {
  mat <- matrix(1:3)
  expect_equal(as_label(mat), "<int[,1]>")
  expect_equal(expr_deparse(mat), "<int[,1]: 1L, 2L, 3L>")

  mat2 <- matrix(1:4, 2)
  expect_equal(as_label(mat2), "<int[,2]>")
  expect_equal(expr_deparse(mat2), "<int[,2]: 1L, 2L, 3L, 4L>")

  arr <- array(1:3, c(1, 1, 3))
  expect_equal(as_label(arr), "<int[,1,3]>")
  expect_equal(expr_deparse(arr), "<int[,1,3]: 1L, 2L, 3L>")
})

test_that("infix operators are labelled (#956, r-lib/testthat#1432)", {
  expect_equal(
    as_label(quote({ 1; 2} + 3)),
    "... + 3"
  )

  expect_equal(
    as_label(quote(`+`(1, 2, 3))),
    "`+`(1, 2, 3)"
  )

  expect_equal(
    as_label(quote(
      arg + arg + arg + arg + arg + arg + arg + arg + arg + arg + arg + arg
    )),
    "... + arg"
  )

  expect_equal(
    as_label(quote(X[key1 == "val1" & key2 == "val2"]$key3 & foobarbaz(foobarbaz(foobarbaz(foobarbaz(foobarbaz(foobarbaz(foobarbaz())))))))),
    "X[key1 == \"val1\" & key2 == \"val2\"]$key3 & ..."
  )

  expect_equal(
    as_label(quote(X[key1 == "val1"]$key3 & foobarbaz(foobarbaz()))),
    "X[key1 == \"val1\"]$key3 & foobarbaz(foobarbaz())"
  )

  # This fits in 60 characters so we don't need to truncate it
  expect_equal(
    as_label(quote(nchar(chr, type = "bytes", allowNA = TRUE) == 1)),
    "nchar(chr, type = \"bytes\", allowNA = TRUE) == 1"
  )

  # This fits into 60 characters if we truncate either side,
  # so we don't need to shorten both of them
  expect_equal(
    as_label(quote(very_long_expression[with(subsetting), -1] -
                     another_very_long_expression[with(subsetting), -1]
    )),
    "very_long_expression[with(subsetting), -1] - ..."
  )

  lhs_perfect_fit <- sym(paste(rep("a", 56), collapse = ""))
  lhs_no_fit <- sym(paste(rep("a", 57), collapse = ""))

  expect_equal(
    as_label(expr(!!lhs_perfect_fit + 1)),
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + 1"
  )
  expect_equal(
    as_label(expr(!!lhs_perfect_fit + 10)),
    "... + 10"
  )

  expect_equal(
    as_label(expr(1 + !!lhs_perfect_fit)),
    "1 + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  )
  expect_equal(
    as_label(expr(10 + !!lhs_perfect_fit)),
    "10 + ..."
  )

  expect_equal(
    as_label(expr(!!lhs_no_fit + 1)),
    "... + 1"
  )
  expect_equal(
    as_label(expr(!!lhs_no_fit + !!lhs_no_fit)),
    "... + ..."
  )
})

test_that("binary op without arguments", {
  expect_equal(
    expr_deparse(quote(`+`())),
    "`+`()"
  )
  expect_equal(
    expr_deparse(quote(`$`())),
    "`$`()"
  )
  expect_equal(
    expr_deparse(quote(`~`())),
    "`~`()"
  )
})

test_that("call_deparse_highlight() handles long lists of arguments (#1456)", {
  out <- call_deparse_highlight(quote(
    foo(
      aaaaaa = aaaaaa,
      bbbbbb = bbbbbb,
      cccccc = cccccc,
      dddddd = dddddd,
      eeeeee = eeeeee
    )
  ), NULL)

  expect_equal(
    cli::ansi_strip(out),
    "foo(...)"
  )
})

test_that("call_deparse_highlight() handles multi-line arguments (#1456)", {
  out <- call_deparse_highlight(quote(
    fn(arg = {
      a
      b
    })
  ), NULL)

  expect_equal(
    cli::ansi_strip(out),
    "fn(...)"
  )
})

test_that("embrace operator is deparsed (#1511)", {
  expect_equal_(
    expr_deparse(quote({{ a }})),
    "{{ a }}"
  )

  expect_equal_(
    expr_deparse(quote(foo({{ a }}))),
    "foo({{ a }})"
  )
})

Try the rlang package in your browser

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

rlang documentation built on Nov. 4, 2023, 9:06 a.m.