% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/conjunct_test_linter.R
\name{conjunct_test_linter}
\alias{conjunct_test_linter}
\title{Force \code{&&} conditions to be written separately where appropriate}
\usage{
conjunct_test_linter(
  allow_named_stopifnot = TRUE,
  allow_filter = c("never", "not_dplyr", "always")
)
}
\arguments{
\item{allow_named_stopifnot}{Logical, \code{TRUE} by default. If \code{FALSE}, "named" calls to \code{stopifnot()},
available since R 4.0.0 to provide helpful messages for test failures, are also linted.}

\item{allow_filter}{Character naming the method for linting calls to \code{filter()}. The default, \code{"never"}, means
\code{filter()} and \code{dplyr::filter()} calls are linted; \code{"not_dplyr"} means only \code{dplyr::filter()} calls are linted;
and \code{"always"} means no calls to \code{filter()} are linted. Calls like \code{stats::filter()} are never linted.}
}
\description{
For readability of test outputs, testing only one thing per call to
\code{\link[testthat:logical-expectations]{testthat::expect_true()}} is preferable, i.e.,
\verb{expect_true(A); expect_true(B)} is better than \code{expect_true(A && B)}, and
\verb{expect_false(A); expect_false(B)} is better than \code{expect_false(A || B)}.
}
\details{
Similar reasoning applies to \code{&&} usage inside \code{\link[=stopifnot]{stopifnot()}} and \code{assertthat::assert_that()} calls.

Relatedly, \code{dplyr::filter(DF, A & B)} is the same as \code{dplyr::filter(DF, A, B)}, but the latter will be more readable
/ easier to format for long conditions. Note that this linter assumes usages of \code{filter()} are \code{dplyr::filter()};
if you're using another function named \code{filter()}, e.g. \code{\link[stats:filter]{stats::filter()}}, please namespace-qualify it to avoid
false positives. You can omit linting \code{filter()} expressions altogether via \code{allow_filter = TRUE}.
}
\examples{
# will produce lints
lint(
  text = "expect_true(x && y)",
  linters = conjunct_test_linter()
)

lint(
  text = "expect_false(x || (y && z))",
  linters = conjunct_test_linter()
)

lint(
  text = "stopifnot('x must be a logical scalar' = length(x) == 1 && is.logical(x) && !is.na(x))",
  linters = conjunct_test_linter(allow_named_stopifnot = FALSE)
)

lint(
  text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)",
  linters = conjunct_test_linter()
)

lint(
  text = "filter(mtcars, mpg > 20 & vs == 0)",
  linters = conjunct_test_linter()
)

# okay
lint(
  text = "expect_true(x || (y && z))",
  linters = conjunct_test_linter()
)

lint(
  text = 'stopifnot("x must be a logical scalar" = length(x) == 1 && is.logical(x) && !is.na(x))',
  linters = conjunct_test_linter(allow_named_stopifnot = TRUE)
)

lint(
  text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)",
  linters = conjunct_test_linter(allow_filter = "always")
)

lint(
  text = "filter(mtcars, mpg > 20 & vs == 0)",
  linters = conjunct_test_linter(allow_filter = "not_dplyr")
)

lint(
  text = "stats::filter(mtcars$cyl, mtcars$mpg > 20 & mtcars$vs == 0)",
  linters = conjunct_test_linter()
)

}
\seealso{
\link{linters} for a complete list of linters available in lintr.
}
\section{Tags}{
\link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability}
}
