File: reporter.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 (152 lines) | stat: -rw-r--r-- 5,009 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
#' Manage test reporting
#'
#' The job of a reporter is to aggregate the results from files, tests, and
#' expectations and display them in an informative way. Every testthat function
#' that runs multiple tests provides a `reporter` argument which you can
#' use to override the default (which is selected by [default_reporter()]).
#'
#' You only need to use this `Reporter` object directly if you are creating
#' a new reporter. Currently, creating new Reporters is undocumented,
#' so if you want to create your own, you'll need to make sure that you're
#' familiar with [R6](https://adv-r.hadley.nz/R6.html) and then need read the
#' source code for a few.
#'
#' @keywords internal
#' @export
#' @export Reporter
#' @aliases Reporter
#' @importFrom R6 R6Class
#' @family reporters
#' @examples
#' path <- testthat_example("success")
#'
#' test_file(path)
#' # Override the default by supplying the name of a reporter
#' test_file(path, reporter = "minimal")
Reporter <- R6::R6Class("Reporter",
  public = list(
    capabilities = list(parallel_support = FALSE, parallel_updates = FALSE),
    start_reporter = function() {},
    start_context =  function(context) {},
    start_test =     function(context, test) {},
    start_file =     function(filename) {},
    add_result =     function(context, test, result) {},
    end_test =       function(context, test) {},
    end_context =    function(context) {},
    end_reporter =   function() {},
    end_file =       function() {},
    is_full =        function() FALSE,
    update =         function() {},

    width = 80,
    unicode = TRUE,
    crayon = TRUE,
    rstudio = TRUE,
    hyperlinks = TRUE,

    out = NULL,

    initialize = function(file = getOption("testthat.output_file", stdout())) {
      if (is.character(file)) {
        file <- normalizePath(file, mustWork = FALSE)
      }
      self$out <- file
      if (is.character(self$out) && file.exists(self$out)) {
        # If writing to a file, overwrite it if it exists
        file.remove(self$out)
      }

      # Capture at init so not affected by test settings
      self$width <- cli::console_width()
      self$unicode <- cli::is_utf8_output()
      self$crayon <- cli::num_ansi_colors() > 1
      self$rstudio <- Sys.getenv("RSTUDIO") == "1"
      self$hyperlinks <- cli::ansi_hyperlink_types()[["run"]]
    },

    # To be used when the reporter needs to produce output inside of an active
    # test, which is almost always from $add_result()
    local_user_output = function(.env = parent.frame()) {
      local_reproducible_output(
        width = self$width,
        crayon = self$crayon,
        rstudio = self$rstudio,
        hyperlinks = self$hyperlinks,
        .env = .env
      )
      # Can't set unicode with local_reproducible_output() because it can
      # generate a skip if you're temporarily using a non-UTF-8 locale
      withr::local_options(cli.unicode = self$unicode, .local_envir = .env)
    },

    cat_tight = function(...) {
      cat(..., sep = "", file = self$out, append = TRUE)
    },

    cat_line = function(...) {
      cli::cat_line(..., file = self$out)
    },

    rule = function(...) {
      cli::cat_rule(..., file = self$out)
    },

    # The hierarchy of contexts are implied - a context starts with a
    # call to context(), and ends either with the end of the file, or
    # with the next call to context() in the same file. These private
    # methods paper over the details so that context appear to work
    # in the same way as tests and expectations.
    .context = NULL,
    .start_context = function(context) {
      if (!is.null(self$.context)) {
        self$end_context(self$.context)
      }
      self$.context <- context
      self$start_context(context)

      invisible()
    },
    end_context_if_started = function(context) {
      if (!is.null(self$.context)) {
        self$end_context(self$.context)
        self$.context <- NULL
      }
      invisible()
    }
  )
)

#' Retrieve the default reporter
#'
#' The defaults are:
#' * [ProgressReporter] for interactive, non-parallel; override with
#'   `testthat.default_reporter`
#' * [ParallelProgressReporter] for interactive, parallel packages;
#'   override with `testthat.default_parallel_reporter`
#' * [CompactProgressReporter] for single-file interactive; override with
#'   `testthat.default_compact_reporter`
#' * [CheckReporter] for R CMD check; override with `testthat.default_check_reporter`
#'
#' @export
#' @keywords internal
default_reporter <- function() {
  getOption("testthat.default_reporter", "Progress")
}

#' @export
#' @rdname default_reporter
default_parallel_reporter <- function() {
  getOption("testthat.default_parallel_reporter", "ParallelProgress")
}

#' @export
#' @rdname default_reporter
default_compact_reporter <- function() {
  getOption("testthat.default_compact_reporter", "CompactProgress")
}

#' @export
#' @rdname default_reporter
check_reporter <- function() {
  getOption("testthat.default_check_reporter", "Check")
}