# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. with_parameters_test_that( "Running tests:", { if (test_outcome == "success") { testthat::expect_success(testthat::expect_true(case)) } else { failure_message <- "`case` (isn't true|is not TRUE|to be TRUE)" testthat::expect_failure(testthat::expect_true(case), failure_message) } }, test_outcome = c("success", "fail", "null"), case = list(TRUE, FALSE, NULL), .test_name = c("success", "fail", "null") ) with_parameters_test_that( "Names are added", { testthat::expect_identical(.test_name, "case=TRUE") }, case = TRUE ) with_parameters_test_that( "Names can be extracted from cases", { testthat::expect_identical( .test_name, "logical=FALSE, number=1, string=hello" ) }, .cases = data.frame( logical = FALSE, number = 1.0, string = "hello", stringsAsFactors = FALSE ) ) with_parameters_test_that( "Cases are correctly evaluated:", { testthat::expect_length(vec, len) }, cases( one = list(vec = 1L, len = 1L), ten = list(vec = 1:10, len = 10L) ) ) with_parameters_test_that( "Cases are correctly evaluated with names added:", { testthat::expect_identical(.test_name, "vec=1, len=1") }, cases(list(vec = 1L, len = 1L)) ) with_parameters_test_that( "Data frames can be passed to cases:", { result <- rlang::as_function(FUN)(input) testthat::expect_identical(result, out) }, .cases = tibble::tribble( ~.test_name, ~FUN, ~input, ~out, "times", ~ .x * 2L, 2L, 4L, "plus", ~ .x + 3L, 3L, 6L ) ) with_parameters_test_that( "Patrick doesn't throw inappropriate warnings:", { testthat::expect_warning(fun(), regexp = message) }, cases( shouldnt_warn = list(fun = \() 1L + 1L, message = NA), should_warn = list( fun = \() warning("still warn!", call. = FALSE), message = "still warn" ) ) ) test_that("Patrick catches the right class of warning", { testthat::local_mocked_bindings( test_that = function(...) { rlang::warn("New warning", class = "testthat_braces_warning") } ) with_parameters_test_that( "No more warnings:", { testthat::expect_true(truth) }, truth = TRUE ) |> testthat::expect_no_warning() }) # From testthat/tests/testthat/test-test-that.R # Use for checking that line numbers are still correct expectation_lines <- function(code) { code_srcref <- attr(substitute(code), "srcref") if (!is.list(code_srcref)) { stop("code doesn't have srcref", call. = FALSE) } results <- testthat::with_reporter("silent", code)$expectations() unlist(lapply(results, \(x) x$srcref[1L])) - code_srcref[[1L]][1L] } test_that("patrick reports the correct line numbers", { # nolint start: indentation_linter. lines <- expectation_lines({ # line 1 with_parameters_test_that("simple", { # line 2 expect_true(truth) # line 3 }, # line 4 cases( true = list(truth = TRUE), false = list(truth = FALSE) )) }) # nolint end: indentation_linter. expect_identical(lines, c(3L, 3L)) }) test_that('patrick gives a deprecation warning for "test_name"', { with_parameters_test_that( "Warn about `test_name` argument:", { testthat::expect_true(truth) }, truth = TRUE, test_name = "true" ) |> testthat::expect_warning(regexp = "deprecated") with_parameters_test_that( "Warn about `test_name` column:", { testthat::expect_true(truth) }, .cases = tibble::tribble( ~test_name, ~truth, "true", TRUE ) ) |> testthat::expect_warning(regexp = "deprecated") }) expectation_names <- function(code) { expectations <- testthat::with_reporter("silent", code)$expectations() vapply(expectations, \(e) as.character(e$test), character(1L)) } test_that("glue-formatted descriptions and test names supported", { with_parameters_test_that( "testing for (x, y, z) = ({x}, {y}, {z})", { testthat::expect_gt(x + y + z, 0L) }, x = 1:10, y = 2:11, z = 3:12 ) |> expectation_names() |> expect_identical( sprintf("testing for (x, y, z) = (%d, %d, %d)", 1:10, 2:11, 3:12) ) with_parameters_test_that( "testing for (x, y, z):", { testthat::expect_gt(x + y + z, 0L) }, x = 1:10, y = 2:11, z = 3:12, .test_name = "({x}, {y}, {z})" ) |> expectation_names() |> expect_identical( sprintf("testing for (x, y, z): (%d, %d, %d)", 1:10, 2:11, 3:12) ) with_parameters_test_that( "testing for (x, y): ({x}, {y})", { testthat::expect_identical(x, y) }, x = list(NULL, 1:10), y = list(NULL, 1:10) ) |> expectation_names() |> expect_identical(sprintf( "testing for (x, y): ({x}, {y}) x=%1$s, y=%1$s", c("NULL", toString(1:10)) )) |> expect_warning("produced output of length 0") expect_warning("produced output of length 10") # but fail kindly for potential accidental use of glue # c.f. https://github.com/r-lib/lintr/issues/2706 expect_error( with_parameters_test_that("a{b}", { expect_true(TRUE) }, .cases = data.frame(d = 1L)), "Attempt to interpret test stub 'a{b}' with glue failed", fixed = TRUE ) # as well as an escape hatch to work around needing ugly escapes expect_no_error( with_parameters_test_that("a{b}", { expect_true(TRUE) }, .cases = data.frame(d = 1L), .interpret_glue = FALSE) ) })