test_that("data_frame() recycles", { expect_equal( data_frame(x = 1, y = 1:2), data_frame(x = c(1, 1), y = 1:2) ) out <- data_frame(x = list(1), y = 1:2) expect_equal(out$x, list(1, 1)) }) test_that("data_frame() nests", { df <- data_frame(a = 3:4) out <- data_frame(x = 1:2, y = df) expect_equal(out$y, df) out <- data_frame(x = 1:2, y = data_frame(a = 1)) expect_equal(out$y, data_frame(a = c(1, 1))) }) test_that("new_data_frame handles zero-length inputs", { # Zero-length input creates zero-length data frame d <- data_frame(x = numeric(0), y = numeric(0)) expect_equal(nrow(d), 0L) # Constants are ignored in the context of zero-length input d <- data_frame(x = numeric(0), y = numeric(0), z = 1) expect_equal(nrow(d), 0L) # Vectors of length > 1 don't mix with zero-length input expect_error( data_frame(x = numeric(0), y = numeric(0), z = 1, a = c(1, 2)), "Inputs can't be recycled" ) # Explicit recycling doesn't work with zero-length input expect_error( new_data_frame(df_list(x = numeric(0), z = 1, .size = 5)), "Inputs can't be recycled to `size`." ) # But it works without d <- new_data_frame(df_list(x = 1, y = "a", .size = 3)) expect_equal(nrow(d), 3L) expect_identical(d$x, rep(1, 3L)) expect_identical(d$y, rep("a", 3L)) # Can supply size for empty df d <- new_data_frame(.size = 3) expect_equal(dim(d), c(3, 0)) }) test_that("can slice vectors and data frames", { fct <- factor(c("a", "b", "a")) fct_exp <- factor(c("a", "a"), levels = c("a", "b")) expect_equal( vec_slice(fct, c(1, 3)), fct_exp ) expect_equal( vec_init(fct, 2), factor(c(NA, NA), c("a", "b")) ) df <- data_frame( x = fct, y = data_frame(a = list(1, 2, 3)) ) df_exp <- data_frame( x = fct_exp, y = data_frame(a = list(1, 3)) ) expect_equal( vec_slice(df, c(1, 3)), df_exp ) expect_equal( vec_init(df, 2), data_frame( x = vec_init(fct, 2), y = data_frame(a = list(NULL, NULL)) ) ) rep_exp <- data_frame( x = rep(fct, 2), y = data_frame(a = rep(list(1, 2, 3), 2)) ) expect_equal(vec_rep(df, 2), rep_exp) }) test_that("vec_slice() is generic", { skip_if_not_installed("tibble") tib <- tibble::tibble(x = 1:2, y = data_frame(a = 3:4)) expect_equal(vec_slice(tib, 1), tib[1, ]) }) test_that("vec_assign() works", { expect_identical( vec_assign(1:2, 1, FALSE), c(0L, 2L) ) expect_error( vec_assign(1:2, 1, 1.5), "Can't convert" ) df <- data_frame(x = list(1, 2), y = data_frame(a = c("a", "b"))) expect_equal( vec_assign(df, 2, data_frame(x = list(10))), data_frame(x = list(1, 10), y = data_frame(a = c("a", NA))) ) }) test_that("vec_ptype2() implements base coercions", { expect_equal(vec_ptype2(lgl(), lgl()), lgl()) expect_equal(vec_ptype2(lgl(), int()), int()) expect_equal(vec_ptype2(lgl(), dbl()), dbl()) expect_error(vec_ptype2(lgl(), chr())) expect_error(vec_ptype2(lgl(), list())) expect_error(vec_ptype2(lgl(), raw())) expect_equal(vec_ptype2(int(), lgl()), int()) expect_equal(vec_ptype2(int(), int()), int()) expect_equal(vec_ptype2(int(), dbl()), int()) expect_error(vec_ptype2(int(), chr())) expect_error(vec_ptype2(int(), list())) expect_error(vec_ptype2(int(), raw())) expect_equal(vec_ptype2(dbl(), lgl()), dbl()) expect_equal(vec_ptype2(dbl(), int()), dbl()) expect_equal(vec_ptype2(dbl(), dbl()), dbl()) expect_error(vec_ptype2(dbl(), chr())) expect_error(vec_ptype2(dbl(), list())) expect_error(vec_ptype2(dbl(), raw())) expect_equal(vec_ptype2(chr(), chr()), chr()) expect_error(vec_ptype2(chr(), lgl())) expect_error(vec_ptype2(chr(), int())) expect_error(vec_ptype2(chr(), dbl())) expect_error(vec_ptype2(chr(), list())) expect_error(vec_ptype2(chr(), raw())) expect_equal(vec_ptype2(list(), list()), list()) expect_error(vec_ptype2(list(), lgl())) expect_error(vec_ptype2(list(), int())) expect_error(vec_ptype2(list(), dbl())) expect_error(vec_ptype2(list(), chr())) expect_error(vec_ptype2(list(), raw())) expect_snapshot(vec_ptype2(lgl(), chr()), error = TRUE) expect_snapshot(vec_ptype2(factor("a"), lgl()), error = TRUE) }) test_that("vec_ptype2() deals with unspecified vectors", { expect_equal(vec_ptype2(NA, NA), .rlang_vctrs_unspecified()) expect_equal(vec_ptype2(NA, lgl()), lgl()) expect_equal(vec_ptype2(NA, int()), int()) expect_equal(vec_ptype2(NA, dbl()), dbl()) expect_equal(vec_ptype2(NA, chr()), chr()) expect_equal(vec_ptype2(NA, list()), list()) expect_equal(vec_ptype2(lgl(), NA), lgl()) expect_equal(vec_ptype2(int(), NA), int()) expect_equal(vec_ptype2(dbl(), NA), dbl()) expect_equal(vec_ptype2(chr(), NA), chr()) expect_equal(vec_ptype2(list(), NA), list()) }) test_that("vec_is_unspecified() knows about empty logicals", { expect_true(vec_is_unspecified(NA)) expect_false(vec_is_unspecified(lgl())) }) test_that("vec_ptype_common() works", { expect_equal( vec_ptype_common(list(lgl(), dbl(), NA)), dbl() ) expect_snapshot( error = TRUE, vec_ptype_common(list(lgl(), dbl(), "")) ) }) test_that("vec_ptype_common() finalises unspecified type", { expect_equal( vec_ptype_common(list(NA, NA)), logical() ) }) test_that("safe casts work", { expect_equal(vec_cast(NULL, logical()), NULL) expect_equal(vec_cast(TRUE, logical()), TRUE) expect_equal(vec_cast(1L, logical()), TRUE) expect_equal(vec_cast(1, logical()), TRUE) expect_equal(vec_cast(NULL, integer()), NULL) expect_equal(vec_cast(TRUE, integer()), 1L) expect_equal(vec_cast(1L, integer()), 1L) expect_equal(vec_cast(1, integer()), 1L) expect_equal(vec_cast(NULL, double()), NULL) expect_equal(vec_cast(TRUE, double()), 1L) expect_equal(vec_cast(1.5, double()), 1.5) expect_equal(vec_cast(1.5, double()), 1.5) expect_equal(vec_cast("", chr()), "") expect_equal(vec_cast(NULL, character()), NULL) expect_equal(vec_cast(NA, character()), NA_character_) expect_equal(vec_cast(NULL, list()), NULL) expect_equal(vec_cast(NA, list()), list(NULL)) expect_equal(vec_cast(list(1L, 2L), list()), list(1L, 2L)) }) test_that("lossy casts throw", { expect_error(vec_cast(c(2L, 1L), logical()), "convert") expect_error(vec_cast(c(2, 1), logical()), "convert") expect_error(vec_cast(c(2.5, 2), integer()), "convert") expect_snapshot(vec_cast(1.5, 2L), error = TRUE) }) test_that("invalid casts throw", { expect_error(vec_cast(c("x", "TRUE"), logical()), "convert") expect_error(vec_cast(list(c(TRUE, FALSE), TRUE), logical()), "convert") expect_error(vec_cast(factor("a"), logical()), "Unimplemented") expect_error(vec_cast(factor("a"), integer()), "Unimplemented") expect_error(vec_cast("1", integer()), "convert") expect_error(vec_cast(list(1L), integer()), "convert") expect_error(vec_cast("1.5", double()), "convert") expect_error(vec_cast(TRUE, character()), "convert") expect_error(vec_cast(list("x"), character()), "convert") expect_error(vec_cast(1:2, list()), "convert") }) test_that("vec_cast_common(): empty input returns list()", { expect_equal(vec_cast_common(list()), list()) expect_equal(vec_cast_common(list(NULL, NULL)), list(NULL, NULL)) }) test_that("data frames have a common type", { exp <- data.frame(x = dbl(), y = chr()) exp_rlib_df <- new_data_frame(exp, .class = "tbl") exp_tibble <- new_data_frame(exp, .class = c("tbl_df", "tbl")) expect_equal( vec_ptype2(data.frame(x = 1, y = ""), data.frame(y = "")), exp ) expect_equal( vec_ptype2(data_frame(x = 1, y = ""), data_frame(y = "")), exp_rlib_df ) expect_equal( vec_ptype2(data_frame(x = 1, y = ""), data.frame(y = "")), exp_rlib_df ) expect_error( vec_ptype2(data.frame(x = 1, y = ""), data.frame(y = 1)), "combine" ) skip_if_not_installed("tibble") expect_equal( vec_ptype2(data_frame(x = 1, y = ""), tibble::tibble(y = "")), exp_tibble ) expect_equal( vec_ptype2(tibble::tibble(x = 1, y = ""), data.frame(y = "")), exp_tibble ) }) test_that("data frame takes max of individual variables", { dt1 <- data.frame(x = FALSE, y = 1L) dt2 <- data.frame(x = 1.5, y = 1.5) expect_equal( vec_ptype_common(list(dt1, dt2)), vec_ptype_common(list(dt2)) ) }) test_that("data frame combines variables", { dt1 <- data.frame(x = 1) dt2 <- data.frame(y = 1) expect_equal( vec_ptype_common(list(dt1, dt2)), vec_ptype_common(list(data.frame(x = double(), y = double()))) ) }) test_that("can cast data frames", { expect_equal( vec_cast(data.frame(y = ""), data.frame(x = 1, y = "")), data.frame(x = na_dbl, y = "") ) expect_equal( vec_cast(data.frame(y = ""), data_frame(x = 1, y = "")), data_frame(x = na_dbl, y = "") ) skip_if_not_installed("tibble") expect_equal( vec_cast(data.frame(y = ""), tibble::tibble(x = 1, y = "")), tibble::tibble(x = na_dbl, y = "") ) }) test_that("can bind data frames", { expect_equal( vec_rbind( data.frame(x = 1), data_frame(y = "") ), data_frame(x = c(1, NA), y = c(NA, "")) ) expect_equal( vec_cbind( data_frame(x = data_frame(a = TRUE)), data_frame(y = list("")) ), data_frame(x = data_frame(a = TRUE), y = list("")) ) expect_equal( vec_rbind( data_frame(x = TRUE), data_frame(y = list("")) ), data_frame(x = c(TRUE, NA), y = list(NULL, "")) ) # `rbind()` has trouble binding df-cols on old R versions skip_if(getRversion() < "4.0") expect_equal( vec_rbind( data_frame(x = data_frame(a = TRUE)), data_frame(y = list("")) ), data_frame(x = data_frame(a = c(TRUE, NA)), y = list(NULL, "")) ) }) test_that("casting to df type uses same column order", { df1 <- data.frame(x = 1, y = 2) df2 <- data.frame(y = 3, x = 4) expect_equal( vec_cast_common(list(df1, df2)), list(df1, df2[2:1]) ) df1 <- data.frame(y = 2) df2 <- data.frame(y = 3, x = 4) expect_equal( vec_cast_common(list(df1, df2)), list(data.frame(y = 2, x = na_dbl), df2) ) }) test_that("vec_as_location() works", { n <- 4 names <- letters[1:4] i <- c(2, 3) expect_identical(vec_as_location(i, n, names), 2:3) i <- -c(2, 3) expect_identical(vec_as_location(i, n, names), c(1L, 4L)) i <- c(TRUE, FALSE, TRUE, FALSE) expect_identical(vec_as_location(i, n, names), c(1L, 3L)) i <- c("a", "d") expect_identical(vec_as_location(i, n, names), c(1L, 4L)) }) test_that("vec_as_location() recycles scalar logical inputs", { expect_equal(vec_as_location(TRUE, 0), int()) expect_equal(vec_as_location(FALSE, 0), int()) }) test_that("vec_slice() preserves attributes of data frames", { df <- data_frame(x = 1:2) attr(df, "foo") <- TRUE out <- vec_slice(df, 1) expect_true(attr(out, "foo")) }) test_that("vec_slice() doesn't restore attributes if there is a `[` method", { df <- new_data_frame( df_list(x = 1:2), .class = "rlang_foobar", foo = "bar" ) local_methods(`[.rlang_foobar` = function(x, ...) { out <- NextMethod() attr(out, "foo") <- "dispatched" out }) expect_equal( attr(vec_slice(df, 1), "foo"), "dispatched" ) }) test_that("vec_slice() preserves attributes of vectors", { x <- set_names(1:2, c("a", "b")) attr(x, "foo") <- TRUE out <- vec_slice(x, 1) expect_true(attr(out, "foo")) expect_equal(attr(out, "names"), "a") }) test_that("can row-bind unspecified columns", { expect_equal( vec_rbind( data_frame(x = NA), data_frame(x = "") ), data_frame(x = c(NA, "")) ) }) test_that("unspecified is detected recursively", { ptype <- vec_ptype(data_frame(x = NA)) expect_s3_class(ptype$x, "rlang_unspecified") }) test_that("ptype is finalised", { x <- data_frame(x = NA) out <- vec_cast_common(list(x, x))[[1]] expect_identical(out$x, NA) out <- vec_cast_common(list(out, x))[[1]] expect_identical(out$x, NA) }) test_that("vec_recycle_common() throws appropriate errors", { expect_error( vec_recycle_common(list(a = 1:2), size = 1), "Inputs can't be recycled to `size`." ) expect_error( vec_recycle_common(list(a = 1:2, b = 1:3)), "Inputs can't be recycled to a common size." ) })