Skip to content

Commit

Permalink
Add {cli} error messaging for assert_one_to_one() (#427)
Browse files Browse the repository at this point in the history
* Add {cli} error messaging for `assert_one_to_one()`

* doc update

* Update assertions.R

* adding example

* adding example

* doc update

* added snapshot

* Update test-get.R

* #424 assert_one_to_one: add examples and test

* #424 assert_one_to_one: fix test

---------

Co-authored-by: Ben Straub <[email protected]>
Co-authored-by: Stefan Bundfuss <[email protected]>
  • Loading branch information
3 people authored Apr 12, 2024
1 parent b70274c commit 70c90c3
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 39 deletions.
80 changes: 65 additions & 15 deletions R/assertions.R
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,12 @@ assert_list_element <- function(list,
#'
#' @param vars2 Second list of variables
#'
#' @param message string passed to `cli::cli_abort(message)`. When `NULL`, default messaging
#' is used (see examples for default messages). `"dataset_name"` can be used in messaging.
#'
#' @param dataset_name string indicating the label/symbol of the object being checked.
#' Default is `rlang::caller_arg(dataset)`.
#' @inheritParams assert_logical_scalar
#'
#' @return
#' An error if the condition is not meet. The input otherwise.
Expand All @@ -1613,7 +1619,40 @@ assert_list_element <- function(list,
#' @family assertion
#' @export
#'
assert_one_to_one <- function(dataset, vars1, vars2) {
#' @examples
#' library(dplyr)
#' library(rlang)
#'
#' df <- tribble(
#' ~SPECIES, ~SPECIESN,
#' "DOG", 1L,
#' "CAT", 2L,
#' "DOG", 1L
#' )
#'
#' assert_one_to_one(df, vars1 = exprs(SPECIES), vars2 = exprs(SPECIESN))
#'
#' df_many <- tribble(
#' ~SPECIES, ~SPECIESN,
#' "DOG", 1L,
#' "CAT", 2L,
#' "DOG", 3L
#' )
#'
#' try(
#' assert_one_to_one(df_many, vars1 = exprs(SPECIES), vars2 = exprs(SPECIESN))
#' )
#'
#' try(
#' assert_one_to_one(df_many, vars1 = exprs(SPECIESN), vars2 = exprs(SPECIES))
#' )
assert_one_to_one <- function(dataset,
vars1,
vars2,
dataset_name = rlang::caller_arg(dataset),
message = NULL,
class = "assert_one_to_one",
call = parent.frame()) {
assert_vars(vars1)
assert_vars(vars2)
assert_data_frame(dataset, required_vars = expr_c(vars1, vars2))
Expand All @@ -1623,34 +1662,45 @@ assert_one_to_one <- function(dataset, vars1, vars2) {
group_by(!!!vars1) %>%
filter(n() > 1) %>%
arrange(!!!vars1)

if (nrow(one_to_many) > 0) {
admiraldev_environment$one_to_many <- one_to_many
abort(
paste0(
"For some values of ",
vars2chr(vars1),
" there is more than one value of ",
vars2chr(vars2),
".\nCall `get_one_to_many_dataset()` to get all one to many values."

message <- message %||%
c("For some values of {.val {vars2chr(vars1)}} there is more than one
value of {.val {vars2chr(vars2)}}",
"i" = "Call {.fun get_one_to_many_dataset} to get all one-to-many values."
)

cli::cli_abort(
message = message,
call = call,
class = c(class, "assert-admiraldev")
)
}

many_to_one <- uniques %>%
group_by(!!!vars2) %>%
filter(n() > 1) %>%
arrange(!!!vars2)

if (nrow(many_to_one) > 0) {
admiraldev_environment$many_to_one <- many_to_one
abort(
paste0(
"There is more than one value of ",
vars2chr(vars1),
" for some values of ",
vars2chr(vars2),
".\nCall `get_many_to_one_dataset()` to get all many to one values."

message <- message %||%
c("There is more than one value of {.val {vars2chr(vars1)}} for some
values of {.val {vars2chr(vars2)}}",
"i" = "Call {.fun get_many_to_one_dataset} to get all many-to-one values."
)

cli::cli_abort(
message = message,
call = call,
class = c(class, "assert-admiraldev")
)
}

invisible(dataset)
}

#' Is a Variable in a Dataset a Date or Datetime Variable?
Expand Down
60 changes: 59 additions & 1 deletion man/assert_one_to_one.Rd

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

17 changes: 13 additions & 4 deletions tests/testthat/_snaps/assertions.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,31 +261,40 @@
! List element "val" must be `>=0` in argument `input`:
i But, `input[[2]]$val = -1`, and `input[[3]]$val = -2`

# assert_date_var Test 86: error if variable is not a date or datetime variable
# assert_one_to_one Test 84: error if there is a one to many mapping

Code
assert_one_to_one(pharmaversesdtm::dm, exprs(DOMAIN), exprs(USUBJID))
Condition
Error:
! For some values of "DOMAIN" there is more than one value of "USUBJID"
i Call `get_one_to_many_dataset()` to get all one-to-many values.

# assert_date_var Test 87: error if variable is not a date or datetime variable

Code
example_fun(dataset = my_data, var = USUBJID)
Condition
Error in `example_fun()`:
! Column "USUBJID" in dataset `dataset` must be a date or datetime, but is a character vector.

# assert_date_vector Test 90: error if `arg` is NULL and optional is FALSE
# assert_date_vector Test 91: error if `arg` is NULL and optional is FALSE

Code
example_fun(NULL)
Condition
Error in `example_fun()`:
! Argument `arg` must be a date or datetime, but is NULL.

# assert_atomic_vector Test 91: error if input is not atomic vector
# assert_atomic_vector Test 92: error if input is not atomic vector

Code
assert_atomic_vector(x)
Condition
Error:
! Argument `x` must be an atomic vector, but is a list.

# assert_same_type Test 93: error if different type
# assert_same_type Test 94: error if different type

Code
assert_same_type(true_value, false_value, missing_value)
Expand Down
62 changes: 43 additions & 19 deletions tests/testthat/test-assertions.R
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,13 @@ test_that("assert_list_element Test 83: error if the elements do not fulfill the
## Test 84: error if there is a one to many mapping ----
test_that("assert_one_to_one Test 84: error if there is a one to many mapping", {
expect_error(
assert_one_to_one(pharmaversesdtm::dm, exprs(DOMAIN), exprs(USUBJID)),
class = "assert_one_to_one"
)
admiraldev_environment$one_to_many <- NULL

expect_snapshot(
error = TRUE,
assert_one_to_one(pharmaversesdtm::dm, exprs(DOMAIN), exprs(USUBJID))
)
admiraldev_environment$one_to_many <- NULL
Expand All @@ -1276,14 +1283,31 @@ test_that("assert_one_to_one Test 84: error if there is a one to many mapping",
## Test 85: error if there is a many to one mapping ----
test_that("assert_one_to_one Test 85: error if there is a many to one mapping", {
expect_error(
assert_one_to_one(pharmaversesdtm::dm, exprs(USUBJID), exprs(DOMAIN))
assert_one_to_one(pharmaversesdtm::dm, exprs(USUBJID), exprs(DOMAIN)),
class = "assert_one_to_one"
)
admiraldev_environment$many_to_one <- NULL
})

## Test 86: dataset is returned invisible if one-to-one ----
test_that("assert_one_to_one Test 86: dataset is returned invisible if one-to-one", {
df <- tibble::tribble(
~SPECIES, ~SPECIESN,
"DOG", 1L,
"CAT", 2L,
"DOG", 1L
)

df_out <- expect_invisible(
assert_one_to_one(df, vars1 = exprs(SPECIES), vars2 = exprs(SPECIESN))
)

expect_equal(df_out, expected = df)
})

# assert_date_var ----
## Test 86: error if variable is not a date or datetime variable ----
test_that("assert_date_var Test 86: error if variable is not a date or datetime variable", {
## Test 87: error if variable is not a date or datetime variable ----
test_that("assert_date_var Test 87: error if variable is not a date or datetime variable", {
example_fun <- function(dataset, var) {
var <- assert_symbol(enexpr(var))
assert_date_var(dataset = dataset, var = !!var)
Expand Down Expand Up @@ -1311,18 +1335,18 @@ test_that("assert_date_var Test 86: error if variable is not a date or datetime
})

# assert_date_vector ----
## Test 87: returns error if input vector is not a date formatted ----
test_that("assert_date_vector Test 87: returns error if input vector is not a date formatted", {
## Test 88: returns error if input vector is not a date formatted ----
test_that("assert_date_vector Test 88: returns error if input vector is not a date formatted", {
expect_error(assert_date_vector("2018-08-23"))
})

## Test 88: returns invisible if input is date formatted ----
test_that("assert_date_vector Test 88: returns invisible if input is date formatted", {
## Test 89: returns invisible if input is date formatted ----
test_that("assert_date_vector Test 89: returns invisible if input is date formatted", {
expect_invisible(assert_date_vector(as.Date("2022-10-25")))
})

## Test 89: no error if `arg` is NULL and optional is TRUE ----
test_that("assert_date_vector Test 89: no error if `arg` is NULL and optional is TRUE", {
## Test 90: no error if `arg` is NULL and optional is TRUE ----
test_that("assert_date_vector Test 90: no error if `arg` is NULL and optional is TRUE", {
example_fun <- function(arg) {
assert_date_vector(arg, optional = TRUE)
}
Expand All @@ -1332,8 +1356,8 @@ test_that("assert_date_vector Test 89: no error if `arg` is NULL and optional is
)
})

## Test 90: error if `arg` is NULL and optional is FALSE ----
test_that("assert_date_vector Test 90: error if `arg` is NULL and optional is FALSE", {
## Test 91: error if `arg` is NULL and optional is FALSE ----
test_that("assert_date_vector Test 91: error if `arg` is NULL and optional is FALSE", {
example_fun <- function(arg) {
assert_date_vector(arg, optional = FALSE)
}
Expand All @@ -1350,8 +1374,8 @@ test_that("assert_date_vector Test 90: error if `arg` is NULL and optional is FA


# assert_atomic_vector ----
## Test 91: error if input is not atomic vector ----
test_that("assert_atomic_vector Test 91: error if input is not atomic vector", {
## Test 92: error if input is not atomic vector ----
test_that("assert_atomic_vector Test 92: error if input is not atomic vector", {
x <- list("a", "a", "b", "c", "d", "d", 1, 1, 4)
expect_error(assert_atomic_vector(x), class = "assert_atomic_vector")
expect_snapshot(
Expand All @@ -1361,15 +1385,15 @@ test_that("assert_atomic_vector Test 91: error if input is not atomic vector", {
})

# assert_same_type ----
## Test 92: no error if same type ----
test_that("assert_same_type Test 92: no error if same type", {
## Test 93: no error if same type ----
test_that("assert_same_type Test 93: no error if same type", {
true_value <- "Y"
false_value <- "N"
expect_invisible(assert_same_type(true_value, false_value))
})

## Test 93: error if different type ----
test_that("assert_same_type Test 93: error if different type", {
## Test 94: error if different type ----
test_that("assert_same_type Test 94: error if different type", {
true_value <- "Y"
false_value <- "N"
missing_value <- 0
Expand All @@ -1385,8 +1409,8 @@ test_that("assert_same_type Test 93: error if different type", {
)
})

## Test 94: works as intended ----
test_that("assert_same_type Test 94: works as intended", {
## Test 95: works as intended ----
test_that("assert_same_type Test 95: works as intended", {
expect_equal(
valid_time_units(),
c("years", "months", "days", "hours", "minutes", "seconds")
Expand Down
3 changes: 3 additions & 0 deletions tests/testthat/test-get.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ test_that("get_source_vars Test 6: no source vars returns NULL", {
# get_dataset ----
## Test 7: get_dataset works ----
test_that("get_dataset Test 7: get_dataset works", {
admiraldev_environment$many_to_one <- NULL
admiraldev_environment$one_to_many <- NULL

expect_equal(NULL, get_dataset("one_to_many"))
})

Expand Down

0 comments on commit 70c90c3

Please sign in to comment.