From 387ed2946763396b126a79a2b4f04fb59f4c1d61 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Fri, 18 Mar 2022 07:32:36 +0000 Subject: [PATCH 1/5] New expect_identical_linter --- DESCRIPTION | 1 + NAMESPACE | 1 + NEWS.md | 1 + R/expect_identical_linter.R | 80 +++++++++++++++++++ inst/lintr/linters.csv | 1 + man/expect_identical_linter.Rd | 26 ++++++ man/linters.Rd | 7 +- man/package_development_linters.Rd | 1 + tests/testthat/test-expect_identical_linter.R | 67 ++++++++++++++++ 9 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 R/expect_identical_linter.R create mode 100644 man/expect_identical_linter.Rd create mode 100644 tests/testthat/test-expect_identical_linter.R diff --git a/DESCRIPTION b/DESCRIPTION index a94a97be0..509dc4ea6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -62,6 +62,7 @@ Collate: 'duplicate_argument_linter.R' 'equals_na_linter.R' 'exclude.R' + 'expect_identical_linter.R' 'expect_length_linter.R' 'expect_lint.R' 'expect_named_linter.R' diff --git a/NAMESPACE b/NAMESPACE index 957f6fcf5..177d95c49 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,6 +28,7 @@ export(default_undesirable_functions) export(default_undesirable_operators) export(duplicate_argument_linter) export(equals_na_linter) +export(expect_identical_linter) export(expect_length_linter) export(expect_lint) export(expect_lint_free) diff --git a/NEWS.md b/NEWS.md index 1f6616efd..00a0f56b6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -94,6 +94,7 @@ function calls. (#850, #851, @renkun-ken) + `expect_true_false_linter()` Require usage of `expect_true(x)` over `expect_equal(x, TRUE)` and similar + `expect_named_linter()` Require usage of `expect_named(x, n)` over `expect_equal(names(x), n)` and similar * `expect_length_linter()` Require usage of `expect_length(x, n)` over `expect_equal(length(x), n)` and similar + * `expect_identical_linter()` Require usage of `expect_identical()` by default, and `expect_equal()` only by exception * `assignment_linter()` now lints right assignment (`->` and `->>`) and gains two arguments. `allow_cascading_assign` (`TRUE` by default) toggles whether to lint `<<-` and `->>`; `allow_right_assign` toggles whether to lint `->` and `->>` (#915, @michaelchirico) * `infix_spaces_linter()` gains argument `exclude_operators` to disable lints on selected infix operators. By default, all "low-precedence" operators throw lints; see `?infix_spaces_linter` for an enumeration of these. (#914 @michaelchirico) * `infix_spaces_linter()` now throws a lint on `a~b` and `function(a=1) {}` (#930, @michaelchirico) diff --git a/R/expect_identical_linter.R b/R/expect_identical_linter.R new file mode 100644 index 000000000..16ae97f22 --- /dev/null +++ b/R/expect_identical_linter.R @@ -0,0 +1,80 @@ +#' Require usage of expect_identical(x, y) where appropriate +#' +#' At Google, [testthat::expect_identical()] should be the default/go-to function for +#' comparing an output to an expected value. `expect_true(identical(x, y))` +#' is an equivalent but unadvised method of the same test. Further, +#' [testthat::expect_equal()] should only be used when `expect_identical()` +#' is inappropriate, i.e., when `x` and `y` need only be *numerically +#' equivalent* instead of fully identical (in which case, provide the +#' `tolerance=` argument to `expect_equal()` explicitly). This also applies +#' when it's inconvenient to check full equality (e.g., names can be ignored, +#' in which case `ignore_attr = "names"` should be supplied to +#' `expect_equal()` (or, for 2nd edition, `check.attributes = FALSE`). +#' +#' @evalRd rd_tags("expect_identical_linter") +#' @seealso [linters] for a complete list of linters available in lintr. +#' @export +expect_identical_linter <- function() { + Linter(function(source_file) { + if (length(source_file$parsed_content) == 0L) { + return(list()) + } + + xml <- source_file$xml_parsed_content + + # outline: + # 1. conditions for expect_equal() + # - skip when tolerance= is set + # - skip when check.attributes = FALSE [for 2nd edition tests] + # - skip when any ignore_* is set [for 3rd edition tests] + # specifically ignore_{srcref,attr,encoding,function_env,formula_env} + # - skip cases like expect_equal(x, 1.02) or the constant vector version + # where a numeric constant indicates inexact testing is preferable + # - skip calls using dots (`...`); see tests + # 2. conditions for expect_true() + xpath <- glue::glue("//expr[ + ( + SYMBOL_FUNCTION_CALL[text() = 'expect_equal'] + and not( + following-sibling::SYMBOL_SUB[text() = 'tolerance'] + or following-sibling::SYMBOL_SUB[ + ( + text() = 'check.attributes' + and following-sibling::expr[1][NUM_CONST[text() = 'FALSE']] + ) + or starts-with(text(), 'ignore_') + ] + or following-sibling::expr[ + expr[SYMBOL_FUNCTION_CALL[text() = 'c']] + and expr[NUM_CONST[contains(text(), '.')]] + ] + or following-sibling::expr[NUM_CONST[contains(text(), '.')]] + or following-sibling::expr[SYMBOL[text() = '...']] + ) + ) or ( + SYMBOL_FUNCTION_CALL[text() = 'expect_true'] + and following-sibling::expr[1][ + expr[SYMBOL_FUNCTION_CALL[text() = 'identical']] + ] + ) + ]") + + bad_expr <- xml2::xml_find_all(xml, xpath) + return(lapply( + bad_expr, + xml_nodes_to_lint, + source_file = source_file, + message = paste( + "expect_identical(x, y) is the default way of comparing two objects in", + "testthat unit tests. Only use expect_equal() if testing numeric", + "equality (and specifying tolerance= explicitly) or there's a need to", + "ignore some attributes, e.g. with ignore_attr = 'names' for the 3rd", + "edition or check.attributes = FALSE for the second. For testing", + "approximate equality to a whole number, you can also avoid setting", + "tolerance= by including an explicit decimal point, e.g.,", + "expect_equal(x, 1.0), not expect_equal(x, 1)." + ), + type = "warning" + )) + }) +} diff --git a/inst/lintr/linters.csv b/inst/lintr/linters.csv index 6284d97fc..52c963646 100644 --- a/inst/lintr/linters.csv +++ b/inst/lintr/linters.csv @@ -8,6 +8,7 @@ commented_code_linter,style readability best_practices default cyclocomp_linter,style readability best_practices default configurable duplicate_argument_linter,correctness common_mistakes configurable equals_na_linter,robustness correctness common_mistakes default +expect_identical_linter,package_development expect_length_linter,package_development best_practices readability expect_named_linter,package_development best_practices readability expect_not_linter,package_development best_practices readability diff --git a/man/expect_identical_linter.Rd b/man/expect_identical_linter.Rd new file mode 100644 index 000000000..8d24f7e2f --- /dev/null +++ b/man/expect_identical_linter.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/expect_identical_linter.R +\name{expect_identical_linter} +\alias{expect_identical_linter} +\title{Require usage of expect_identical(x, y) where appropriate} +\usage{ +expect_identical_linter() +} +\description{ +\code{\link[testthat:equality-expectations]{testthat::expect_identical()}} should be the default/go-to function for +comparing an output to an expected value. \code{expect_true(identical(x, y))} +is an equivalent but unadvised method of the same test. Further, +\code{\link[testthat:equality-expectations]{testthat::expect_equal()}}, should only be used when \code{expect_identical()} +is inappropriate, i.e., when \code{x} and \code{y} need only be \emph{numerically +equivalent} instead of fully identical (in which case, provide the +\verb{tolerance=} argument to \code{expect_equal()} explicitly). This also applies +when it's inconvenient to check full equality (e.g., names can be ignored, +in which case \code{ignore_attr = "names"} should be supplied to +\code{expect_equal()} (or, for 2nd edition, \code{check.attributes = FALSE}). +} +\seealso{ +\link{linters} for a complete list of linters available in lintr. +} +\section{Tags}{ +\link[=package_development_linters]{package_development} +} diff --git a/man/linters.Rd b/man/linters.Rd index 42168d448..947f7bb11 100644 --- a/man/linters.Rd +++ b/man/linters.Rd @@ -17,15 +17,15 @@ Documentation for linters is structured into tags to allow for easier discovery. \section{Tags}{ The following tags exist: \itemize{ -\item{\link[=best_practices_linters]{best_practices} (17 linters)} +\item{\link[=best_practices_linters]{best_practices} (18 linters)} \item{\link[=common_mistakes_linters]{common_mistakes} (5 linters)} \item{\link[=configurable_linters]{configurable} (16 linters)} \item{\link[=consistency_linters]{consistency} (7 linters)} \item{\link[=correctness_linters]{correctness} (7 linters)} \item{\link[=default_linters]{default} (25 linters)} \item{\link[=efficiency_linters]{efficiency} (4 linters)} -\item{\link[=package_development_linters]{package_development} (9 linters)} -\item{\link[=readability_linters]{readability} (23 linters)} +\item{\link[=package_development_linters]{package_development} (11 linters)} +\item{\link[=readability_linters]{readability} (24 linters)} \item{\link[=robustness_linters]{robustness} (10 linters)} \item{\link[=style_linters]{style} (31 linters)} } @@ -42,6 +42,7 @@ The following linters exist: \item{\code{\link{cyclocomp_linter}} (tags: best_practices, configurable, default, readability, style)} \item{\code{\link{duplicate_argument_linter}} (tags: common_mistakes, configurable, correctness)} \item{\code{\link{equals_na_linter}} (tags: common_mistakes, correctness, default, robustness)} +\item{\code{\link{expect_identical_linter}} (tags: package_development)} \item{\code{\link{expect_length_linter}} (tags: best_practices, package_development, readability)} \item{\code{\link{expect_named_linter}} (tags: best_practices, package_development, readability)} \item{\code{\link{expect_not_linter}} (tags: best_practices, package_development, readability)} diff --git a/man/package_development_linters.Rd b/man/package_development_linters.Rd index 3f7510b42..ed3ac4184 100644 --- a/man/package_development_linters.Rd +++ b/man/package_development_linters.Rd @@ -13,6 +13,7 @@ Linters useful to package developers, for example for writing consistent tests. The following linters are tagged with 'package_development': \itemize{ \item{\code{\link{backport_linter}}} +\item{\code{\link{expect_identical_linter}}} \item{\code{\link{expect_length_linter}}} \item{\code{\link{expect_named_linter}}} \item{\code{\link{expect_not_linter}}} diff --git a/tests/testthat/test-expect_identical_linter.R b/tests/testthat/test-expect_identical_linter.R new file mode 100644 index 000000000..c98832ed4 --- /dev/null +++ b/tests/testthat/test-expect_identical_linter.R @@ -0,0 +1,67 @@ +test_that("expect_identical_linter skips allowed usages", { + # expect_type doesn't have an inverted version + expect_lint("expect_true(identical(x, y) || identical(y, z))", NULL, expect_identical_linter()) + # NB: also applies to tinytest, but it's sufficient to test testthat + expect_lint("testthat::expect_true(identical(x, y) || identical(y, z))", NULL, expect_identical_linter()) + + # expect_equal calls with explicit tolerance= are OK + expect_lint("expect_equal(x, y, tolerance = 1e-6)", NULL, expect_identical_linter()) + + # ditto for check.attributes = FALSE + expect_lint("expect_equal(x, y, check.attributes = FALSE)", NULL, expect_identical_linter()) +}) + +test_that("expect_identical_linter blocks simple disallowed usages", { + expect_lint( + "expect_equal(x, y)", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) + + # check.attributes = TRUE (set explicitly) gets dinged + expect_lint( + "expect_equal(x, y, check.attributes = TRUE)", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) + + # different usage to redirect to expect_identical + expect_lint( + "expect_true(identical(x, y))", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) +}) + +test_that("expect_identical_linter skips cases likely testing numeric equality", { + expect_lint("expect_equal(x, 1.034)", NULL, expect_identical_linter()) + expect_lint("expect_equal(x, c(1.01, 1.02))", NULL, expect_identical_linter()) + # whole numbers with explicit decimals are OK, even in mixed scenarios + expect_lint("expect_equal(x, c(1.0, 2))", NULL, expect_identical_linter()) + # plain numbers are still caught, however + expect_lint( + "expect_equal(x, 1L)", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) + expect_lint( + "expect_equal(x, 1)", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) + expect_lint( + "expect_equal(x, TRUE)", + rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + expect_identical_linter() + ) +}) + +test_that("expect_identical_linter skips 3e cases needing expect_equal", { + expect_lint("expect_equal(x, y, ignore_attr = 'names')", NULL, expect_identical_linter()) +}) + +# this arose where a helper function was wrapping expect_equal() and +# some of the "allowed" arguments were being passed --> false positive +test_that("expect_identical_linter skips calls using ...", { + expect_lint("expect_equal(x, y, ...)", NULL, expect_identical_linter()) +}) From 49322de7ea4341aa2e7423f1eaad139376f867b8 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sun, 20 Mar 2022 23:26:37 +0000 Subject: [PATCH 2/5] comment about double-lint test --- tests/testthat/test-expect_identical_linter.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testthat/test-expect_identical_linter.R b/tests/testthat/test-expect_identical_linter.R index c98832ed4..1ef3807d4 100644 --- a/tests/testthat/test-expect_identical_linter.R +++ b/tests/testthat/test-expect_identical_linter.R @@ -49,6 +49,8 @@ test_that("expect_identical_linter skips cases likely testing numeric equality", rex::rex("expect_identical(x, y) is the default way of comparing two objects"), expect_identical_linter() ) + # NB: TRUE is a NUM_CONST so we want test matching it, even though this test is + # also a violation of expect_true_false_linter() expect_lint( "expect_equal(x, TRUE)", rex::rex("expect_identical(x, y) is the default way of comparing two objects"), From e044eed281048d0c8bd00cd5e632a1e030a429a5 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sun, 20 Mar 2022 23:31:46 +0000 Subject: [PATCH 3/5] simply test for any named argument --- R/expect_identical_linter.R | 19 ++++++------------- tests/testthat/test-expect_identical_linter.R | 7 ------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/R/expect_identical_linter.R b/R/expect_identical_linter.R index 16ae97f22..9ebb4dacf 100644 --- a/R/expect_identical_linter.R +++ b/R/expect_identical_linter.R @@ -24,10 +24,10 @@ expect_identical_linter <- function() { # outline: # 1. conditions for expect_equal() - # - skip when tolerance= is set - # - skip when check.attributes = FALSE [for 2nd edition tests] - # - skip when any ignore_* is set [for 3rd edition tests] - # specifically ignore_{srcref,attr,encoding,function_env,formula_env} + # - skip when any named argument is set. most commonly this + # is check.attributes (for 2e tests) or one of the ignore_* + # arguments (for 3e tests). This will generate some false + # negatives, but will be much easier to maintain. # - skip cases like expect_equal(x, 1.02) or the constant vector version # where a numeric constant indicates inexact testing is preferable # - skip calls using dots (`...`); see tests @@ -36,14 +36,7 @@ expect_identical_linter <- function() { ( SYMBOL_FUNCTION_CALL[text() = 'expect_equal'] and not( - following-sibling::SYMBOL_SUB[text() = 'tolerance'] - or following-sibling::SYMBOL_SUB[ - ( - text() = 'check.attributes' - and following-sibling::expr[1][NUM_CONST[text() = 'FALSE']] - ) - or starts-with(text(), 'ignore_') - ] + following-sibling::SYMBOL_SUB or following-sibling::expr[ expr[SYMBOL_FUNCTION_CALL[text() = 'c']] and expr[NUM_CONST[contains(text(), '.')]] @@ -64,7 +57,7 @@ expect_identical_linter <- function() { bad_expr, xml_nodes_to_lint, source_file = source_file, - message = paste( + lint_message = paste( "expect_identical(x, y) is the default way of comparing two objects in", "testthat unit tests. Only use expect_equal() if testing numeric", "equality (and specifying tolerance= explicitly) or there's a need to", diff --git a/tests/testthat/test-expect_identical_linter.R b/tests/testthat/test-expect_identical_linter.R index 1ef3807d4..df3655f7e 100644 --- a/tests/testthat/test-expect_identical_linter.R +++ b/tests/testthat/test-expect_identical_linter.R @@ -18,13 +18,6 @@ test_that("expect_identical_linter blocks simple disallowed usages", { expect_identical_linter() ) - # check.attributes = TRUE (set explicitly) gets dinged - expect_lint( - "expect_equal(x, y, check.attributes = TRUE)", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), - expect_identical_linter() - ) - # different usage to redirect to expect_identical expect_lint( "expect_true(identical(x, y))", From 91b510458cb025e4090ce23e63eac4dc978012f8 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sun, 20 Mar 2022 23:42:02 +0000 Subject: [PATCH 4/5] shorten message; put details in man page --- R/expect_identical_linter.R | 17 +++++++++-------- man/expect_identical_linter.Rd | 14 ++++++++++++-- tests/testthat/test-expect_identical_linter.R | 10 +++++----- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/R/expect_identical_linter.R b/R/expect_identical_linter.R index 9ebb4dacf..9d028533e 100644 --- a/R/expect_identical_linter.R +++ b/R/expect_identical_linter.R @@ -11,6 +11,13 @@ #' in which case `ignore_attr = "names"` should be supplied to #' `expect_equal()` (or, for 2nd edition, `check.attributes = FALSE`). #' +#' NB: The linter allows `expect_equal()` in three circumstances: +#' 1. A named argument is set (e.g. `ignore_attr` or `tolerance`) +#' 2. Comparison is made to an explicit decimal, e.g. +#' `expect_equal(x, 1.0)` (implicitly setting `tolerance`) +#' 3. `...` is passed (wrapper functions whcih might set +#' arguments such as `ignore_attr` or `tolerance`) +#' #' @evalRd rd_tags("expect_identical_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export @@ -58,14 +65,8 @@ expect_identical_linter <- function() { xml_nodes_to_lint, source_file = source_file, lint_message = paste( - "expect_identical(x, y) is the default way of comparing two objects in", - "testthat unit tests. Only use expect_equal() if testing numeric", - "equality (and specifying tolerance= explicitly) or there's a need to", - "ignore some attributes, e.g. with ignore_attr = 'names' for the 3rd", - "edition or check.attributes = FALSE for the second. For testing", - "approximate equality to a whole number, you can also avoid setting", - "tolerance= by including an explicit decimal point, e.g.,", - "expect_equal(x, 1.0), not expect_equal(x, 1)." + "Use expect_identical(x, y) by default; resort to expect_equal() only when needed,", + "e.g. when setting ignore_attr= or tolerance=." ), type = "warning" )) diff --git a/man/expect_identical_linter.Rd b/man/expect_identical_linter.Rd index 8d24f7e2f..e47c76cb7 100644 --- a/man/expect_identical_linter.Rd +++ b/man/expect_identical_linter.Rd @@ -7,10 +7,10 @@ expect_identical_linter() } \description{ -\code{\link[testthat:equality-expectations]{testthat::expect_identical()}} should be the default/go-to function for +At Google, \code{\link[testthat:equality-expectations]{testthat::expect_identical()}} should be the default/go-to function for comparing an output to an expected value. \code{expect_true(identical(x, y))} is an equivalent but unadvised method of the same test. Further, -\code{\link[testthat:equality-expectations]{testthat::expect_equal()}}, should only be used when \code{expect_identical()} +\code{\link[testthat:equality-expectations]{testthat::expect_equal()}} should only be used when \code{expect_identical()} is inappropriate, i.e., when \code{x} and \code{y} need only be \emph{numerically equivalent} instead of fully identical (in which case, provide the \verb{tolerance=} argument to \code{expect_equal()} explicitly). This also applies @@ -18,6 +18,16 @@ when it's inconvenient to check full equality (e.g., names can be ignored, in which case \code{ignore_attr = "names"} should be supplied to \code{expect_equal()} (or, for 2nd edition, \code{check.attributes = FALSE}). } +\details{ +NB: The linter allows \code{expect_equal()} in three circumstances: +\enumerate{ +\item A named argument is set (e.g. \code{ignore_attr} or \code{tolerance}) +\item Comparison is made to an explicit decimal, e.g. +\code{expect_equal(x, 1.0)} (implicitly setting \code{tolerance}) +\item \code{...} is passed (wrapper functions whcih might set +arguments such as \code{ignore_attr} or \code{tolerance}) +} +} \seealso{ \link{linters} for a complete list of linters available in lintr. } diff --git a/tests/testthat/test-expect_identical_linter.R b/tests/testthat/test-expect_identical_linter.R index df3655f7e..e157820e3 100644 --- a/tests/testthat/test-expect_identical_linter.R +++ b/tests/testthat/test-expect_identical_linter.R @@ -14,14 +14,14 @@ test_that("expect_identical_linter skips allowed usages", { test_that("expect_identical_linter blocks simple disallowed usages", { expect_lint( "expect_equal(x, y)", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed"), expect_identical_linter() ) # different usage to redirect to expect_identical expect_lint( "expect_true(identical(x, y))", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed"), expect_identical_linter() ) }) @@ -34,19 +34,19 @@ test_that("expect_identical_linter skips cases likely testing numeric equality", # plain numbers are still caught, however expect_lint( "expect_equal(x, 1L)", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed"), expect_identical_linter() ) expect_lint( "expect_equal(x, 1)", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed"), expect_identical_linter() ) # NB: TRUE is a NUM_CONST so we want test matching it, even though this test is # also a violation of expect_true_false_linter() expect_lint( "expect_equal(x, TRUE)", - rex::rex("expect_identical(x, y) is the default way of comparing two objects"), + rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed"), expect_identical_linter() ) }) From f38f73468061f6ee2a60ff1f88f8e74919d4f19b Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 21 Mar 2022 18:17:59 +0000 Subject: [PATCH 5/5] @section --- R/expect_identical_linter.R | 4 +++- man/expect_identical_linter.Rd | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/R/expect_identical_linter.R b/R/expect_identical_linter.R index 9d028533e..5eabbd8af 100644 --- a/R/expect_identical_linter.R +++ b/R/expect_identical_linter.R @@ -11,7 +11,9 @@ #' in which case `ignore_attr = "names"` should be supplied to #' `expect_equal()` (or, for 2nd edition, `check.attributes = FALSE`). #' -#' NB: The linter allows `expect_equal()` in three circumstances: +#' @section Exceptions: +#' +#' The linter allows `expect_equal()` in three circumstances: #' 1. A named argument is set (e.g. `ignore_attr` or `tolerance`) #' 2. Comparison is made to an explicit decimal, e.g. #' `expect_equal(x, 1.0)` (implicitly setting `tolerance`) diff --git a/man/expect_identical_linter.Rd b/man/expect_identical_linter.Rd index e47c76cb7..898a70bad 100644 --- a/man/expect_identical_linter.Rd +++ b/man/expect_identical_linter.Rd @@ -18,8 +18,10 @@ when it's inconvenient to check full equality (e.g., names can be ignored, in which case \code{ignore_attr = "names"} should be supplied to \code{expect_equal()} (or, for 2nd edition, \code{check.attributes = FALSE}). } -\details{ -NB: The linter allows \code{expect_equal()} in three circumstances: +\section{Exceptions}{ + + +The linter allows \code{expect_equal()} in three circumstances: \enumerate{ \item A named argument is set (e.g. \code{ignore_attr} or \code{tolerance}) \item Comparison is made to an explicit decimal, e.g. @@ -28,6 +30,7 @@ NB: The linter allows \code{expect_equal()} in three circumstances: arguments such as \code{ignore_attr} or \code{tolerance}) } } + \seealso{ \link{linters} for a complete list of linters available in lintr. }