# To turn on warnings from tibble::`names<-()`
local_options(lifecycle_verbosity = "warning")
test_that("empty duckplyr_arrange() returns input", {
df <- tibble(x = 1:10, y = 1:10)
gf <- duckplyr_group_by(df, x)
expect_identical(duckplyr_arrange(df), df)
expect_identical(duckplyr_arrange(gf), gf)
expect_identical(duckplyr_arrange(df, !!!list()), df)
expect_identical(duckplyr_arrange(gf, !!!list()), gf)
})
test_that("can sort empty data frame", {
df <- tibble(a = numeric(0))
expect_equal(duckplyr_arrange(df, a), df)
})
test_that("local arrange sorts missing values to end", {
df <- data.frame(x = c(2, 1, NA))
expect_equal(df %>% duckplyr_arrange(x) %>% duckplyr_pull(), c(1, 2, NA))
expect_equal(df %>% duckplyr_arrange(desc(x)) %>% duckplyr_pull(), c(2, 1, NA))
})
test_that("duckplyr_arrange() gives meaningful errors", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
expect_snapshot({
# duplicated column name
(expect_error(
tibble(x = 1, x = 1, .name_repair = "minimal") %>% duckplyr_arrange(x)
))
# error in duckplyr_mutate() step
(expect_error(
tibble(x = 1) %>% duckplyr_arrange(y)
))
(expect_error(
tibble(x = 1) %>% duckplyr_arrange(rep(x, 2))
))
})
})
# column types ----------------------------------------------------------
test_that("arrange handles list columns (#282)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
# no intrinsic ordering
df <- tibble(x = 1:3, y = list(3, 2, 1))
expect_equal(duckplyr_arrange(df, y), df)
df <- tibble(x = 1:3, y = list(sum, mean, sd))
expect_equal(duckplyr_arrange(df, y), df)
})
test_that("arrange handles raw columns (#1803)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 1:3, y = as.raw(3:1))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("arrange handles matrix columns", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 1:3, y = matrix(6:1, ncol = 2))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("arrange handles data.frame columns (#3153)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 1:3, y = data.frame(z = 3:1))
expect_equal(duckplyr_arrange(df, y), tibble(x = 3:1, y = data.frame(z = 1:3)))
})
test_that("arrange handles complex columns", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 1:3, y = 3:1 + 2i)
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("arrange handles S4 classes (#1105)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
TestS4 <- suppressWarnings(setClass("TestS4", contains = "integer"))
setMethod('[', 'TestS4', function(x, i, ...){ TestS4(unclass(x)[i, ...]) })
on.exit(removeClass("TestS4"), add = TRUE)
df <- tibble(x = 1:3, y = TestS4(3:1))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("arrange works with two columns when the first has a data frame proxy (#6268)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
# `id1` has a data frame proxy for `vec_proxy_order()`
df <- tibble(
id1 = new_rcrd(list(x = 1, y = 1)),
id2 = c(1, 3, 2)
)
out <- duckplyr_arrange(df, id1, id2)
expect_identical(out$id2, c(1, 2, 3))
})
test_that("arrange ignores NULLs (#6193)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 1:2)
y <- NULL
out <- duckplyr_arrange(df, y, desc(x))
expect_equal(out$x, 2:1)
out <- duckplyr_arrange(df, y, desc(x), y)
expect_equal(out$x, 2:1)
})
test_that("`duckplyr_arrange()` works with `numeric_version` (#6680)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
x <- numeric_version(c("1.11", "1.2.3", "1.2.2"))
df <- tibble(x = x)
expect <- df[c(3, 2, 1),]
expect_identical(duckplyr_arrange(df, x), expect)
})
# locale --------------------------------------------------------------
test_that("arrange defaults to the C locale", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
x <- c("A", "a", "b", "B")
df <- tibble(x = x)
res <- duckplyr_arrange(df, x)
expect_identical(res$x, c("A", "B", "a", "b"))
res <- duckplyr_arrange(df, desc(x))
expect_identical(res$x, rev(c("A", "B", "a", "b")))
})
test_that("locale can be set to an English locale", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
skip_if_not_installed("stringi", "1.5.3")
x <- c("A", "a", "b", "B")
df <- tibble(x = x)
res <- duckplyr_arrange(df, x, .locale = "en")
expect_identical(res$x, c("a", "A", "b", "B"))
})
test_that("non-English locales can be used", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
skip_if_not_installed("stringi", "1.5.3")
# Danish `o` with `/` through it sorts after `z` in Danish locale
x <- c("o", "\u00F8", "p", "z")
df <- tibble(x = x)
# American English locale puts it right after `o`
res <- duckplyr_arrange(df, x, .locale = "en")
expect_identical(res$x, x)
res <- duckplyr_arrange(df, x, .locale = "da")
expect_identical(res$x, x[c(1, 3, 4, 2)])
})
test_that("arrange errors if stringi is not installed and a locale identifier is used", {
expect_snapshot(error = TRUE, {
locale_to_chr_proxy_collate("fr", has_stringi = FALSE)
})
})
test_that("arrange validates `.locale`", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble()
expect_snapshot(error = TRUE, {
duckplyr_arrange(df, .locale = 1)
})
expect_snapshot(error = TRUE, {
duckplyr_arrange(df, .locale = c("en_US", "fr_BF"))
})
})
test_that("arrange validates that `.locale` must be one from stringi", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
skip_if_not_installed("stringi", "1.5.3")
df <- tibble()
expect_snapshot(error = TRUE, {
duckplyr_arrange(df, .locale = "x")
})
})
# data ----------------------------------------------------------------
test_that("arrange preserves input class", {
df1 <- data.frame(x = 1:3, y = 3:1)
df2 <- tibble(x = 1:3, y = 3:1)
df3 <- df1 %>% duckplyr_group_by(x)
expect_s3_class(duckplyr_arrange(df1, x), "data.frame", exact = TRUE)
expect_s3_class(duckplyr_arrange(df2, x), "tbl_df")
expect_s3_class(duckplyr_arrange(df3, x), "grouped_df")
})
test_that("grouped arrange ignores group, unless requested with .by_group", {
df <- data.frame(g = c(2, 1, 2, 1), x = 4:1)
gf <- duckplyr_group_by(df, g)
expect_equal(duckplyr_arrange(gf, x), gf[4:1, ,])
expect_equal(duckplyr_arrange(gf, x, .by_group = TRUE), gf[c(4, 2, 3, 1), ,])
})
test_that("arrange updates the grouping structure (#605)", {
df <- tibble(g = c(2, 2, 1, 1), x = c(1, 3, 2, 4))
res <- df %>% duckplyr_group_by(g) %>% duckplyr_arrange(x)
expect_s3_class(res, "grouped_df")
expect_equal(group_rows(res), list_of(c(2L, 4L), c(1L, 3L)))
})
test_that("duckplyr_arrange() supports across() and pick() (#4679)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = c(1, 3, 2, 1), y = c(4, 3, 2, 1))
expect_identical(
df %>% duckplyr_arrange(pick(everything())),
df %>% duckplyr_arrange(x, y)
)
expect_identical(
df %>% duckplyr_arrange(across(everything(), .fns = desc)),
df %>% duckplyr_arrange(desc(x), desc(y))
)
expect_identical(
df %>% duckplyr_arrange(pick(x)),
df %>% duckplyr_arrange(x)
)
expect_identical(
df %>% duckplyr_arrange(across(y, .fns = identity)),
df %>% duckplyr_arrange(y)
)
})
test_that("duckplyr_arrange() works with across() and pick() cols that return multiple columns (#6490)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(
a = c(1, 1, 1),
b = c(2, 2, 2),
c = c(4, 4, 3),
d = c(5, 2, 7)
)
expect_identical(
duckplyr_arrange(df, across(c(a, b), .fns = identity), across(c(c, d), .fns = identity)),
df[c(3, 2, 1),]
)
expect_identical(
duckplyr_arrange(df, pick(a, b), pick(c, d)),
df[c(3, 2, 1),]
)
})
test_that("duckplyr_arrange() evaluates each pick() call on the original data (#6495)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
df <- tibble(x = 2:1)
out <- duckplyr_arrange(df, TRUE, pick(everything()))
expect_identical(out, df[c(2, 1),])
out <- duckplyr_arrange(df, NULL, pick(everything()))
expect_identical(out, df[c(2, 1),])
})
test_that("duckplyr_arrange() with empty dots still calls dplyr_row_slice()", {
tbl <- new_tibble(list(x = 1), nrow = 1L)
foo <- structure(tbl, class = c("foo_df", class(tbl)))
local_methods(
# `foo_df` always loses class when row slicing
dplyr_row_slice.foo_df = function(data, i, ...) {
out <- NextMethod()
new_tibble(out, nrow = nrow(out))
}
)
expect_s3_class(duckplyr_arrange(foo), class(tbl), exact = TRUE)
expect_s3_class(duckplyr_arrange(foo, x), class(tbl), exact = TRUE)
})
test_that("can duckplyr_arrange() with unruly class", {
local_methods(
`[.dplyr_foobar` = function(x, i, ...) new_dispatched_quux(vec_slice(x, i)),
dplyr_row_slice.dplyr_foobar = function(x, i, ...) x[i, ]
)
df <- foobar(data.frame(x = 1:3))
expect_identical(
duckplyr_arrange(df, desc(x)),
quux(data.frame(x = 3:1, dispatched = TRUE))
)
})
test_that("duckplyr_arrange() preserves the call stack on error (#5308)", {
foobar <- function() stop("foo")
stack <- NULL
expect_error(
withCallingHandlers(
error = function(...) stack <<- sys.calls(),
duckplyr_arrange(mtcars, foobar())
)
)
expect_true(some(stack, is_call, "foobar"))
})
test_that("desc() inside duckplyr_arrange() checks the number of arguments (#5921)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
expect_snapshot({
df <- data.frame(x = 1, y = 2)
(expect_error(duckplyr_arrange(df, desc(x, y))))
})
})
test_that("arrange keeps zero length groups",{
df <- tibble(
e = 1,
f = factor(c(1, 1, 2, 2), levels = 1:3),
g = c(1, 1, 2, 2),
x = c(1, 2, 1, 4)
)
df <- duckplyr_group_by(df, e, f, g, .drop = FALSE)
expect_equal( duckplyr_group_size(duckplyr_arrange(df)), c(2, 2, 0) )
expect_equal( duckplyr_group_size(duckplyr_arrange(df, x)), c(2, 2, 0) )
})
# legacy --------------------------------------------------------------
test_that("legacy - using the global option `dplyr.legacy_locale` forces the system locale", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
skip_if_not(has_collate_locale("en_US"), message = "Can't use 'en_US' locale")
local_options(dplyr.legacy_locale = TRUE)
withr::local_collate("en_US")
df <- tibble(x = c("a", "A", "Z", "b"))
expect_identical(duckplyr_arrange(df, x)$x, c("a", "A", "b", "Z"))
})
test_that("legacy - usage of `.locale` overrides `dplyr.legacy_locale`", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
skip_if_not_installed("stringi", "1.5.3")
local_options(dplyr.legacy_locale = TRUE)
# Danish `o` with `/` through it sorts after `z` in Danish locale
x <- c("o", "\u00F8", "p", "z")
df <- tibble(x = x)
# American English locale puts it right after `o`
res <- duckplyr_arrange(df, x, .locale = "en")
expect_identical(res$x, x)
res <- duckplyr_arrange(df, x, .locale = "da")
expect_identical(res$x, x[c(1, 3, 4, 2)])
})
test_that("legacy - empty duckplyr_arrange() returns input", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = 1:10, y = 1:10)
gf <- duckplyr_group_by(df, x)
expect_identical(duckplyr_arrange(df), df)
expect_identical(duckplyr_arrange(gf), gf)
expect_identical(duckplyr_arrange(df, !!!list()), df)
expect_identical(duckplyr_arrange(gf, !!!list()), gf)
})
test_that("legacy - can sort empty data frame", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(a = numeric(0))
expect_equal(duckplyr_arrange(df, a), df)
})
test_that("legacy - local arrange sorts missing values to end", {
local_options(dplyr.legacy_locale = TRUE)
df <- data.frame(x = c(2, 1, NA))
expect_equal(df %>% duckplyr_arrange(x) %>% duckplyr_pull(), c(1, 2, NA))
expect_equal(df %>% duckplyr_arrange(desc(x)) %>% duckplyr_pull(), c(2, 1, NA))
})
test_that("legacy - arrange handles list columns (#282)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
# no intrinsic ordering
df <- tibble(x = 1:3, y = list(3, 2, 1))
expect_equal(duckplyr_arrange(df, y), df)
df <- tibble(x = 1:3, y = list(sum, mean, sd))
expect_equal(duckplyr_arrange(df, y), df)
})
test_that("legacy - arrange handles raw columns (#1803)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = 1:3, y = as.raw(3:1))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("legacy - arrange handles matrix columns", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = 1:3, y = matrix(6:1, ncol = 2))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("legacy - arrange handles data.frame columns (#3153)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = 1:3, y = data.frame(z = 3:1))
expect_equal(duckplyr_arrange(df, y), tibble(x = 3:1, y = data.frame(z = 1:3)))
})
test_that("legacy - arrange handles complex columns", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = 1:3, y = 3:1 + 2i)
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("legacy - arrange handles S4 classes (#1105)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
TestS4 <- suppressWarnings(setClass("TestS4", contains = "integer"))
setMethod('[', 'TestS4', function(x, i, ...){ TestS4(unclass(x)[i, ...]) })
on.exit(removeClass("TestS4"), add = TRUE)
df <- tibble(x = 1:3, y = TestS4(3:1))
expect_equal(duckplyr_arrange(df, y), df[3:1, ])
})
test_that("legacy - `duckplyr_arrange()` works with `numeric_version` (#6680)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
x <- numeric_version(c("1.11", "1.2.3", "1.2.2"))
df <- tibble(x = x)
expect <- df[c(3, 2, 1),]
expect_identical(duckplyr_arrange(df, x), expect)
})
test_that("legacy - arrange works with two columns when the first has a data frame proxy (#6268)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
# `id1` has a data frame proxy for `vec_proxy_order()`
df <- tibble(
id1 = new_rcrd(list(x = 1, y = 1)),
id2 = c(1, 3, 2)
)
out <- duckplyr_arrange(df, id1, id2)
expect_identical(out$id2, c(1, 2, 3))
})
test_that("legacy - duckplyr_arrange() supports across() and pick() (#4679)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(x = c(1, 3, 2, 1), y = c(4, 3, 2, 1))
expect_identical(
df %>% duckplyr_arrange(pick(everything())),
df %>% duckplyr_arrange(x, y)
)
expect_identical(
df %>% duckplyr_arrange(across(everything(), .fns = desc)),
df %>% duckplyr_arrange(desc(x), desc(y))
)
expect_identical(
df %>% duckplyr_arrange(pick(x)),
df %>% duckplyr_arrange(x)
)
expect_identical(
df %>% duckplyr_arrange(across(y, .fns = identity)),
df %>% duckplyr_arrange(y)
)
})
test_that("legacy - duckplyr_arrange() works with across() and pick() cols that return multiple columns (#6490)", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
df <- tibble(
a = c(1, 1, 1),
b = c(2, 2, 2),
c = c(4, 4, 3),
d = c(5, 2, 7)
)
expect_identical(
duckplyr_arrange(df, across(c(a, b), .fns = identity), across(c(c, d), .fns = identity)),
df[c(3, 2, 1),]
)
expect_identical(
duckplyr_arrange(df, pick(a, b), pick(c, d)),
df[c(3, 2, 1),]
)
})
test_that("legacy - arrange sorts missings in df-cols correctly", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
col <- tibble(a = c(1, 1, 1), b = c(3, NA, 1))
df <- tibble(x = col)
expect_identical(duckplyr_arrange(df, x), df[c(3, 1, 2),])
expect_identical(duckplyr_arrange(df, desc(x)), df[c(1, 3, 2),])
})
test_that("legacy - arrange with duplicates in a df-col uses a stable sort", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
col <- tibble(a = c(1, 1, 1, 1, 1), b = c(3, NA, 2, 3, NA))
df <- tibble(x = col, y = 1:5)
expect_identical(duckplyr_arrange(df, x)$y, c(3L, 1L, 4L, 2L, 5L))
expect_identical(duckplyr_arrange(df, desc(x))$y, c(1L, 4L, 3L, 2L, 5L))
})
test_that("legacy - arrange with doubly nested df-col doesn't infloop", {
skip_if(Sys.getenv("DUCKPLYR_FORCE") == "TRUE")
local_options(dplyr.legacy_locale = TRUE)
one <- tibble(a = c(1, 1, 1, 1, 1), b = c(1, 1, 2, 2, 2))
two <- tibble(a = c(1, 1, 1, 1, 1), b = c(2, 1, 1, 2, 2))
col <- tibble(one = one, two = two)
df <- tibble(x = col, y = c(1, 1, 1, 1, 0))
expect_identical(duckplyr_arrange(df, x, y), df[c(2, 1, 3, 5, 4),])
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.