-
Notifications
You must be signed in to change notification settings - Fork 185
/
Copy pathtest-lint.R
235 lines (200 loc) · 6.68 KB
/
test-lint.R
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# The lints for a given file should be the same regardless of the working
# directory
test_that("lint() results do not depend on the working directory", {
# Helper function: run assignment_linter on a given file
lint_assignments <- function(filename) {
lint(filename, linters = list(assignment_linter()))
}
# a dummy package for use in the test
pkg_path <- test_path("dummy_packages", "assignmentLinter")
# put a .lintr in the package root that excludes the first line of `R/jkl.R`
local_config("exclusions: list('R/jkl.R' = 1)", pkg_path)
# linting the `R/jkl.R` should identify the following assignment lint on the
# second line of the file
expected_lines <- "mno = 789"
# lint the file from:
# - outside the package
# - at the package root
# - in the package's R/ directory
lints_from_outside <- lint_assignments(
file.path(pkg_path, "R", "jkl.R")
)
lints_from_pkg_root <- withr::with_dir(
pkg_path,
lint_assignments(file.path("R", "jkl.R"))
)
lints_from_a_subdir <- withr::with_dir(
file.path(pkg_path, "R"),
lint_assignments("jkl.R")
)
expect_identical(
as.data.frame(lints_from_pkg_root)[["line"]],
expected_lines
)
expect_identical(
as.data.frame(lints_from_outside),
as.data.frame(lints_from_pkg_root)
)
expect_identical(
as.data.frame(lints_from_a_subdir),
as.data.frame(lints_from_pkg_root)
)
})
# The lints for a given file should be the same regardless of where the .lintr
# file is positioned (file-exclusions in the .lintr should be relative to the
# directory containing the .lintr)
test_that("lint() results do not depend on the position of the .lintr", {
# .lintr config files for lint(filepath) are looked for in:
# - the same directory as filepath
# - the project directory
# - the user's home directory
lint_with_config <- function(config_string, config_dir, filename) {
local_config(config_string, config_dir)
lint(filename, linters = assignment_linter())
}
# a dummy package for use in the test
pkg_path <- test_path("dummy_packages", "assignmentLinter")
# we lint the file <pkg-root>/R/jkl.R using the pkg-root as working directory
# and
# - 1) a .lintr config in the package root,
# - 2) a .lintr config in the source directory R/
# The second line of jkl.R contains the following assignment lint:
expected_lines <- "mno = 789"
lints_with_config_at_pkg_root <- withr::with_dir(
pkg_path,
lint_with_config(
config_string = "exclusions: list('R/jkl.R' = 1)",
config_dir = ".",
filename = file.path("R", "jkl.R")
)
)
lints_with_config_in_r_dir <- withr::with_dir(
pkg_path,
lint_with_config(
config_string = "exclusions: list('jkl.R' = 1)",
config_dir = "R",
filename = file.path("R", "jkl.R")
)
)
expect_identical(
as.data.frame(lints_with_config_at_pkg_root)[["line"]], expected_lines
)
expect_identical(
as.data.frame(lints_with_config_at_pkg_root),
as.data.frame(lints_with_config_in_r_dir),
info = paste(
"lints for a source file should be independent of whether the .lintr",
"file is in the project-root or the source-file-directory"
)
)
})
test_that("lint uses linter names", { # nofuzz
expect_lint(
"a = 2",
list(linter = "bla"),
linters = list(bla = assignment_linter()),
parse_settings = FALSE
)
})
test_that("lint() results from file or text should be consistent", {
linters <- list(assignment_linter(), infix_spaces_linter())
lines <- c("x<-1", "x+1")
file <- withr::local_tempfile(lines = lines)
text <- paste(lines, collapse = "\n")
file <- normalize_path(file)
lint_from_file <- lint(file, linters = linters)
lint_from_lines <- lint(linters = linters, text = lines)
lint_from_text <- lint(linters = linters, text = text)
# Remove file before linting to ensure that lint works and do not
# assume that file exists when both filename and text are supplied.
expect_identical(unlink(file), 0L)
lint_from_text2 <- lint(file, linters = linters, text = text)
expect_length(lint_from_file, 2L)
expect_length(lint_from_lines, 2L)
expect_length(lint_from_text, 2L)
expect_length(lint_from_text2, 2L)
expect_identical(lint_from_file, lint_from_text2)
for (i in seq_along(lint_from_lines)) {
lint_from_file[[i]]$filename <- ""
lint_from_lines[[i]]$filename <- ""
lint_from_text[[i]]$filename <- ""
}
expect_identical(lint_from_file, lint_from_lines)
expect_identical(lint_from_file, lint_from_text)
})
test_that("exclusions work with custom linter names", { # nofuzz
expect_no_lint(
"a = 2 # nolint: bla.",
linters = list(bla = assignment_linter()),
parse_settings = FALSE
)
})
test_that("old compatibility usage errors", {
error_msg <- rex::rex("Expected `", anything, "` to be a function of class <linter>")
expect_error(
expect_lint(
"a == NA",
"Use is.na",
linters = equals_na_linter
),
error_msg
)
expect_error(
expect_lint(
"a = 42",
"Use <-",
linters = assignment_linter
),
error_msg
)
# Also within `linters_with_defaults()` (#1725)
expect_error(
expect_lint(
"a = 42",
"Use <-",
linters = linters_with_defaults(assignment_linter)
),
error_msg
)
expect_error(
expect_lint(
"a == NA",
"Use is.na",
linters = unclass(equals_na_linter())
),
error_msg
)
# Trigger compatibility in auto_names()
expect_error(
expect_lint(
"a == NA",
"Use is.na",
linters = list(unclass(equals_na_linter()))
),
error_msg
)
expect_error(
lint("a <- 1\n", linters = function(two, arguments) NULL),
error_msg
)
expect_error(
lint("a <- 1\n", linters = "equals_na_linter"),
error_msg
)
})
test_that("Linters throwing an error give a helpful error", {
tmp_file <- withr::local_tempfile(lines = "a <- 1")
lintr_error_msg <- "a broken linter"
linter <- function() Linter(function(source_expression) cli_abort(lintr_error_msg))
# NB: Some systems/setups may use e.g. symlinked files when creating under tempfile();
# we don't care much about that, so just check basename()
expect_error(lint(tmp_file, linter()), lintr_error_msg, fixed = TRUE)
expect_error(lint(tmp_file, list(broken_linter = linter())), lintr_error_msg, fixed = TRUE)
})
test_that("Linter() input is validated", {
expect_error(Linter(1L), "`fun` must be a function taking exactly one argument", fixed = TRUE)
expect_error(Linter(function(a, b) TRUE), "`fun` must be a function taking exactly one argument", fixed = TRUE)
})
test_that("typo in argument name gives helpful error", {
expect_error(lint("xxx", litners = identity), "Found unknown arguments in `...`: `litners`")
})