1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
test_that("condition_message_linter skips allowed usages", {
linter <- condition_message_linter()
expect_lint("stop('a string', 'another')", NULL, linter)
expect_lint("warning('a string', 'another')", NULL, linter)
expect_lint("message('a string', 'another')", NULL, linter)
# extracted calls likely don't obey base::stop() semantics
expect_lint("ctx$stop(paste('a', 'b'))", NULL, linter)
expect_lint("ctx@stop(paste('a', 'b'))", NULL, linter)
# sprintf is OK -- gettextf() enforcement is left to other linters
expect_lint("stop(sprintf('A %s!', 'string'))", NULL, linter)
# get multiple sep= in one expression
expect_lint(
trim_some("
tryCatch(
foo(x),
error = function(e) stop(paste(a, b, sep = '-')),
warning = function(w) warning(paste(a, b, sep = '--')),
)
"),
NULL,
linter
)
})
skip_if_not_installed("tibble")
patrick::with_parameters_test_that(
"paste/paste0 allowed by condition_message_linter when using other seps and/or collapse",
expect_lint(
sprintf("%s(%s(x, %s = '%s'))", condition, fun, parameter, arg),
NULL,
condition_message_linter()
),
.cases = tibble::tribble(
~.test_name, ~condition, ~fun, ~parameter, ~arg,
"stop, paste and collapse = ''", "stop", "paste", "collapse", "",
"warning, paste and collapse = '\n'", "warning", "paste", "collapse", "\n",
"message, paste and collapse = '|'", "message", "paste", "collapse", "|",
"stop, paste0 and collapse = ''", "stop", "paste0", "collapse", "",
"warning, paste0 and collapse = '\n'", "warning", "paste0", "collapse", "\n",
"message, paste0 and collapse = '|'", "message", "paste0", "collapse", "|",
"stop, paste and sep = '-'", "stop", "paste", "sep", "-",
"warning, paste and sep = '\n'", "warning", "paste", "sep", "\n",
"message, paste and sep = '|'", "message", "paste", "sep", "|"
)
)
test_that("condition_message_linter blocks simple disallowed usages", {
expect_lint(
"stop(paste('a string', 'another'))",
rex::rex("Don't use paste to build stop strings."),
condition_message_linter()
)
expect_lint(
"warning(paste0('a string ', 'another'))",
rex::rex("Don't use paste0 to build warning strings."),
condition_message_linter()
)
# `sep` argument allowed, but only if it is different from default
expect_lint(
"stop(paste(x, sep = ' '))",
rex::rex("Don't use paste to build stop strings."),
condition_message_linter()
)
# not thrown off by named arguments
expect_lint(
"stop(paste('a', 'b'), call. = FALSE)",
rex::rex("Don't use paste to build stop strings."),
condition_message_linter()
)
expect_lint(
"warning(paste0('a', 'b'), immediate. = TRUE)",
rex::rex("Don't use paste0 to build warning strings."),
condition_message_linter()
)
expect_lint(
trim_some("
tryCatch(
foo(x),
error = function(e) stop(paste(a, b)),
warning = function(w) warning(paste(a, b, sep = '--')),
)
"),
rex::rex("Don't use paste to build stop strings."),
condition_message_linter()
)
# one with no sep, one with linted sep
expect_lint(
trim_some("
tryCatch(
foo(x),
error = function(e) stop(paste(a, b)),
warning = function(w) warning(paste(a, b, sep = '')),
)
"),
list(
list(message = rex::rex("Don't use paste to build stop strings."), line_number = 3L),
list(message = rex::rex("Don't use paste to build warning strings"), line_number = 4L)
),
condition_message_linter()
)
})
test_that("packageStartupMessage usages are also matched", {
expect_lint(
"packageStartupMessage(paste('a string', 'another'))",
rex::rex("Don't use paste to build packageStartupMessage strings."),
condition_message_linter()
)
expect_lint(
"packageStartupMessage(paste0('a string ', 'another'))",
rex::rex("Don't use paste0 to build packageStartupMessage strings."),
condition_message_linter()
)
})
test_that("R>=4.0.0 raw strings are handled", {
skip_if_not_r_version("4.0.0")
expect_lint(
"warning(paste(a, b, sep = R'( )'))",
rex::rex("Don't use paste to build warning strings."),
condition_message_linter()
)
expect_lint(
"warning(paste(a, b, sep = R'---[ ]---'))",
rex::rex("Don't use paste to build warning strings."),
condition_message_linter()
)
})
test_that("message vectorization works", {
expect_lint(
trim_some("
foo <- function() {
warning(paste('uh oh!', 'spaghettios'))
stop(paste0('look out ', 'below!'))
}
"),
list(
rex::rex("Don't use paste to build warning strings"),
rex::rex("Don't use paste0 to build stop strings")
),
condition_message_linter()
)
})
|