-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New expect_setequal_linter #951
Changes from all commits
f2cebe1
c8b87bf
7f36806
b3425f2
98de1e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#' Require usage of expect_setequal() over expect_identical(sort(...), ...) | ||
#' | ||
#' `expect_setequal()` is designed for testing an output, regardless of order; | ||
#' for example, this is particularly useful for SQL, which is typically | ||
#' row-order-agnostic. | ||
#' | ||
#' Note that, in the presence of possible duplicates, | ||
#' `expect_identical(sort(x), y)` won't be the same as | ||
#' `expect_setequal(x, y)`. This linter encourages a separate test for | ||
#' duplicates rather than integrating two tests into one. | ||
#' | ||
#' @evalRd rd_tags("expect_setequal_linter") | ||
#' @seealso [linters] for a complete list of linters available in lintr. | ||
#' @export | ||
expect_setequal_linter <- function() { | ||
Linter(function(source_file) { | ||
if (length(source_file$parsed_content) == 0L) { | ||
return(list()) | ||
} | ||
|
||
xml <- source_file$xml_parsed_content | ||
|
||
xpath <- glue::glue("//expr[ | ||
expr[SYMBOL_FUNCTION_CALL[text() = 'expect_identical' or text() = 'expect_equal']] | ||
and expr[expr[SYMBOL_FUNCTION_CALL[text() = 'sort']]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our sense is that people are using This linter only caught a handful of cases in practice as is. Maybe we should just exclude this one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fine for me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense... I wonder if Anyway, closing for now. |
||
and not(SYMBOL_SUB[text() = 'tolerance']) | ||
]") | ||
|
||
bad_expr <- xml2::xml_find_all(xml, xpath) | ||
return(lapply(bad_expr, gen_expect_setequal_lint, source_file)) | ||
}) | ||
} | ||
|
||
gen_expect_setequal_lint <- function(expr, source_file) { | ||
matched_function <- xml2::xml_text(xml2::xml_find_first(expr, "expr/SYMBOL_FUNCTION_CALL")) | ||
lint_msg <- sprintf("Use expect_setequal(actual, expected) instead of %s(sort(actual), expected).", matched_function) | ||
lint_msg <- paste(lint_msg, "If you need to check equality of duplicates, do so as a separate test.") | ||
xml_nodes_to_lint(expr, source_file, lint_msg, type = "warning") | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
test_that("expect_setequal_linter skips allowed usages", { | ||
# tolerance= blocks applicability | ||
expect_lint("expect_equal(sort(x), sort(y), tolerance = 1e-12)", NULL, expect_setequal_linter()) | ||
}) | ||
|
||
test_that("expect_setequal_linter blocks simple disallowed usages", { | ||
expect_lint( | ||
"expect_identical(sort(x), sort(y))", | ||
rex::rex("Use expect_setequal(actual, expected) instead of expect_identical(sort(actual), expected)"), | ||
expect_setequal_linter() | ||
) | ||
expect_lint( | ||
"expect_equal(sort(x), sort(y))", | ||
rex::rex("Use expect_setequal(actual, expected) instead of expect_equal(sort(actual), expected)"), | ||
expect_setequal_linter() | ||
) | ||
|
||
# usage in either argument alone is matched | ||
expect_lint( | ||
"expect_identical(x, sort(y))", | ||
rex::rex("Use expect_setequal(actual, expected) instead of expect_identical(sort(actual), expected)"), | ||
expect_setequal_linter() | ||
) | ||
expect_lint( | ||
"expect_identical(sort(x), y)", | ||
rex::rex("Use expect_setequal(actual, expected) instead of expect_identical(sort(actual), expected)"), | ||
expect_setequal_linter() | ||
) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sort(unique(x))
andsort(unique(y))
, no?