tests/testthat/test-nzchar_linter.R

test_that("nzchar_linter skips allowed usages", {
  linter <- nzchar_linter()

  expect_lint("if (any(nzchar(x))) TRUE", NULL, linter)

  expect_lint("letters == 'a'", NULL, linter)

  expect_lint("which(nchar(x) == 4)", NULL, linter)
  expect_lint("which(nchar(x) != 2)", NULL, linter)
})

test_that("nzchar_linter skips as appropriate for other nchar args", {
  linter <- nzchar_linter()

  # using type="width" can lead to 0-width strings that are counted as
  #   nzchar, c.f. nchar("\u200b", type="width"), so don't lint this.
  # type="bytes" should be >= the value for the default (type="chars")
  expect_lint("nchar(x, type='width') == 0L", NULL, linter)

  expect_lint("nchar(x, allowNA=TRUE) == 0L", NULL, linter)

  # nzchar also has keepNA argument so a drop-in switch is easy
  expect_lint(
    "nchar(x, keepNA=TRUE) == 0",
    rex::rex("Use !nzchar(x) instead of nchar(x) == 0"),
    linter
  )
})

test_that("nzchar_linter blocks simple disallowed usages", {
  linter <- nzchar_linter()
  lint_msg_quote <- rex::rex('Use !nzchar(x) instead of x == ""')
  lint_msg_nchar <- rex::rex("Use nzchar() instead of comparing nchar(x) to 0")

  expect_lint("which(x == '')", lint_msg_quote, linter)
  expect_lint("any(nchar(x) >= 0)", rex::rex("nchar(x) >= 0 is always true, maybe you want nzchar(x)?"), linter)
  expect_lint("all(nchar(x) == 0L)", rex::rex("Use !nzchar(x) instead of nchar(x) == 0"), linter)
  expect_lint("sum(0.0 < nchar(x))", rex::rex("Use nzchar(x) instead of nchar(x) > 0"), linter)
})

test_that("nzchar_linter skips comparison to '' in if/while statements", {
  linter <- nzchar_linter()
  lint_msg_quote <- rex::rex('Use !nzchar(x) instead of x == ""')
  lint_msg_nchar <- rex::rex("Use nzchar(x) instead of nchar(x) > 0")

  # still lint nchar() comparisons
  expect_lint("if (nchar(x) > 0) TRUE", lint_msg_nchar, linter)
  expect_lint('if (x == "") TRUE', NULL, linter)
  expect_lint('while (x == "") TRUE', NULL, linter)

  # nested versions, a la nesting issues with vector_logic_linter
  expect_lint('if (TRUE || (x == "" && FALSE)) TRUE', NULL, linter)
  expect_lint('if (TRUE && x == "" && FALSE) TRUE', NULL, linter)
  expect_lint('if (any(x == "")) TRUE', lint_msg_quote, linter)
  expect_lint('if (TRUE || any(x == "" | FALSE)) TRUE', lint_msg_quote, linter)
  expect_lint('foo(if (x == "") y else z)', NULL, linter)
})

test_that("multiple lints are generated correctly", {
  expect_lint(
    trim_some("{
      a == ''
      '' < b
      nchar(c) != 0
      0.0 > nchar(d)
    }"),
    list(
      list(rex::rex('Use !nzchar(x) instead of x == ""'), line_number = 2L),
      list(rex::rex('Use nzchar(x) instead of x > ""'), line_number = 3L),
      list(rex::rex("Use nzchar(x) instead of nchar(x) != 0."), line_number = 4L),
      list(rex::rex("nchar(x) < 0 is always false, maybe you want !nzchar(x)?"), line_number = 5L)
    ),
    nzchar_linter()
  )
})
jimhester/lintr documentation built on April 24, 2024, 8:21 a.m.