File: try-again.R

package info (click to toggle)
r-cran-testthat 3.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,048 kB
  • sloc: cpp: 9,269; sh: 14; ansic: 14; makefile: 5
file content (48 lines) | stat: -rw-r--r-- 1,243 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#' Evaluate an expectation multiple times until it succeeds
#'
#' If you have a flaky test, you can use `try_again()` to run it a few times
#' until it succeeds. In most cases, you are better fixing the underlying
#' cause of the flakeyness, but sometimes that's not possible.
#'
#' @param times Number of times to retry.
#' @param code Code to evaluate.
#' @export
#' @examples
#' usually_return_1 <- function(i) {
#'   if (runif(1) < 0.1) 0 else 1
#' }
#'
#' \dontrun{
#' # 10% chance of failure:
#' expect_equal(usually_return_1(), 1)
#'
#' # 1% chance of failure:
#' try_again(1, expect_equal(usually_return_1(), 1))
#'
#' # 0.1% chance of failure:
#' try_again(2, expect_equal(usually_return_1(), 1))
#' }
try_again <- function(times, code) {
  check_number_whole(times, min = 1)

  code <- enquo(code)

  i <- 1
  while (i <= times) {
    tryCatch(
      return(eval(get_expr(code), get_env(code))),
      expectation_failure = function(cnd) {
        cli::cli_inform(c(i = "Expectation failed; trying again ({i})..."))
        NULL
      },
      error = function(cnd) {
        cli::cli_inform(c(i = "Expectation errored; trying again ({i})..."))
        NULL
      }
    )

    i <- i + 1
  }

  eval(get_expr(code), get_env(code))
}