tests/testthat/test-matrix_apply_linter.R

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

  expect_lint("apply(x, 1, prod)", NULL, linter)

  expect_lint("apply(x, 1, function(i) sum(i[i > 0]))", NULL, linter)

  # sum as FUN argument
  expect_lint("apply(x, 1, f, sum)", NULL, linter)

  # mean() with named arguments other than na.rm is skipped because they are not
  # implemented in colMeans() or rowMeans()
  expect_lint("apply(x, 1, mean, trim = 0.2)", NULL, linter)
})

test_that("matrix_apply_linter is not implemented for complex MARGIN values", {
  linter <- matrix_apply_linter()

  # Could be implemented at some point
  expect_lint("apply(x, seq(2, 4), sum)", NULL, linter)

  # No equivalent
  expect_lint("apply(x, c(2, 4), sum)", NULL, linter)

  # Beyond the scope of static analysis
  expect_lint("apply(x, m, sum)", NULL, linter)

  expect_lint("apply(x, 1 + 2:4, sum)", NULL, linter)

})


test_that("matrix_apply_linter simple disallowed usages", {
  linter <- matrix_apply_linter()
  lint_message <- rex::rex("rowSums(x)")

  expect_lint("apply(x, 1, sum)", lint_message, linter)

  expect_lint("apply(x, MARGIN = 1, FUN = sum)", lint_message, linter)

  expect_lint("apply(x, 1L, sum)", lint_message, linter)

  expect_lint("apply(x, 1:4, sum)", rex::rex("rowSums(x, dims = 4)"), linter)

  expect_lint("apply(x, 2, sum)", rex::rex("rowSums(colSums(x))"), linter)

  expect_lint("apply(x, 2:4, sum)", rex::rex("rowSums(colSums(x), dims = 3)"), linter)

  lint_message <- rex::rex("rowMeans")

  expect_lint("apply(x, 1, mean)", lint_message, linter)

  expect_lint("apply(x, MARGIN = 1, FUN = mean)", lint_message, linter)

  # Works with extra args in mean()
  expect_lint("apply(x, 1, mean, na.rm = TRUE)", lint_message, linter)

  lint_message <- rex::rex("colMeans")

  expect_lint("apply(x, 2, mean)", lint_message, linter)

  expect_lint("apply(x, 2:4, mean)", lint_message, linter)

})

test_that("matrix_apply_linter recommendation includes na.rm if present in original call", {
  linter <- matrix_apply_linter()
  lint_message <- rex::rex("na.rm = TRUE")

  expect_lint("apply(x, 1, sum, na.rm = TRUE)", lint_message, linter)

  expect_lint("apply(x, 2, sum, na.rm = TRUE)", lint_message, linter)

  expect_lint("apply(x, 1, mean, na.rm = TRUE)", lint_message, linter)

  expect_lint("apply(x, 2, mean, na.rm = TRUE)", lint_message, linter)

  lint_message <- rex::rex("rowSums(x)")
  expect_lint("apply(x, 1, sum)", lint_message, linter)

  lint_message <- rex::rex("na.rm = foo")
  expect_lint("apply(x, 1, sum, na.rm = foo)", lint_message, linter)

})

test_that("matrix_apply_linter works with multiple lints in a single expression", {
  linter <- matrix_apply_linter()

  expect_lint(
    "rbind(
      apply(x, 1, sum),
      apply(y, 2:4, mean, na.rm = TRUE)
    )",
    list(
      rex::rex("Use rowSums(x)"),
      rex::rex("Use rowMeans(colMeans(y, na.rm = TRUE), dims = 3) or colMeans(y, na.rm = TRUE) if y has 4 dimensions")
    ),
    linter
  )

})

Try the lintr package in your browser

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

lintr documentation built on Nov. 7, 2023, 5:07 p.m.