Skip to content

Commit

Permalink
Two minor improvements (#590)
Browse files Browse the repository at this point in the history
* explicit perl and fixed arguments to expect_match()

to allow reporting an unescaped label with `fixed = TRUE`

* improve behavior of summary reporter in case of overflow

* update infinite recursion test for R 3.4.0
  • Loading branch information
krlmlr authored Jun 6, 2017
1 parent 092bded commit c7e8330
Show file tree
Hide file tree
Showing 18 changed files with 126 additions and 58 deletions.
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# testthat 1.0.2.9000

* Improved behavior of the `SummaryReporter` when the maximum number of errors
reported is reached.

* `expect_match()` now accepts explicit `perl` and `fixed` arguments, and adapts
the failure message to the value of `fixed`. This also affects other expectations
that forward to `expect_match()`, like `expect_output()`, `expect_message()`,
`expect_warning()`, and `expect_error()`.

* New option `testthat.default_check_reporter`, defaults to `"check"`.
Continuous Integration system can set this option before evaluating
package test sources in order to direct test result details to known
Expand Down
2 changes: 1 addition & 1 deletion R/expect-output.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#' that `options(warn)` has no effect.
#'
#' @inheritParams expect_that
#' @inheritParams expect_match
#' @inheritDotParams expect_match -object -regexp -info -label
#' @param regexp regular expression to test against.
#'
#' If `NULL`, the default, asserts that there should be an output,
Expand Down
20 changes: 12 additions & 8 deletions R/expectations-matches.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#' Expectation: does string/output/message/warning/error match a regular expression?
#' Expectation: does string match a regular expression?
#'
#' @inheritParams expect_that
#' @inheritParams base::grepl
#' @param regexp Regular expression to test against.
#' @param all Should all elements of actual value match `regexp` (TRUE),
#' or does only one need to match (FALSE)
#' @param ... Additional arguments passed on to [grepl()], e.g.
#' `ignore.case` or `fixed`.
#' @inheritDotParams base::grepl -pattern -x -perl -fixed
#' @family expectations
#' @export
#' @examples
Expand All @@ -18,8 +18,12 @@
#' # Zero-length inputs always fail
#' expect_match(character(), ".")
#' }
expect_match <- function(object, regexp, ..., all = TRUE,
expect_match <- function(object, regexp, perl = FALSE, fixed = FALSE, ..., all = TRUE,
info = NULL, label = NULL) {

if (fixed) escape <- identity
else escape <- escape_regex

stopifnot(is.character(regexp), length(regexp) == 1)
label <- make_label(object, label)

Expand All @@ -28,19 +32,19 @@ expect_match <- function(object, regexp, ..., all = TRUE,
fail(sprintf("%s is empty.", label))
}

matches <- grepl(regexp, object, ...)
matches <- grepl(regexp, object, perl = perl, fixed = fixed, ...)

if (length(object) == 1) {
values <- paste0("Actual value: \"", escape_regex(encodeString(object)), "\"")
values <- paste0("Actual value: \"", escape(encodeString(object)), "\"")
} else {
values <- paste0("Actual values:\n",
paste0("* ", escape_regex(encodeString(object)), collapse = "\n"))
paste0("* ", escape(encodeString(object)), collapse = "\n"))
}
expect(
if (all) all(matches) else any(matches),
sprintf(
"%s does not match %s.\n%s",
escape_regex(label),
escape(label),
encodeString(regexp, quote = '"'),
values
),
Expand Down
19 changes: 12 additions & 7 deletions R/reporter-summary.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,12 @@ SummaryReporter <- R6::R6Class("SummaryReporter", inherit = Reporter,
self$omit_dots <- omit_dots
},

start_context = function(context) {
self$cat_tight(context, ": ")
is_full = function() {
self$failures$size() >= self$max_reports
},

end_test = function(context, test) {
if (self$failures$size() >= self$max_reports) {
self$cat_line()
stop("Reached maximum number of reports.", call. = FALSE)
}
start_context = function(context) {
self$cat_tight(context, ": ")
},

end_context = function(context) {
Expand Down Expand Up @@ -77,6 +74,14 @@ SummaryReporter <- R6::R6Class("SummaryReporter", inherit = Reporter,
private$cat_reports("Warnings", warnings, Inf, skip_summary)
private$cat_reports("Failed", failures, self$max_reports, failure_summary)

if (self$failures$size() >= self$max_reports) {
self$cat_line(
"Maximum number of ", self$max_reports, " failures reached, ",
"some test results may be missing."
)
self$cat_line()
}

self$rule("DONE", pad = "=")
if (self$show_praise) {
if (length(failures) == 0 && runif(1) < 0.1) {
Expand Down
1 change: 1 addition & 0 deletions R/reporter.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Reporter <- R6::R6Class("Reporter",
end_test = function(context, test) {},
end_context = function(context) {},
end_reporter = function() {},
is_full = function() FALSE,

out = NULL,

Expand Down
1 change: 1 addition & 0 deletions R/test-files.R
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ test_file <- function(path, reporter = default_reporter(), env = test_env(),
library(testthat)

reporter <- find_reporter(reporter)
if (reporter$is_full()) return()

if (load_helpers) {
source_test_helpers(dirname(path), env = env)
Expand Down
22 changes: 17 additions & 5 deletions man/expect_match.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions man/output-expectations.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions tests/testthat/reporters/check.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ evaluation nested too deeply: infinite recursion / options(expressions=)?
9: f() at reporters/tests.R:42
10: f() at reporters/tests.R:42
...
164: f() at reporters/tests.R:42
165: f() at reporters/tests.R:42
166: f() at reporters/tests.R:42
167: f() at reporters/tests.R:42
168: f() at reporters/tests.R:42
169: f() at reporters/tests.R:42
170: f() at reporters/tests.R:42
171: f() at reporters/tests.R:42
172: f() at reporters/tests.R:42
173: f() at reporters/tests.R:42
174: f() at reporters/tests.R:42
175: f() at reporters/tests.R:42
176: f() at reporters/tests.R:42
177: f() at reporters/tests.R:42
178: f() at reporters/tests.R:42
179: f() at reporters/tests.R:42

testthat results ================================================================
OK: 7 SKIPPED: 3 FAILED: 7
Expand Down
6 changes: 6 additions & 0 deletions tests/testthat/reporters/debug.txt
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@
171: tests.R#42: f()
172: tests.R#42: f()
173: tests.R#42: f()
174: tests.R#42: f()
175: tests.R#42: f()
176: tests.R#42: f()
177: tests.R#42: f()
178: tests.R#42: f()
179: tests.R#42: f()

1: tests.R#49: skip("skip")

Expand Down
14 changes: 7 additions & 7 deletions tests/testthat/reporters/junit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@
9: f() at reporters/tests.R:42
10: f() at reporters/tests.R:42
...
164: f() at reporters/tests.R:42
165: f() at reporters/tests.R:42
166: f() at reporters/tests.R:42
167: f() at reporters/tests.R:42
168: f() at reporters/tests.R:42
169: f() at reporters/tests.R:42
170: f() at reporters/tests.R:42
171: f() at reporters/tests.R:42
172: f() at reporters/tests.R:42
173: f() at reporters/tests.R:42</error>
173: f() at reporters/tests.R:42
174: f() at reporters/tests.R:42
175: f() at reporters/tests.R:42
176: f() at reporters/tests.R:42
177: f() at reporters/tests.R:42
178: f() at reporters/tests.R:42
179: f() at reporters/tests.R:42</error>
</testcase>
</testsuite>
<testsuite name="Skips" timestamp="1999:12:31 23:59:59" hostname="nodename" tests="3" skipped="3" failures="0" errors="0" time="0">
Expand Down
24 changes: 23 additions & 1 deletion tests/testthat/reporters/summary-2.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
Expectations: .12
Expectations: .1234.
Errors: 56
Recursion: 7
Skips: SSS
Warnings: WWW
Output: ..

Skipped ------------------------------------------------------------------------
1. Skip:1 (@tests.R#49) - skip

2. Skip:2 (@tests.R#54) - skip

3. Skip:3 (@tests.R#57) - Empty test

Warnings -----------------------------------------------------------------------
1. Warning:1 (@tests.R#63) - abc

2. Warning:2 (@tests.R#67) - def

3. Warning:2 (@tests.R#68) - ghi

Failed -------------------------------------------------------------------------
1. Failure: Failure:1 (@tests.R#8) ---------------------------------------------
Expand All @@ -7,6 +26,9 @@ Failure has been forced

2. Failure: Failure:2a (@tests.R#12) -------------------------------------------
Failure has been forced
... and 5 more


Maximum number of 2 failures reached, some test results may be missing.

DONE ===========================================================================
12 changes: 6 additions & 6 deletions tests/testthat/reporters/summary-no-dots.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ evaluation nested too deeply: infinite recursion / options(expressions=)?
9: f() at reporters/tests.R:42
10: f() at reporters/tests.R:42
...
164: f() at reporters/tests.R:42
165: f() at reporters/tests.R:42
166: f() at reporters/tests.R:42
167: f() at reporters/tests.R:42
168: f() at reporters/tests.R:42
169: f() at reporters/tests.R:42
170: f() at reporters/tests.R:42
171: f() at reporters/tests.R:42
172: f() at reporters/tests.R:42
173: f() at reporters/tests.R:42
174: f() at reporters/tests.R:42
175: f() at reporters/tests.R:42
176: f() at reporters/tests.R:42
177: f() at reporters/tests.R:42
178: f() at reporters/tests.R:42
179: f() at reporters/tests.R:42

DONE ===========================================================================
12 changes: 6 additions & 6 deletions tests/testthat/reporters/summary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ evaluation nested too deeply: infinite recursion / options(expressions=)?
9: f() at reporters/tests.R:42
10: f() at reporters/tests.R:42
...
164: f() at reporters/tests.R:42
165: f() at reporters/tests.R:42
166: f() at reporters/tests.R:42
167: f() at reporters/tests.R:42
168: f() at reporters/tests.R:42
169: f() at reporters/tests.R:42
170: f() at reporters/tests.R:42
171: f() at reporters/tests.R:42
172: f() at reporters/tests.R:42
173: f() at reporters/tests.R:42
174: f() at reporters/tests.R:42
175: f() at reporters/tests.R:42
176: f() at reporters/tests.R:42
177: f() at reporters/tests.R:42
178: f() at reporters/tests.R:42
179: f() at reporters/tests.R:42

DONE ===========================================================================
12 changes: 6 additions & 6 deletions tests/testthat/reporters/tap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ not ok 9 Recursion:1
9: f() at reporters/tests.R:42
10: f() at reporters/tests.R:42
...
164: f() at reporters/tests.R:42
165: f() at reporters/tests.R:42
166: f() at reporters/tests.R:42
167: f() at reporters/tests.R:42
168: f() at reporters/tests.R:42
169: f() at reporters/tests.R:42
170: f() at reporters/tests.R:42
171: f() at reporters/tests.R:42
172: f() at reporters/tests.R:42
173: f() at reporters/tests.R:42
174: f() at reporters/tests.R:42
175: f() at reporters/tests.R:42
176: f() at reporters/tests.R:42
177: f() at reporters/tests.R:42
178: f() at reporters/tests.R:42
179: f() at reporters/tests.R:42
# Context Skips
ok 10 # SKIP skip
ok 11 # SKIP skip
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/reporters/teamcity.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
##teamcity[testSuiteStarted name='Recursion']
##teamcity[testSuiteStarted name='Recursion:1']
##teamcity[testStarted name='expectation 1']
##teamcity[testFailed name='expectation 1' message='evaluation nested too deeply: infinite recursion / options(expressions=)?' details='1: f() at reporters/tests.R:43|n2: f() at reporters/tests.R:42|n3: f() at reporters/tests.R:42|n4: f() at reporters/tests.R:42|n5: f() at reporters/tests.R:42|n6: f() at reporters/tests.R:42|n7: f() at reporters/tests.R:42|n8: f() at reporters/tests.R:42|n9: f() at reporters/tests.R:42|n10: f() at reporters/tests.R:42|n...|n164: f() at reporters/tests.R:42|n165: f() at reporters/tests.R:42|n166: f() at reporters/tests.R:42|n167: f() at reporters/tests.R:42|n168: f() at reporters/tests.R:42|n169: f() at reporters/tests.R:42|n170: f() at reporters/tests.R:42|n171: f() at reporters/tests.R:42|n172: f() at reporters/tests.R:42|n173: f() at reporters/tests.R:42']
##teamcity[testFailed name='expectation 1' message='evaluation nested too deeply: infinite recursion / options(expressions=)?' details='1: f() at reporters/tests.R:43|n2: f() at reporters/tests.R:42|n3: f() at reporters/tests.R:42|n4: f() at reporters/tests.R:42|n5: f() at reporters/tests.R:42|n6: f() at reporters/tests.R:42|n7: f() at reporters/tests.R:42|n8: f() at reporters/tests.R:42|n9: f() at reporters/tests.R:42|n10: f() at reporters/tests.R:42|n...|n170: f() at reporters/tests.R:42|n171: f() at reporters/tests.R:42|n172: f() at reporters/tests.R:42|n173: f() at reporters/tests.R:42|n174: f() at reporters/tests.R:42|n175: f() at reporters/tests.R:42|n176: f() at reporters/tests.R:42|n177: f() at reporters/tests.R:42|n178: f() at reporters/tests.R:42|n179: f() at reporters/tests.R:42']
##teamcity[testFinished name='expectation 1']
##teamcity[testSuiteFinished name='Recursion:1']

Expand Down
4 changes: 4 additions & 0 deletions tests/testthat/test-expect-match.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ test_that("special regex characters are escaped in output", {
expect_equal(error, "\"f\\(\\) test\" does not match \"f() test\".\nActual value: \"f\\(\\) test\"\n")
})

test_that("correct reporting of expected label", {
expect_failure(expect_match("[a]", "[b]"), escape_regex("[a]"), fixed = TRUE)
expect_failure(expect_match("[a]", "[b]", fixed = TRUE), "[a]", fixed = TRUE)
})
3 changes: 1 addition & 2 deletions tests/testthat/test-reporter.R
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ test_that("reporters produce consistent output", {
)
save_report("check", error_regexp = NULL)
save_report("summary", SummaryReporter$new(show_praise = FALSE, omit_dots = FALSE))
save_report("summary-2", SummaryReporter$new(show_praise = FALSE, max_reports = 2),
error_regexp = "Reached maximum number of reports")
save_report("summary-2", SummaryReporter$new(show_praise = FALSE, max_reports = 2))
save_report("summary-no-dots", SummaryReporter$new(show_praise = FALSE, omit_dots = TRUE))
save_report("location")
save_report("minimal")
Expand Down

0 comments on commit c7e8330

Please sign in to comment.