test_that("works with data frames", { conditions <- list( c(FALSE, TRUE, FALSE, FALSE), c(TRUE, TRUE, FALSE, FALSE), c(FALSE, TRUE, FALSE, TRUE) ) values <- list( data_frame(x = 1, y = 2), data_frame(x = 3, y = 4), data_frame(x = 3:6, y = 4:7) ) out <- vec_case_when(conditions, values) expect_identical( out, data_frame( x = c(3, 1, NA, 6), y = c(4, 2, NA, 7) ) ) }) test_that("first `TRUE` case wins", { conditions <- list( c(TRUE, FALSE), c(TRUE, TRUE), c(TRUE, TRUE) ) values <- list( 1, 2, 3 ) expect_identical( vec_case_when(conditions, values), c(1, 2) ) }) test_that("can replace missing values by catching with `is.na()`", { x <- c(1:3, NA) conditions <- list( x <= 1, x <= 2, is.na(x) ) values <- list( 1, 2, 0 ) expect_identical( vec_case_when(conditions, values), c(1, 2, NA, 0) ) }) test_that("Unused logical `NA` can still be cast to `values` ptype", { # Requires that casting happen before recycling, because it recycles # to size zero, resulting in a logical rather than an unspecified. expect_identical( vec_case_when(list(TRUE, FALSE), list("x", NA)), "x" ) expect_identical( vec_case_when(list(FALSE, TRUE), list("x", NA)), NA_character_ ) }) test_that("`conditions` inputs can be size zero", { expect_identical( vec_case_when( list(logical(), logical()), list(1, 2) ), numeric() ) expect_snapshot(error = TRUE, { vec_case_when(list(logical()), list(1:2)) }) }) test_that("retains inner names of `values` inputs", { value1 <- c(x = 1, y = 2) value2 <- c(z = 3, w = 4) out <- vec_case_when( list(c(TRUE, FALSE), c(TRUE, TRUE)), list(a = value1, b = value2) ) expect_named(out, c("x", "w")) }) test_that("outer names have no affect over the output names", { value1 <- c(1, 2) value2 <- c(3, 4) out <- vec_case_when( list(c(TRUE, FALSE), c(FALSE, TRUE)), list(x = value1, y = value2) ) expect_named(out, NULL) }) test_that("`values` are cast to their common type", { expect_identical(vec_case_when(list(FALSE, TRUE), list(1, 2L)), 2) expect_identical(vec_case_when(list(FALSE, TRUE), list(1, NA)), NA_real_) expect_snapshot(error = TRUE, { vec_case_when(list(FALSE, TRUE), list(1, "x")) }) }) test_that("`values` must be size 1 or same size as the `conditions`", { expect_identical( vec_case_when( list(c(TRUE, TRUE)), list(1) ), c(1, 1) ) expect_identical( vec_case_when( list(c(TRUE, FALSE), c(TRUE, TRUE)), list(c(1, 2), c(3, 4)) ), c(1, 4) ) expect_snapshot(error = TRUE, { vec_case_when( list(c(TRUE, FALSE, TRUE, TRUE)), list(1:3) ) }) }) test_that("Unhandled `NA` are given a value of `default`", { expect_identical( vec_case_when(list(NA), list(1)), NA_real_ ) expect_identical( vec_case_when(list(NA), list(1), default = 2), 2 ) expect_identical( vec_case_when( list( c(FALSE, NA, TRUE, FALSE), c(NA, FALSE, TRUE, FALSE) ), list( 2, 3 ), default = 4 ), c(4, 4, 2, 4) ) }) test_that("`NA` is overridden by any `TRUE` values", { x <- c(1, 2, NA, 3) expect <- c("one", "not_one", "missing", "not_one") # `TRUE` overriding before the `NA` conditions <- list( is.na(x), x == 1 ) values <- list( "missing", "one" ) expect_identical( vec_case_when( conditions, values, default = "not_one" ), expect ) # `TRUE` overriding after the `NA` conditions <- list( x == 1, is.na(x) ) values <- list( "one", "missing" ) expect_identical( vec_case_when( conditions, values, default = "not_one" ), expect ) }) test_that("works when there is a used `default` and no missing values", { expect_identical( vec_case_when(list(c(TRUE, FALSE)), list(1), default = 3:4), c(1, 4) ) }) test_that("works when there are missing values but no `default`", { expect_identical(vec_case_when(list(c(TRUE, NA)), list(1)), c(1, NA)) }) test_that("A `NULL` `default` fills in with missing values", { expect_identical( vec_case_when(list(c(TRUE, FALSE, FALSE)), list(1)), c(1, NA, NA) ) }) test_that("`default` fills in all unused slots", { expect_identical( vec_case_when(list(c(TRUE, FALSE, FALSE)), list(1), default = 2), c(1, 2, 2) ) }) test_that("`default` is initialized correctly in the logical / unspecified case", { # i.e. `vec_ptype(NA)` is unspecified but the result should be finalized to logical expect_identical(vec_case_when(list(FALSE), list(NA)), NA) }) test_that("`default` can be vectorized, and is sliced to fit as needed", { out <- vec_case_when( list( c(FALSE, TRUE, FALSE, TRUE, FALSE), c(FALSE, TRUE, FALSE, FALSE, TRUE) ), list( 1:5, 6:10 ), default = 11:15 ) expect_identical(out, c(11L, 2L, 13L, 4L, 10L)) }) test_that("`default` must be size 1 or same size as `conditions` (exact same as any other `values` input)", { expect_snapshot(error = TRUE, { vec_case_when(list(FALSE), list(1L), default = 2:3) }) }) test_that("`default` participates in common type determination (exact same as any other `values` input)", { expect_identical(vec_case_when(list(FALSE), list(1L), default = 2), 2) }) test_that("`default` that is an unused logical `NA` can still be cast to `values` ptype", { # Requires that casting happen before recycling, because it recycles # to size zero, resulting in a logical rather than an unspecified. expect_identical(vec_case_when(list(TRUE), list("x"), default = NA), "x") }) test_that("`default` type is used when all values are logical `NA` (#2094)", { expect_identical( vec_case_when(list(TRUE), list(NA), default = "a"), NA_character_ ) expect_identical( vec_case_when(list(c(TRUE, FALSE)), list(NA), default = "a"), c(NA_character_, "a") ) }) test_that("`default_arg` can be customized", { expect_snapshot(error = TRUE, { vec_case_when(list(FALSE), list(1L), default = 2:3, default_arg = "foo") }) expect_snapshot(error = TRUE, { vec_case_when(list(FALSE), list(1L), default = "x", default_arg = "foo") }) }) test_that("`conditions_arg` is validated", { expect_snapshot(error = TRUE, { vec_case_when(list("x"), list(1), conditions_arg = 1) }) }) test_that("`values_arg` is validated", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(lm(1 ~ 1)), values_arg = 1) }) }) test_that("`default_arg` is validated", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(1), default = "x", default_arg = 1) }) }) test_that("`conditions` must all be the same size", { expect_snapshot(error = TRUE, { vec_case_when( list(c(TRUE, FALSE), TRUE), list(1, 2) ) }) expect_snapshot(error = TRUE, { vec_case_when( list(c(TRUE, FALSE), c(TRUE, FALSE, TRUE)), list(1, 2) ) }) }) test_that("`conditions` must be logical (and aren't cast to logical!)", { expect_snapshot(error = TRUE, { vec_case_when(list(1), list(2)) }) # Make sure input numbering is right in the error message! expect_snapshot(error = TRUE, { vec_case_when(list(TRUE, 3.5), list(2, 4)) }) # `vec_as_location()` would not allow this either x <- structure(c(FALSE, TRUE), class = "my_logical") expect_snapshot(error = TRUE, { vec_case_when(list(x), list(1), default = 2) }) }) test_that("`conditions` are allowed to have attributes", { x <- structure(c(FALSE, TRUE), label = "foo") expect_identical(vec_case_when(list(x), list(1), default = 2), c(2, 1)) }) test_that("`conditions` can't be arrays (#6862)", { x <- array(TRUE, dim = c(3, 3)) y <- c("a", "b", "c") expect_snapshot(error = TRUE, { vec_case_when(list(x), list(y)) }) expect_snapshot(error = TRUE, { vec_case_when(list(x), list(y), size = 3) }) # Not even 1D arrays x <- array(TRUE, dim = 3) expect_snapshot(error = TRUE, { vec_case_when(list(x), list(y)) }) }) test_that("`size` overrides the `conditions` sizes", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(1), size = 5) }) expect_snapshot(error = TRUE, { vec_case_when( list(c(TRUE, FALSE), c(TRUE, FALSE, TRUE)), list(1, 2), size = 2 ) }) }) test_that("0 `conditions` result depends on `size` and `default` and `ptype`", { expect_identical( vec_case_when( conditions = list(), values = list() ), unspecified() ) expect_identical( vec_case_when( conditions = list(), values = list(), size = 0 ), unspecified() ) expect_identical( vec_case_when( conditions = list(), values = list(), size = 2 ), unspecified(2) ) expect_identical( vec_case_when( conditions = list(), values = list(), default = integer() ), integer() ) expect_identical( vec_case_when( conditions = list(), values = list(), default = 1L ), integer() ) expect_identical( vec_case_when( conditions = list(), values = list(), ptype = integer() ), integer() ) expect_identical( vec_case_when( conditions = list(), values = list(), size = 2L, default = 1L ), c(1L, 1L) ) expect_identical( vec_case_when( conditions = list(), values = list(), size = 2L, default = 1:2 ), c(1L, 2L) ) expect_identical( vec_case_when( conditions = list(), values = list(), size = 2L, ptype = integer() ), c(NA_integer_, NA_integer_) ) }) test_that("`vec_replace_when()` with empty `conditions` is a no-op", { x <- 1:5 expect_identical( vec_replace_when(x, conditions = list(), values = list()), x ) }) test_that("`ptype` overrides the `values` types", { expect_identical( vec_case_when(list(FALSE, TRUE), list(1, 2), ptype = integer()), 2L ) expect_snapshot(error = TRUE, { vec_case_when(list(FALSE, TRUE), list(1, 2), ptype = character()) }) }) test_that("number of `conditions` and `values` must be the same", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list()) }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE, TRUE), list(1)) }) }) test_that("dots must be empty", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(1), 2) }) }) test_that("`conditions` must be a list", { expect_snapshot(error = TRUE, { vec_case_when(1, list(2)) }) }) test_that("`values` must be a list", { expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), 1) }) }) test_that("named inputs show up in the error message", { expect_snapshot(error = TRUE, { vec_case_when(list(x = 1.5), list(1)) }) expect_snapshot(error = TRUE, { vec_case_when(list(x = 1.5), list(1), conditions_arg = "foo") }) expect_snapshot(error = TRUE, { vec_case_when(list(x = 1.5), list(1), conditions_arg = "") }) expect_snapshot(error = TRUE, { vec_case_when(list(x = TRUE, y = c(TRUE, FALSE)), list(1, 2)) }) expect_snapshot(error = TRUE, { vec_case_when( list(x = TRUE, y = c(TRUE, FALSE)), list(1, 2), conditions_arg = "foo" ) }) expect_snapshot(error = TRUE, { vec_case_when( list(x = TRUE, y = c(TRUE, FALSE)), list(1, 2), conditions_arg = "" ) }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE, FALSE), list(1, x = "y")) }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE, FALSE), list(1, x = "y"), values_arg = "foo") }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE, FALSE), list(1, x = "y"), values_arg = "") }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(NULL)) }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(x = NULL)) }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(NULL), values_arg = "foo") }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(x = NULL), values_arg = "foo") }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(NULL), values_arg = "") }) expect_snapshot(error = TRUE, { vec_case_when(list(TRUE), list(x = NULL), values_arg = "") }) }) test_that("proof that `ptype` finalization is important", { # Imagine you have an input logical vector you are remapping # and it happens to only have `NA`s x <- c(NA, NA) conditions <- list(x %in% NA) values <- list(FALSE) # If no `ptype` finalization happened, then `ptype = x` would result in # `unspecified` being the output type and these would error. `list_combine()` # now does `ptype` finalization when an explicit `ptype` is provided, so this # works. expect_identical( vec_case_when(conditions, values, default = x, ptype = x), c(FALSE, FALSE) ) expect_identical( vec_replace_when(x, conditions, values), c(FALSE, FALSE) ) }) test_that("`unmatched` errors are correct", { conditions <- list( c(TRUE, FALSE, TRUE, FALSE, FALSE, NA, NA, NA, TRUE), c(FALSE, TRUE, TRUE, FALSE, NA, FALSE, NA, TRUE, NA) ) values <- list( 1, 2 ) expect_snapshot(error = TRUE, { vec_case_when(conditions, values, unmatched = "error") }) })