testit/0000755000175100001440000000000013110472064011602 5ustar hornikuserstestit/inst/0000755000175100001440000000000012660727755012602 5ustar hornikuserstestit/inst/rstudio/0000755000175100001440000000000012660730017014254 5ustar hornikuserstestit/inst/rstudio/addins.dcf0000644000175100001440000000017012660730065016175 0ustar hornikusersName: Insert %==% Description: Insert the infix operator %==% from testit. Binding: insert_identical Interactive: false testit/tests/0000755000175100001440000000000012661414562012755 5ustar hornikuserstestit/tests/testit/0000755000175100001440000000000013107757635014300 5ustar hornikuserstestit/tests/testit/test-utils.R0000644000175100001440000000106612763567040016537 0ustar hornikuserslibrary(testit) # no need to use testit:::available_dir() assert( 'available_dir() should find an existing directory', file.exists( available_dir(c('foobar', 'whatever', '~', system.file('man', package = 'testit'))) ), has_error(available_dir('asdfasdf')) ) exprs = parse(text = 'if (TRUE) {T&F}\n1+1') assert( 'deparse_key() fetches the n-1 element if code is in {}', deparse_key(exprs[[1]]) == 'if (TRUE) { .... T & F' ) assert( 'deparse_key() returns the parsed code if length == 1', deparse_key(exprs[[2]]) == '1 + 1' ) insert_identical() testit/tests/testit/test-assert.R0000644000175100001440000000174313107757635016706 0ustar hornikuserslibrary(testit) assert('assert works', 1 == 1) # Okay, that is kind of cheating assert( 'assert() should signal an error if a condition does not hold', has_error(assert('this should produce an error', 1 == 2)) ) # a meaningless test in terms of R (failure is irrelevant to Frequentist or Bayesian) try(assert( 'Frequentists must be correct (http://xkcd.com/1132/)', 'The sun has exploded!', sample(6, 2) == c(6, 6) ), silent = !interactive()) # fail logical(0) assert( 'assert() should stop on logical(0)', has_error(assert('1 equals integer(0)', 1 == integer(0))) ) assert( 'the infix operator %==% works', 1 %==% 1, !(1 %==% 1L) ) assert( 'has_warning() works', has_warning(warning('An intentional warning')), has_warning((function() {1:2 + 1:3})()) ) assert( 'has_error() works', has_error(stop('An intentional error')), has_error(1 + 'a') ) assert('tests can be written in () in a single {}', { (1 == 1L) z = 1:10 (rev(z) %==% 10:1) !!TRUE }) testit/tests/test-error/0000755000175100001440000000000012661414633015062 5ustar hornikuserstestit/tests/test-error/test-error.R0000644000175100001440000000003612661414653017314 0ustar hornikusersstop('An intentional error!') testit/tests/test-all.R0000644000175100001440000000011112661420115014605 0ustar hornikuserslibrary(testit) test_pkg('testit') try(test_pkg('testit', 'test-error')) testit/NAMESPACE0000644000175100001440000000020313057301552013017 0ustar hornikusers# Generated by roxygen2: do not edit by hand export("%==%") export(assert) export(has_error) export(has_warning) export(test_pkg) testit/NEWS0000644000175100001440000000362013107752022012303 0ustar hornikusers CHANGES IN testit VERSION 0.7 (unreleased) NEW FEATURES o provided an alternative way to write assertions of the form assert('fact', {(condition_2); (condition_2)}); see ?testit::assert for more information CHANGES IN testit VERSION 0.6 NEW FEATURES o test_pkg() runs package tests with top-level environment being set to the namespace of the tested package (thanks, @kalibera, #3) MAJOR CHANGES o all test scripts (test-*.R) are assumed to be encoded in UTF-8 if they contain multibyte characters CHANGES IN testit VERSION 0.5 NEW FEATURES o added an infix operator `%==%` as an alias of identical() (in RStudio, you can use an add-in to insert the text `%==%`) MINOR CHANGES o test_pkg() will print out the filename of the R script that errored CHANGES IN testit VERSION 0.4 MAJOR CHANGES o the `fact` argument of `assert()` is optional now: all arguments of `assert()` can be test conditions CHANGES IN testit VERSION 0.3 MAJOR CHANGES o the test files have to be named of the form test-*.R (or test-*.r), i.e. they have to use the prefix test- o the test environment is always cleaned (all objects removed) before the next test is run CHANGES IN testit VERSION 0.2.1 MINOR CHANGES o fixed a test that failed under R 2.15.x because the argument keep.source did not exist in parse() CHANGES IN testit VERSION 0.2 MAJOR CHANGES o assert() does not use base::stopifnot() any more; a tailored version of stopifnot() is used now; see ?assert for the differences between this version and base::stopifnot(); in particular, assert(fact, logical(0)) will fail but stopifnot(logical(0)) will not CHANGES IN testit VERSION 0.1 NEW FEATURES o this is the first version of testit; the source code is hosted on Github: https://github.com/yihui/testit o added functions assert(), test_pkg(), has_error() and has_warning() testit/R/0000755000175100001440000000000013110216270011776 5ustar hornikuserstestit/R/utils.R0000644000175100001440000000331013010443574013266 0ustar hornikusers# find an available dir available_dir = function(dirs) { for (i in dirs) { if (utils::file_test('-d', i)) return(i) } stop('none of the directories exists:\n', paste(utils::formatUL(dirs), collapse = '\n')) } # tailored for assert(): extract the expression that is likely to be useful for # diagnostics if possible deparse_key = function(expr) { x = deparse(expr, width.cutoff = 100L) if ((n <- length(x)) <= 1) return(x) # if expression is in {}, fetch the line n-1, otherwise use the first line paste(x[1], '....', if (x[n] == '}') sub('^\\s*', '', x[n - 1L])) } # whether every element of x is strictly TRUE all_true = function(x) { is.logical(x) && length(x) && !any(is.na(x)) && all(x) } insert_identical = function() { if (!has_error(rstudioapi::verifyAvailable())) rstudioapi::insertText(text = ' %==% ') } # This function is a modification of base::sys.source. It allows to specify # the top-level environment, which is by default "envir" (the same as in # base::sys.source), but for package testing it is desirable to use the # package namespace to mimick the environment structure used when packages # are running. This function assumes that chdir = FALSE and keep.source = TRUE. sys.source2 = function(file, envir, top.env = as.environment(envir)) { oop = options(keep.source = TRUE, topLevelEnvironment = top.env) on.exit(options(oop)) lines = readLines(file, warn = FALSE, encoding = 'UTF-8') srcfile = srcfilecopy(file, lines, file.mtime(file), isFile = TRUE) exprs = parse(text = lines, srcfile = srcfile, encoding = 'UTF-8') if (length(exprs) == 0L) return() owd = setwd(dirname(file)); on.exit(setwd(owd), add = TRUE) for (i in seq_along(exprs)) eval(exprs[i], envir) } testit/R/testit.R0000644000175100001440000002042613110216422013440 0ustar hornikusers#' Assertions with an optional message #' #' The function \code{assert()} was inspired by \code{\link{stopifnot}()}. It #' emits a message in case of errors, which can be a helpful hint for diagnosing #' the errors (\code{stopifnot()} only prints the possibly truncated source code #' of the expressions). #' #' There are two ways to write R expressions in the \code{...} argument. #' #' The first way is a series of R expressions (each expression is passed as an #' individual argument) that return vectors of \code{TRUE}'s (if \code{FALSE} is #' returned anywhere, an error will show up). #' #' The second way is a single R expression wrapped in \code{{}} and passed as a #' single argument. This expression may contain multiple sub-expressions. A #' sub-expression is treated as a test condition if it is wrapped in \code{()} #' (meaning its value will be checked to see if it is a logical vector #' containing any \code{FALSE} values) , otherwise it is evaluated in the normal #' way and its value will not be checked. If the value of the last #' sub-expression is logical, it will also be treated as a test condition. #' @param fact a message for the assertions when any of them fails; treated the #' same way as expressions in \code{...} if it is not a character string, #' which means you do not have to provide a message to this function #' @param ... any number of R expressions; see Details #' @return Invisible \code{NULL} if all expressions returned \code{TRUE}, #' otherwise an error is signalled and the user-provided message is emitted. #' @note The internal implementation of \code{assert()} is different with the #' \code{stopifnot()} function in R \pkg{base}: (1) the custom message #' \code{fact} is emitted if an error occurs; (2) \code{assert()} requires the #' logical values to be non-empty (\code{logical(0)} will trigger an error); #' (3) if \code{...} contains a compound expression in \code{{}} that returns #' \code{FALSE} (e.g., \code{if (TRUE) {1+1; FALSE}}), the first and the last #' but one line of the source code from \code{\link{deparse}()} are printed in #' the error message, otherwise the first line is printed; (4) the arguments #' in \code{...} are evaluated sequentially, and \code{assert()} will signal #' an error upon the first failed assertion, and will ignore the rest of #' assertions. #' @export #' @examples ## The first way to write assertions -------------------- #' #' assert('one equals one', 1==1) #' assert('seq and : produce equal sequences', seq(1L, 10L) == 1L:10L) #' assert('seq and : produce identical sequences', identical(seq(1L, 10L), 1L:10L)) #' #' # multiple tests #' T=FALSE; F=TRUE #' assert('T is bad for TRUE, and so is F for FALSE', T!=TRUE, F!=FALSE) #' #' # a mixture of tests #' assert("Let's pray all of them will pass", 1==1, 1!=2, letters[4]=='d', rev(rev(letters))==letters) #' #' # logical(0) cannot pass assert(), although stopifnot() does not care #' try(assert('logical(0) cannot pass', 1==integer(0))) #' stopifnot(1==integer(0)) # it's OK! #' #' # a compound expression #' try(assert('this if statement returns TRUE', if(TRUE){x=1;x==2})) #' #' # no message #' assert(!FALSE, TRUE, is.na(NA)) #' #' #' ## The second way to write assertions ------------------- #' #' assert('T is bad for TRUE, and so is F for FALSE', {T=FALSE;F=TRUE #' (T!=TRUE) # note the parentheses #' (F!=FALSE)}) #' #' assert('A Poisson random number is non-negative', { #' x = rpois(1, 10) #' (x >= 0) #' x > -1 # do not need () here because it's the last expression #' }) assert = function(fact, ...) { mc = match.call() # match.call() uses the arg order in the func def, so fact is always 1st arg fact = NULL if (is.character(mc[[2]])) { fact = mc[[2]]; mc = mc[-2] } one = one_expression(mc) assert2(fact, if (one) mc[[2]][-1] else mc[-1], parent.frame(), !one) } # whether the argument of a function call is a single expression in {} one_expression = function(call) { length(call) == 2 && length(call[[2]]) >= 1 && identical(call[[c(2, 1)]], as.symbol('{')) } assert2 = function(fact, exprs, envir, all = TRUE) { n = length(exprs) for (i in seq_len(n)) { expr = exprs[[i]] val = eval(expr, envir = envir, enclos = NULL) # special case: fact is an expression instead of a string constant in assert() if (is.null(fact) && all && i == 1 && is.character(val)) { fact = val; next } # check all values in case of multiple arguments, o/w only check values in () if (all || (i == n && is.logical(val)) || (length(expr) >= 1 && identical(expr[[1]], as.symbol('(')))) { if (all_true(val)) next if (!is.null(fact)) message('assertion failed: ', fact) stop(sprintf( ngettext(length(val), '%s is not TRUE', '%s are not all TRUE'), deparse_key(expr) ), call. = FALSE, domain = NA) } } } #' @description The infix operator \code{\%==\%} is simply an alias of the #' \code{\link{identical}()} function to make it slightly easier and intuitive #' to write test conditions. \code{x \%==\% y} is the same as #' \code{identical(x, y)}. #' @param x,y two R objects to be compared #' @rdname assert #' @export `%==%` = function(x, y) identical(x, y) #' Run the tests of a package in its namespace #' #' The main purpose of this function is to expose the namespace of a package #' when running tests, which allows one to use non-exported objects in the #' package without having to resort to the triple colon \code{\link{:::}} trick. #' #' The tests are assumed to be under the \file{testit/} directory by default, #' and this function also looks for the \file{tests/testit/} directory under the #' package installation directory when the user-provided \code{dir} does not #' exist. The test scripts must be named of the form \samp{test-*.R}; other R #' scripts will not be treated as test files (but may also be useful, e.g. you #' can \code{\link{source}()} them in tests). #' #' For \command{R CMD check}, this means the test R scripts (\file{test-*.R} are #' under \file{pkg_root/tests/testit/}. The R scripts are executed with #' \code{\link{sys.source}} in the namespace of the package to be tested; when #' an R script is executed, the working directory is the same as the directory #' containing this script, and all existing objects in the test environment will #' be removed before the code is executed. #' @param package the package name #' @param dir the directory of the test files; by default, it is the directory #' \file{testit/} under the current working directory #' @return \code{NULL}. All test files are executed, unless an error occurs. #' @note All test scripts (\samp{test-*.R}) must be encoded in UTF-8 if they #' contain any multibyte characters. #' @seealso The \pkg{testthat} package (much more sophisticated). #' @export #' @examples \dontrun{test_pkg('testit')} test_pkg = function(package, dir = 'testit') { library(package, character.only = TRUE) path = available_dir(c(dir, system.file('tests', 'testit', package = package))) rs = list.files(path, '^test-.+[.][rR]$', full.names = TRUE) # make all objects in the package visible to tests env = new.env(parent = getNamespace(package)) for (r in rs) { rm(list = ls(env, all.names = TRUE), envir = env) withCallingHandlers( sys.source2(r, envir = env, top.env = getNamespace(package)), error = function(e) { z = .traceback(5) if (length(z) == 0) return() z = z[[1]] n = length(z) s = if (!is.null(srcref <- attr(z, 'srcref'))) { paste0(' at ', basename(attr(srcref, 'srcfile')$filename), '#', srcref[1]) } z[n] = paste0(z[n], s) cat(z, sep = '\n') } ) } } #' Check if an R expression produces warnings or errors #' #' The two functions \code{has_warning()} and \code{has_error()} check if an #' expression produces warnings and errors, respectively. #' @param expr an R expression #' @return A logical value. #' @export #' @rdname has_message #' @examples has_warning(1+1); has_warning(1:2+1:3) #' #' has_error(2-3); has_error(1+'a') has_warning = function(expr) { warn = FALSE op = options(warn = -1); on.exit(options(op)) withCallingHandlers(expr, warning = function(w) { warn <<- TRUE invokeRestart('muffleWarning') }) warn } #' @export #' @rdname has_message has_error = function(expr) { inherits(try(force(expr), silent = !interactive()), 'try-error') } testit/README.md0000644000175100001440000000617213107751604013075 0ustar hornikusers# testit [![Build Status](https://travis-ci.org/yihui/testit.svg)](https://travis-ci.org/yihui/testit) [![Coverage Status](https://coveralls.io/repos/github/yihui/testit/badge.svg?branch=master)](https://coveralls.io/github/yihui/testit?branch=master) This package provides two simple functions (30 lines of code in total): - `assert(fact, ...)`: think of it as `message(fact)` + `stopifnot(...)` - `test_pkg(package)`: runs tests with all objects (exported or non-exported) in the package namespace directly available, so no need to use `package:::name` for non-exported objects ## Why? The reason is laziness. It is tedious to type these commands repeatedly in tests: ```r message('checking if these numbers are equal...') stopifnot(all.equal(1, 1+1e-10), 10*.1 == 1) message('checking if a non-exported function works...') stopifnot(is.character(package:::utility_foo(x = 'abcd', y = 1:100))) ``` With the two simple functions above, we type six letters (`assert`) instead of sixteen (`message` + `stopifnot`), and `assert` is also a more intuitive function name for testing purposes (you _assert_ a fact followed by evidence): ```r assert( 'these numbers are equal', all.equal(1, 1+1e-10), 10*.1 == 1 ) assert( 'a non-exported function works', is.character(utility_foo(x = 'abcd', y = 1:100)) ) assert('T is TRUE and F is FALSE by default', { (T == TRUE) (F == FALSE) }) ``` ## R CMD check Put the tests under the directory `pkg_name/tests/testit/` (where `pkg_name` is the root directory of your package), and write a `test-all.R` under `pkg_name/tests/`: ```r library(testit) test_pkg('pkg_name') ``` That is all for `R CMD check`. For package development, it is recommended to use [**devtools**](https://cran.rstudio.org/package=devtools). In particular, `Ctrl + Shift + L` in RStudio makes all objects in a package visible to you, and you can play with the tests freely. ## Installation Stable version on CRAN: ```r install.packages('testit') ``` Development version: ```r devtools::install_github('yihui/testit') ``` ## More How about [**testthat**](https://CRAN.R-project.org/package=testthat)? Well, this package is far less sophisticated than **testthat**. There is nothing fancy in this package. Please do consider **testthat** if your tests require more granularity. I myself do not use **testthat** because I find it unnecessary to invent a new vocabulary (`testthat::expect_xxx`), and the error message of **testthat** is somehow obscure in my eyes. For **testit**, I do not need to think if I should use `expect_equal`, `expect_equivalent`, or `expect_identical`; I just write test conditions that return TRUE or FALSE. That is the only single rule to remember. There is no plan to add new features or reinvent anything in this package. It is an intentionally tiny package. Xunzi Although he did not really mean it, [Xunzi](http://en.wikipedia.org/wiki/Xunzi) said something that happens to apply well to unit testing: > 不积跬步,无以至千里;不积小流,无以成江海。 This package is free and open source software, licensed under GPL. testit/MD50000644000175100001440000000130313110472064012107 0ustar hornikuserse1d4b01eadefdc02dc579ca7d452251f *DESCRIPTION 8d4dda1a84a55725a51b9963e3ee588d *NAMESPACE e162e8f5079d136a7bcd23162fdf00cc *NEWS ef28927bca5eda6466a47c8619f52985 *R/testit.R c24fd4cbad5d330a945a9e04cd75822b *R/utils.R d7abed7e95e250b294874a94e4e02255 *README.md 4aae9b69bfa4f9baa95bd50f98274ba3 *inst/rstudio/addins.dcf f5601995b089ef6ab109ba1bedae2456 *man/assert.Rd 4811220ddf9663cc8e21554be5dafcad *man/has_message.Rd 4e059d0078876de01046e14a5a0a13ba *man/test_pkg.Rd fc95de596ff143707ce5da2874086a92 *tests/test-all.R 5330c047ff926dcaf08d9266db9a71f8 *tests/test-error/test-error.R 80027fdc69c299a33a6b22e37f0e1055 *tests/testit/test-assert.R e058e991696d0946fdf35e115fbf3dc0 *tests/testit/test-utils.R testit/DESCRIPTION0000644000175100001440000000106613110472064013313 0ustar hornikusersPackage: testit Type: Package Title: A Simple Package for Testing R Packages Version: 0.7 Date: 2017-05-21 Author: Yihui Xie Maintainer: Yihui Xie Description: Provides two convenience functions assert() and test_pkg() to facilitate testing R packages. License: GPL URL: https://github.com/yihui/testit BugReports: https://github.com/yihui/testit/issues Suggests: rstudioapi Collate: 'testit.R' 'utils.R' RoxygenNote: 6.0.1 NeedsCompilation: no Packaged: 2017-05-21 04:53:18 UTC; yihui Repository: CRAN Date/Publication: 2017-05-22 05:16:36 UTC testit/man/0000755000175100001440000000000013057301552012360 5ustar hornikuserstestit/man/assert.Rd0000644000175100001440000000752013110210053014135 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/testit.R \name{assert} \alias{assert} \alias{\%==\%} \title{Assertions with an optional message} \usage{ assert(fact, ...) x \%==\% y } \arguments{ \item{fact}{a message for the assertions when any of them fails; treated the same way as expressions in \code{...} if it is not a character string, which means you do not have to provide a message to this function} \item{...}{any number of R expressions; see Details} \item{x, y}{two R objects to be compared} } \value{ Invisible \code{NULL} if all expressions returned \code{TRUE}, otherwise an error is signalled and the user-provided message is emitted. } \description{ The function \code{assert()} was inspired by \code{\link{stopifnot}()}. It emits a message in case of errors, which can be a helpful hint for diagnosing the errors (\code{stopifnot()} only prints the possibly truncated source code of the expressions). The infix operator \code{\%==\%} is simply an alias of the \code{\link{identical}()} function to make it slightly easier and intuitive to write test conditions. \code{x \%==\% y} is the same as \code{identical(x, y)}. } \details{ There are two ways to write R expressions in the \code{...} argument. The first way is a series of R expressions (each expression is passed as an individual argument) that return vectors of \code{TRUE}'s (if \code{FALSE} is returned anywhere, an error will show up). The second way is a single R expression wrapped in \code{{}} and passed as a single argument. This expression may contain multiple sub-expressions. A sub-expression is treated as a test condition if it is wrapped in \code{()} (meaning its value will be checked to see if it is a logical vector containing any \code{FALSE} values) , otherwise it is evaluated in the normal way and its value will not be checked. If the value of the last sub-expression is logical, it will also be treated as a test condition. } \note{ The internal implementation of \code{assert()} is different with the \code{stopifnot()} function in R \pkg{base}: (1) the custom message \code{fact} is emitted if an error occurs; (2) \code{assert()} requires the logical values to be non-empty (\code{logical(0)} will trigger an error); (3) if \code{...} contains a compound expression in \code{{}} that returns \code{FALSE} (e.g., \code{if (TRUE) {1+1; FALSE}}), the first and the last but one line of the source code from \code{\link{deparse}()} are printed in the error message, otherwise the first line is printed; (4) the arguments in \code{...} are evaluated sequentially, and \code{assert()} will signal an error upon the first failed assertion, and will ignore the rest of assertions. } \examples{ ## The first way to write assertions -------------------- assert("one equals one", 1 == 1) assert("seq and : produce equal sequences", seq(1L, 10L) == 1L:10L) assert("seq and : produce identical sequences", identical(seq(1L, 10L), 1L:10L)) # multiple tests T = FALSE F = TRUE assert("T is bad for TRUE, and so is F for FALSE", T != TRUE, F != FALSE) # a mixture of tests assert("Let's pray all of them will pass", 1 == 1, 1 != 2, letters[4] == "d", rev(rev(letters)) == letters) # logical(0) cannot pass assert(), although stopifnot() does not care try(assert("logical(0) cannot pass", 1 == integer(0))) stopifnot(1 == integer(0)) # it's OK! # a compound expression try(assert("this if statement returns TRUE", if (TRUE) { x = 1 x == 2 })) # no message assert(!FALSE, TRUE, is.na(NA)) ## The second way to write assertions ------------------- assert("T is bad for TRUE, and so is F for FALSE", { T = FALSE F = TRUE (T != TRUE) # note the parentheses (F != FALSE) }) assert("A Poisson random number is non-negative", { x = rpois(1, 10) (x >= 0) x > -1 # do not need () here because it's the last expression }) } testit/man/test_pkg.Rd0000644000175100001440000000336613110210053014460 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/testit.R \name{test_pkg} \alias{test_pkg} \title{Run the tests of a package in its namespace} \usage{ test_pkg(package, dir = "testit") } \arguments{ \item{package}{the package name} \item{dir}{the directory of the test files; by default, it is the directory \file{testit/} under the current working directory} } \value{ \code{NULL}. All test files are executed, unless an error occurs. } \description{ The main purpose of this function is to expose the namespace of a package when running tests, which allows one to use non-exported objects in the package without having to resort to the triple colon \code{\link{:::}} trick. } \details{ The tests are assumed to be under the \file{testit/} directory by default, and this function also looks for the \file{tests/testit/} directory under the package installation directory when the user-provided \code{dir} does not exist. The test scripts must be named of the form \samp{test-*.R}; other R scripts will not be treated as test files (but may also be useful, e.g. you can \code{\link{source}()} them in tests). For \command{R CMD check}, this means the test R scripts (\file{test-*.R} are under \file{pkg_root/tests/testit/}. The R scripts are executed with \code{\link{sys.source}} in the namespace of the package to be tested; when an R script is executed, the working directory is the same as the directory containing this script, and all existing objects in the test environment will be removed before the code is executed. } \note{ All test scripts (\samp{test-*.R}) must be encoded in UTF-8 if they contain any multibyte characters. } \examples{ \dontrun{ test_pkg("testit") } } \seealso{ The \pkg{testthat} package (much more sophisticated). } testit/man/has_message.Rd0000644000175100001440000000105513110210053015110 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/testit.R \name{has_warning} \alias{has_warning} \alias{has_error} \title{Check if an R expression produces warnings or errors} \usage{ has_warning(expr) has_error(expr) } \arguments{ \item{expr}{an R expression} } \value{ A logical value. } \description{ The two functions \code{has_warning()} and \code{has_error()} check if an expression produces warnings and errors, respectively. } \examples{ has_warning(1 + 1) has_warning(1:2 + 1:3) has_error(2 - 3) has_error(1 + "a") }