File: local.R

package info (click to toggle)
r-cran-testthat 3.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,452 kB
  • sloc: cpp: 9,261; ansic: 37; sh: 14; makefile: 5
file content (201 lines) | stat: -rw-r--r-- 7,805 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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#' Locally set options for maximal test reproducibility
#'
#' @description
#' `local_test_context()` is run automatically by `test_that()` but you may
#' want to run it yourself if you want to replicate test results interactively.
#' If run inside a function, the effects are automatically reversed when the
#' function exits; if running in the global environment, use
#' [withr::deferred_run()] to undo.
#'
#' `local_reproducible_output()` is run automatically by `test_that()` in the
#' 3rd edition. You might want to call it to override the the default settings
#' inside a test, if you want to test Unicode, coloured output, or a
#' non-standard width.
#'
#' @details
#' `local_test_context()` sets `TESTTHAT = "true"`, which ensures that
#' [is_testing()] returns `TRUE` and allows code to tell if it is run by
#' testthat.
#'
#' In the third edition, `local_test_context()` also calls
#' `local_reproducible_output()` which temporary sets the following options:
#'
#' * `cli.dynamic = FALSE` so that tests assume that they are not run in
#'   a dynamic console (i.e. one where you can move the cursor around).
#' * `cli.unicode` (default: `FALSE`) so that the cli package never generates
#'   unicode output (normally cli uses unicode on Linux/Mac but not Windows).
#'   Windows can't easily save unicode output to disk, so it must be set to
#'   false for consistency.
#' * `cli.condition_width = Inf` so that new lines introduced while
#'   width-wrapping condition messages don't interfere with message matching.
#' * `crayon.enabled` (default: `FALSE`) suppresses ANSI colours generated by
#'   the cli and crayon packages (normally colours are used if cli detects
#'   that you're in a terminal that supports colour).
#' * `cli.num_colors` (default: `1L`) Same as the crayon option.
#' * `lifecycle_verbosity = "warning"` so that every lifecycle problem always
#'   generates a warning (otherwise deprecated functions don't generate a
#'   warning every time).
#' * `max.print = 99999` so the same number of values are printed.
#' * `OutDec = "."` so numbers always uses `.` as the decimal point
#'   (European users sometimes set `OutDec = ","`).
#' * `rlang_interactive = FALSE` so that [rlang::is_interactive()] returns
#'   `FALSE`, and code that uses it pretends you're in a non-interactive
#'   environment.
#' * `useFancyQuotes = FALSE` so base R functions always use regular (straight)
#'   quotes (otherwise the default is locale dependent, see [sQuote()] for
#'   details).
#' * `width` (default: 80) to control the width of printed output (usually this
#'   varies with the size of your console).
#'
#' And modifies the following env vars:
#'
#' * Unsets `RSTUDIO`, which ensures that RStudio is never detected as running.
#' * Sets `LANGUAGE = "en"`, which ensures that no message translation occurs.
#'
#' Finally, it sets the collation locale to "C", which ensures that character
#' sorting the same regardless of system locale.
#'
#' @export
#' @param .env Environment to use for scoping; expert use only.
#' @examples
#' local({
#'   local_test_context()
#'   cat(cli::col_blue("Text will not be colored"))
#'   cat(cli::symbol$ellipsis)
#'   cat("\n")
#' })
local_test_context <- function(.env = parent.frame()) {
  withr::local_envvar("_R_CHECK_BROWSER_NONINTERACTIVE_" = "true", TESTTHAT = "true", .local_envir = .env)
  if (edition_get() >= 3) {
    local_reproducible_output(.env = .env)
  }
}

#' @export
#' @param width Value of the `"width"` option.
#' @param crayon Determines whether or not crayon (now cli) colour
#'   should be applied.
#' @param unicode Value of the `"cli.unicode"` option.
#'   The test is skipped if `` l10n_info()$`UTF-8` `` is `FALSE`.
#' @param rstudio Should we pretend that we're inside of RStudio?
#' @param hyperlinks Should we use ANSI hyperlinks.
#' @param lang Optionally, supply a BCP47 language code to set the language
#'   used for translating error messages. This is a lower case two letter
#'   [ISO 639 country code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes),
#'   optionally followed by "_" or "-" and an upper case two letter
#'   [ISO 3166 region code](https://en.wikipedia.org/wiki/ISO_3166-2).
#' @rdname local_test_context
#' @examples
#' test_that("test ellipsis", {
#'   local_reproducible_output(unicode = FALSE)
#'   expect_equal(cli::symbol$ellipsis, "...")
#'
#'   local_reproducible_output(unicode = TRUE)
#'   expect_equal(cli::symbol$ellipsis, "\u2026")
#' })
local_reproducible_output <- function(width = 80,
                                      crayon = FALSE,
                                      unicode = FALSE,
                                      rstudio = FALSE,
                                      hyperlinks = FALSE,
                                      lang = "C",
                                      .env = parent.frame()) {

  if (unicode) {
    # If you force unicode display, you _must_ skip the test on non-utf8
    # locales; otherwise it's guaranteed to fail
    skip_if(!l10n_info()$`UTF-8`, "non utf8 locale")
  }

  local_width(width = width, .env = .env)
  withr::local_options(
    crayon.enabled = crayon,
    cli.hyperlink = hyperlinks,
    cli.hyperlink_run = hyperlinks,
    cli.hyperlink_help = hyperlinks,
    cli.hyperlink_vignette = hyperlinks,
    cli.dynamic = FALSE,
    cli.unicode = unicode,
    cli.condition_width = Inf,
    cli.num_colors = if (crayon) 8L else 1L,
    useFancyQuotes = FALSE,
    lifecycle_verbosity = "warning",
    OutDec = ".",
    rlang_interactive = FALSE,
    max.print = 99999,
    .local_envir = .env,
  )
  withr::local_envvar(
    RSTUDIO = if (rstudio) 1 else NA,
    RSTUDIO_SESSION_PID = if (rstudio) Sys.getpid() else NA,
    RSTUDIO_CHILD_PROCESS_PANE = if (rstudio) "build" else NA,
    RSTUDIO_CLI_HYPERLINKS = if (rstudio) 1 else NA,
    .local_envir = .env
  )

  withr::local_language(lang, .local_envir = .env)
  withr::local_collate("C", .local_envir = .env)
}

local_reporter_output <- function(.env = parent.frame()) {
  reporter <- get_reporter()
  if (!is.null(reporter)) {
    reporter$local_user_output(.env)
  }
}

waldo_compare <- function(x, y, ..., x_arg = "x", y_arg = "y") {
  # Need to very carefully isolate this change to this function - can not set
  # in expectation functions because part of expectation handling bubbles
  # up through calling handlers, which are run before on.exit()
  local_reporter_output()

  waldo::compare(x, y,..., x_arg = x_arg, y_arg = y_arg)
}

local_width <- function(width = 80, .env = parent.frame()) {
  withr::local_options(width = width, cli.width = width, .local_envir = .env)
  withr::local_envvar(RSTUDIO_CONSOLE_WIDTH = width, .local_envir = .env)
}


#' Locally set test directory options
#'
#' For expert use only.
#'
#' @param path Path to directory of files
#' @param package Optional package name, if known.
#' @export
#' @keywords internal
local_test_directory <- function(path, package = NULL, .env = parent.frame()) {
  # Set edition before changing working directory in case path is relative
  local_edition(find_edition(path, package), .env = .env)

  withr::local_dir(
    path,
    .local_envir = .env
  )
  withr::local_envvar(
    R_TESTS = "",
    TESTTHAT = "true",
    TESTTHAT_PKG = package,
    .local_envir = .env
  )
}

local_interactive_reporter <- function(.env = parent.frame()) {
  # Definitely not on CRAN
  withr::local_envvar(NOT_CRAN = "true", .local_envir = .env)
  withr::local_options(testthat_interactive = TRUE, .local_envir = .env)

  # Use edition from working directory
  local_edition(find_edition("."), .env = .env)

  # Use StopReporter
  reporter <- StopReporter$new()
  old <- set_reporter(reporter)
  withr::defer(reporter$stop_if_needed(), envir = .env)
  withr::defer(set_reporter(old), envir = .env)

  reporter
}