# ------------------------------------------------------------------------------ # vec_interval_groups() test_that("can compute groups", { x <- data_frame( start = c(1L, 9L, 2L, 2L, 10L), end = c(5L, 11L, 6L, 8L, 12L) ) expect_identical( vec_interval_groups(x$start, x$end), data_frame(start = c(1L, 9L), end = c(8L, 12L)) ) }) test_that("can group with size one input", { x <- data_frame(start = 1L, end = 2L) expect_identical( vec_interval_groups(x$start, x$end), x ) }) test_that("can group with size zero input", { x <- data_frame(start = integer(), end = integer()) expect_identical( vec_interval_groups(x$start, x$end), x ) }) test_that("missing intervals are retained", { x <- data_frame(start = NA, end = NA) expect_identical( vec_interval_groups(x$start, x$end), x ) x <- data_frame(start = c(NA, NA), end = c(NA, NA)) expect_identical( vec_interval_groups(x$start, x$end), x[1,] ) x <- data_frame(start = c(3, NA, 2, NA), end = c(5, NA, 3, NA)) expect_identical( vec_interval_groups(x$start, x$end), data_frame(start = c(2, NA), end = c(5, NA)) ) }) test_that("missing intervals can be dropped", { x <- data_frame(start = NA, end = NA) expect_identical( vec_interval_groups(x$start, x$end, missing = "drop"), data_frame(start = logical(), end = logical()) ) x <- data_frame(start = c(NA, NA), end = c(NA, NA)) expect_identical( vec_interval_groups(x$start, x$end, missing = "drop"), data_frame(start = logical(), end = logical()) ) x <- data_frame(start = c(3, NA, 2, NA), end = c(5, NA, 3, NA)) expect_identical( vec_interval_groups(x$start, x$end, missing = "drop"), data_frame(start = 2, end = 5) ) }) test_that("max endpoint is retained even if it isn't the last in the group", { # 10 is max end of first group, but 5 is last value in that group x <- data_frame(start = c(1L, 2L, 12L), end = c(10L, 5L, 15L)) expect_identical( vec_interval_groups(x$start, x$end), data_frame(start = c(1L, 12L), end = c(10L, 15L)) ) }) # ------------------------------------------------------------------------------ # vec_interval_locate_groups() test_that("can locate groups", { x <- data_frame( start = c(1L, 9L, 2L, 2L, 10L), end = c(5L, 11L, 6L, 8L, 12L) ) out <- vec_interval_locate_groups(x$start, x$end) expect_identical( out$key, data_frame(start = c(1L, 9L), end = c(8L, 12L)) ) expect_identical( out$loc, list(c(1L, 3L, 4L), c(2L, 5L)) ) }) test_that("can locate groups with size one input", { expect_identical( vec_interval_locate_groups(1L, 2L), data_frame( key = data_frame(start = 1L, end = 2L), loc = list(1L) ) ) }) test_that("can locate groups with size zero input", { expect_identical( vec_interval_locate_groups(integer(), integer()), data_frame( key = data_frame(start = integer(), end = integer()), loc = list() ) ) }) test_that("locations are ordered by both `start` and `end`", { x <- data_frame(start = c(4L, 4L, 1L), end = c(6L, 5L, 2L)) out <- vec_interval_locate_groups(x$start, x$end) # Ties of `start = 4` are broken by `end` values and reordered expect_identical( out$loc, list(3L, c(2L, 1L)) ) # So this orders `x` expect_identical( vec_slice(x, unlist(out$loc)), vec_sort(x) ) }) test_that("missing intervals are retained", { x <- data_frame(start = NA, end = NA) out <- vec_interval_locate_groups(x$start, x$end) expect_identical( out$key, data_frame(start = NA, end = NA) ) expect_identical( out$loc, list(1L) ) x <- data_frame(start = c(3, NA, 2, NA), end = c(5, NA, 3, NA)) out <- vec_interval_locate_groups(x$start, x$end) expect_identical( out$key, data_frame(start = c(2, NA), end = c(5, NA)) ) expect_identical( out$loc, list(c(3L, 1L), c(2L, 4L)), ) }) test_that("missing intervals can be dropped", { x <- data_frame(start = NA, end = NA) out <- vec_interval_locate_groups(x$start, x$end, missing = "drop") expect_identical( out$key, data_frame(start = logical(), end = logical()) ) expect_identical( out$loc, list() ) x <- data_frame(start = c(3, NA, 2, NA), end = c(5, NA, 3, NA)) out <- vec_interval_locate_groups(x$start, x$end, missing = "drop") expect_identical( out$key, data_frame(start = 2, end = 5) ) expect_identical( out$loc, list(c(3L, 1L)), ) }) test_that("treats NA and NaN as equivalent with doubles", { x <- data_frame(start = c(NA, NaN, NA, NaN), end = c(NA, NA, NaN, NaN)) out <- vec_interval_locate_groups(x$start, x$end) expect_identical( out$key, data_frame(start = NA_real_, end = NaN) ) expect_identical( out$loc, list(1:4), ) out <- vec_interval_locate_groups(x$start, x$end, missing = "drop") expect_identical( out$key, data_frame(start = double(), end = double()) ) expect_identical( out$loc, list(), ) }) test_that("recognizes missing rows in data frames", { start <- data_frame(year = c(2019, NA, NA, 2019, 2019), month = c(12, NA, NA, 12, 12)) end <- data_frame(year = c(2020, NA, NA, 2020, 2020), month = c(2, NA, NA, 11, 12)) x <- data_frame(start = start, end = end) out <- vec_interval_locate_groups(x$start, x$end) expect_start <- data_frame(year = c(2019, NA), month = c(12, NA)) expect_end <- data_frame(year = c(2020, NA), month = c(12, NA)) expect <- data_frame(start = expect_start, end = expect_end) expect_identical(out$key, expect) expect_identical(out$loc, list(c(1L, 4L, 5L), c(2L, 3L))) }) test_that("works on various types", { x <- data_frame(start = c(1.5, 2, 3.1, NA), end = c(1.7, 3.2, 4.5, NA)) out <- vec_interval_locate_groups(x$start, x$end) expect_identical(out$key, data_frame(start = c(1.5, 2, NA), end = c(1.7, 4.5, NA))) expect_identical(out$loc, list(1L, 2:3, 4L)) out <- vec_interval_locate_groups(x$start, x$end, missing = "drop") expect_identical(out$key, data_frame(start = c(1.5, 2), end = c(1.7, 4.5))) expect_identical(out$loc, list(1L, 2:3)) x <- data_frame(start = c("a", "c", "f", NA), end = c("b", "g", "h", NA)) out <- vec_interval_locate_groups(x$start, x$end) expect_identical(out$key, data_frame(start = c("a", "c", NA), end = c("b", "h", NA))) expect_identical(out$loc, list(1L, 2:3, 4L)) out <- vec_interval_locate_groups(x$start, x$end, missing = "drop") expect_identical(out$key, data_frame(start = c("a", "c"), end = c("b", "h"))) expect_identical(out$loc, list(1L, 2:3)) }) test_that("can keep abutting intervals separate", { # after x <- data_frame(start = c(1L, 2L, 0L), end = c(2L, 3L, 2L)) out <- vec_interval_locate_groups(x$start, x$end, abutting = FALSE) expect_identical(out$key, data_frame(start = c(0L, 2L), end = c(2L, 3L))) expect_identical(out$loc, list(c(3L, 1L), 2L)) # before x <- data_frame(start = c(1L, 0L), end = c(2L, 1L)) out <- vec_interval_locate_groups(x$start, x$end, abutting = FALSE) expect_identical(out$key, data_frame(start = c(0L, 1L), end = c(1L, 2L))) expect_identical(out$loc, list(2L, 1L)) # both x <- data_frame(start = c(1L, 0L, 2L), end = c(2L, 1L, 3L)) out <- vec_interval_locate_groups(x$start, x$end, abutting = FALSE) expect_identical(out$key, data_frame(start = c(0L, 1L, 2L), end = c(1L, 2L, 3L))) expect_identical(out$loc, list(2L, 1L, 3L)) }) test_that("`missing` is validated", { expect_snapshot((expect_error(vec_interval_locate_groups(1, 2, missing = "s")))) expect_snapshot((expect_error(vec_interval_locate_groups(1, 2, missing = c("group", "drop"))))) }) test_that("common type is taken", { expect_snapshot((expect_error(vec_interval_locate_groups(1, "x")))) }) # ------------------------------------------------------------------------------ # vec_interval_complement() test_that("computes the complement", { x <- data_frame( start = c(6L, 1L, 2L, 12L), end = c(9L, 3L, 4L, 14L) ) expect_identical( vec_interval_complement(x$start, x$end), data_frame(start = c(4L, 9L), end = c(6L, 12L)) ) }) test_that("treats intervals as half-open like [a, b)", { x <- data_frame( start = c(1L, 5L), end = c(4L, 6L) ) expect_identical( vec_interval_complement(x$start, x$end), data_frame(start = 4L, end = 5L) ) }) test_that("`[a, b)` and `[b, c)` result in no complement values", { x <- data_frame( start = c(1L, 5L), end = c(5L, 6L) ) expect_identical( vec_interval_complement(x$start, x$end), data_frame(start = integer(), end = integer()) ) }) test_that("works with `lower == upper`", { x <- data_frame( start = c(1L, 2L, 12L, NA), end = c(10L, 5L, 15L, NA) ) expect_identical( vec_interval_complement(x$start, x$end, lower = 10L, upper = 10L), data_frame(start = integer(), end = integer()) ) expect_identical( vec_interval_complement(x$start, x$end, lower = -1L, upper = -1L), data_frame(start = integer(), end = integer()) ) expect_identical( vec_interval_complement(x$start, x$end, lower = 20L, upper = 20L), data_frame(start = integer(), end = integer()) ) }) test_that("works with `lower` before any values", { x <- data_frame( start = c(1L, 2L, 12L, NA), end = c(10L, 5L, 15L, NA) ) expect_identical( vec_interval_complement(x$start, x$end, lower = -1L), data_frame(start = c(-1L, 10L), end = c(1L, 12L)) ) }) test_that("works if both `lower` and `upper` are before any values", { x <- data_frame( start = c(2L, 1L, 12L, NA), end = c(5L, 10L, 15L, NA) ) expect_identical( vec_interval_complement(x$start, x$end, lower = -5L, upper = -2L), data_frame(start = -5L, end = -2L) ) }) test_that("works with `upper` after any values", { x <- data_frame( start = c(2L, 1L, 13L, 12L, NA), end = c(5L, 10L, 17L, 15L, NA) ) expect_identical( vec_interval_complement(x$start, x$end, upper = 20L), data_frame(start = c(10L, 17L), end = c(12L, 20L)) ) }) test_that("works if both `lower` and `upper` are after any values", { x <- data_frame( start = c(2L, 1L, 12L, NA), end = c(5L, 10L, 15L, NA) ) expect_identical( vec_interval_complement(x$start, x$end, lower = 17L, upper = 19L), data_frame(start = 17L, end = 19L) ) }) test_that("works with only NA and `lower`", { x <- data_frame(start = NA_integer_, end = NA_integer_) expect_identical(vec_interval_complement(x$start, x$end, lower = 5L), data_frame(start = integer(), end = integer())) }) test_that("works with only NA and `upper`", { x <- data_frame(start = NA_integer_, end = NA_integer_) expect_identical(vec_interval_complement(x$start, x$end, upper = 5L), data_frame(start = integer(), end = integer())) }) test_that("works with only NA and both `lower` and `upper`", { x <- data_frame(start = NA_integer_, end = NA_integer_) expect_identical(vec_interval_complement(x$start, x$end, lower = 2L, upper = 5L), data_frame(start = 2L, end = 5L)) }) test_that("works with `lower` that is on the max set value", { x <- data_frame( start = c(1L, 12L), end = c(9L, 13L) ) expect_identical( vec_interval_complement(x$start, x$end, lower = 9L), data_frame(start = 9L, end = 12L) ) }) test_that("works with `upper` that is on the max set value", { x <- data_frame( start = c(-5L, 1L, 2L, 12L), end = c(0L, 10L, 5L, 15L) ) expect_identical( vec_interval_complement(x$start, x$end, upper = 10L), data_frame(start = 0L, end = 1L) ) expect_identical( vec_interval_complement(x$start, x$end, lower = 10L, upper = 10L), data_frame(start = integer(), end = integer()) ) }) test_that("size zero case generally returns nothing", { expect_identical( vec_interval_complement(integer(), integer()), data_frame(start = integer(), end = integer()) ) expect_identical( vec_interval_complement(integer(), integer(), lower = 5L), data_frame(start = integer(), end = integer()) ) expect_identical( vec_interval_complement(integer(), integer(), upper = 5L), data_frame(start = integer(), end = integer()) ) }) test_that("size zero case with both `lower` and `upper` returns an interval", { expect_identical( vec_interval_complement(integer(), integer(), lower = 5L, upper = 10L), data_frame(start = 5L, end = 10L) ) }) test_that("size zero case with `lower == upper` doesn't return anything", { expect_identical( vec_interval_complement(integer(), integer(), lower = 5L, upper = 5L), data_frame(start = integer(), end = integer()) ) }) test_that("works when `lower` is contained in an interval", { expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = 3), data_frame(start = 5, end = 10) ) }) test_that("works when `lower` is in a gap between intervals", { expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = 7), data_frame(start = 7, end = 10) ) }) test_that("works when `upper` is in a gap between intervals", { expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), upper = 7), data_frame(start = c(-3, 5), end = c(1, 7)) ) }) test_that("works when `lower` and `upper` are in a gap between intervals", { expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = 6, upper = 7), data_frame(start = 6, end = 7) ) expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = 7, upper = 7), data_frame(start = double(), end = double()) ) }) test_that("works when `lower` and `upper` have an interval between them", { expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = 0, upper = 7), data_frame(start = c(0, 5), end = c(1, 7)) ) expect_identical( vec_interval_complement(c(-5, 1, 10), c(-3, 5, 15), lower = -6, upper = 7), data_frame(start = c(-6, -3, 5), end = c(-5, 1, 7)) ) }) test_that("allow `lower > upper` which returns an empty interval", { x <- data_frame(start = c(1, 2), end = c(5, 12)) expect_identical( vec_interval_complement(x$start, x$end, lower = 10, upper = 9), data_frame(start = double(), end = double()) ) }) test_that("complement works when `lower` and `upper` are in the same interval", { x <- data_frame(start = 1, end = 5) expect_identical( vec_interval_complement(x$start, x$end, lower = 2, upper = 4), data_frame(start = double(), end = double()) ) }) test_that("`lower` and `upper` can't contain missing values", { expect_snapshot({ (expect_error(vec_interval_complement(1, 2, lower = NA))) (expect_error(vec_interval_complement(1, 2, upper = NA))) start <- data_frame(x = 1, y = 2) end <- data_frame(x = 1, y = 3) (expect_error(vec_interval_complement(start, end, lower = data_frame(x = 1, y = NA)))) (expect_error(vec_interval_complement(start, end, upper = data_frame(x = 1, y = NA)))) }) }) # ------------------------------------------------------------------------------ # vec_interval_locate_containers() test_that("can locate containers", { x <- data_frame( start = c(1L, 9L, 2L, 2L, 10L), end = c(5L, 12L, 6L, 8L, 12L) ) expect_identical( vec_interval_locate_containers(x$start, x$end), c(1L, 4L, 2L) ) }) test_that("can locate containers with size one input", { x <- data_frame(start = 1L, end = 2L) expect_identical( vec_interval_locate_containers(x$start, x$end), 1L ) }) test_that("can locate containers with size zero input", { x <- data_frame(start = integer(), end = integer()) expect_identical( vec_interval_locate_containers(x$start, x$end), integer() ) }) test_that("missing intervals are retained", { x <- data_frame(start = NA, end = NA) expect_identical( vec_interval_locate_containers(x$start, x$end), 1L ) x <- data_frame(start = c(NA, NA), end = c(NA, NA)) # Ties use first missing value seen expect_identical( vec_interval_locate_containers(x$start, x$end), 1L ) x <- data_frame(start = c(3, NA, 2, NA), end = c(5, NA, 5, NA)) # Missing intervals at the end expect_identical( vec_interval_locate_containers(x$start, x$end), c(3L, 2L) ) }) test_that("locations order the intervals", { x <- data_frame(start = c(4L, 4L, 1L, NA, 4L), end = c(5L, 6L, 2L, NA, 6L)) out <- vec_interval_locate_containers(x$start, x$end) expect_identical( out, c(3L, 2L, 4L) ) # This orders `x` expect_identical( vec_slice(x, out), vec_sort(vec_slice(x, out)) ) }) test_that("treats NA and NaN as equivalent with doubles", { x <- data_frame(start = c(NA, NaN, NA, NaN), end = c(NA, NA, NaN, NaN)) expect_identical(vec_interval_locate_containers(x$start, x$end), 1L) }) test_that("recognizes missing rows in data frames", { start <- data_frame(year = c(2019, NA, NA, 2019, 2019), month = c(12, NA, NA, 12, 12)) end <- data_frame(year = c(2020, NA, NA, 2020, 2020), month = c(2, NA, NA, 11, 12)) x <- data_frame(start = start, end = end) expect_identical( vec_interval_locate_containers(x$start, x$end), c(5L, 2L) ) }) test_that("duplicate containers return the first", { x <- data_frame(start = c(1, 1, 2, 1, 2), end = c(2, 2, 3, 2, 3)) expect_identical(vec_interval_locate_containers(x$start, x$end), c(1L, 3L)) }) test_that("works on various types", { x <- data_frame(start = c(1.5, 3, NA, 1.6, NA), end = c(1.7, 3.1, NA, 3.2, NA)) out <- vec_interval_locate_containers(x$start, x$end) expect_identical(out, c(1L, 4L, 3L)) x <- data_frame(start = c("a", "a", NA, "f", NA), end = c("b", "g", NA, "h", NA)) out <- vec_interval_locate_containers(x$start, x$end) expect_identical(out, c(2L, 4L, 3L)) }) test_that("common type is taken", { expect_snapshot((expect_error(vec_interval_locate_containers(1, "x")))) })