tests/testthat/test-unnest-tree.R

test_that("checks arguments", {
  df <- tibble::tibble(
    id = 1,
    x = "a",
    children = list()
  )

  expect_snapshot({
    (expect_error(unnest_tree(1L)))

    (expect_error(unnest_tree(df, id_col = "not-there")))
    (expect_error(unnest_tree(df, id_col = 1:2)))

    (expect_error(unnest_tree(df, id_col, children = "not-there")))
    (expect_error(unnest_tree(df, id_col, children = 1:2)))

    (expect_error(unnest_tree(df, children, children)))
    (expect_error(unnest_tree(df, id, children, level_to = 1L)))
    (expect_error(unnest_tree(df, id, children, level_to = "id")))
    (expect_error(unnest_tree(df, id, children, level_to = c("a", "b"))))

    (expect_error(unnest_tree(df, id, children, parent_to = "level")))
    (expect_error(unnest_tree(df, id, children, parent_to = 1L)))
    (expect_error(unnest_tree(df, id, children, parent_to = "id")))
    (expect_error(unnest_tree(df, id, children, parent_to = c("a", "b"))))

    (expect_error(unnest_tree(df, id, children, ancestors_to = "level")))
    (expect_error(unnest_tree(df, id, children, ancestors_to = "parent")))
    (expect_error(unnest_tree(df, id, children, ancestors_to = 1L)))
    (expect_error(unnest_tree(df, id, children, ancestors_to = "id")))
    (expect_error(unnest_tree(df, id, children, ancestors_to = c("a", "b"))))
  })

  expect_snapshot({

  })
})

test_that("child col type is checked", {
  df <- tibble::tibble(
    id = 1,
    x = "a",
    children = 1L
  )

  df2 <- df
  df2$children <- list(1L)

  expect_snapshot({
    (expect_error(unnest_tree(df, id, children)))
    (expect_error(unnest_tree(df2, id, children)))
  })

  df <- tibble::tibble(
    id = 1,
    x = "a",
    children = list(1L)
  )

  expect_snapshot({
    (expect_error(unnest_tree(df, id, children)))
  })
})

test_that("can unnest", {
  # simple case
  df <- tibble::tibble(
    id = 1L,
    x = "a",
    children = list(
      tibble::tibble(
        id = 2:3,
        x = c("b", "c"),
        children = list(NULL)
      )
    )
  )

  expect_equal(
    unnest_tree(df, id, children, ancestors_to = "ancestors"),
    tibble::tibble(
      id = 1:3,
      x = c("a", "b", "c"),
      level = c(1L, 2L, 2L),
      parent = c(NA, 1L, 1L),
      ancestors = list(NULL, 1L, 1L)
    )
  )

  # some elements with children, others not
  df <- tibble::tibble(
    id = 1:2,
    x = c("a", "b"),
    children = list(
      tibble::tibble(
        id = 3L,
        x = "c",
        children = list(NULL)
      ),
      NULL
    )
  )

  expect_equal(
    unnest_tree(df, id, children, ancestors_to = "ancestors"),
    tibble::tibble(
      id = 1:3,
      x = c("a", "b", "c"),
      level = c(1L, 1L, 2L),
      parent = c(NA, NA, 1L),
      ancestors = list(NULL, NULL, 1L)
    )
  )

  # deep nesting
  df <- tibble::tibble(
    id = 1:2,
    x = c("a", "b"),
    children = list(
      tibble::tibble(
        id = 3L,
        x = "c",
        children = list(
          tibble::tibble(
            id = 5L,
            x = "e",
            children = list(
              tibble::tibble(
                id = 6L, x = "f", children = list(NULL)
              )
            )
          )
        )
      ),
      tibble::tibble(
        id = 4,
        x = "d",
        children = list(NULL)
      )
    )
  )

  expect_equal(
    unnest_tree(df, id, children, ancestors_to = "ancestors"),
    tibble::tibble(
      id = 1:6,
      x = letters[1:6],
      level = c(1L, 1L, 2L, 2L, 3L, 4L),
      parent = c(NA, NA, 1L, 2L, 3L, 5L),
      ancestors = list(
        NULL,
        NULL,
        1L,
        2L,
        c(1L, 3L),
        c(1L, 3L, 5L)
      )
    )
  )
})

test_that("can handle list_of children", {
  df <- tibble::tibble(
    id = 1L,
    x = "a",
    children = list_of(
      tibble::tibble(
        id = 2:3,
        x = c("b", "c"),
        children = list_of(
          tibble(id = 4, x = "d"),
          NULL
        )
      )
    )
  )

  expect_equal(
    unnest_tree(df, id, children, ancestors_to = "ancestors"),
    tibble::tibble(
      id = 1:4,
      x = c("a", "b", "c", "d"),
      level = c(1L, 2L, 2L, 3L),
      parent = c(NA, 1L, 1L, 2),
      ancestors = list(NULL, 1L, 1L, c(1L, 2L))
    )
  )
})

test_that("can handle children of differen types", {
  df <- tibble::tibble(
    id = 1:2,
    x = c("a", "b"),
    children = list(
      tibble::tibble(id = 3L, x = "c", children = list(NULL)),
      tibble::tibble(id = 4.0, x = "d", children = list(NULL))
    )
  )

  result <- unnest_tree(df, id, children)
  expect_identical(
    result,
    tibble(
      id = c(1, 2, 3, 4),
      x = c("a", "b", "c", "d"),
      level = c(1L, 1L, 2L, 2L),
      parent = c(NA, NA, 1, 2)
    )
  )
  expect_type(result$id, "double")

  df <- tibble::tibble(
    id = 1L,
    x = "a",
    children = list(
      tibble::tibble(id = "a", x = "c", children = list(NULL))
    )
  )

  # TODO produce a nicer error message here giving the path of the child?
  expect_snapshot({
    (expect_error(unnest_tree(df, id, children)))
  })
})

test_that("can handle if all childre have no children column", {
  df <- tibble::tibble(
    id = 1,
    x = "a",
    children = list(NULL)
  )
  expect_equal(
    unnest_tree(df, id, children),
    tibble(id = 1, x = "a", level = 1L, parent = NA_real_)
  )
})

test_that("can handle 0 row data", {
  df <- tibble::tibble(
    id = integer(),
    x = character(),
    children = list()
  )

  expect_equal(
    unnest_tree(df, id, children, ancestors_to = "ancestors"),
    tibble::tibble(
      id = integer(),
      x = character(),
      level = integer(),
      parent = integer(),
      ancestors = list()
    )
  )
})

test_that("checks ids", {
  df_duplicated <- tibble::tibble(
    id = 1L,
    x = "a",
    children = list(
      tibble::tibble(
        id = 1L,
        x = "b",
        children = list(NULL)
      )
    )
  )

  df_na <- df_duplicated
  df_na$children[[1]]$id <- NA

  expect_snapshot({
    (expect_error(unnest_tree(df_duplicated, id, children)))
    (expect_error(unnest_tree(df_na, id, children)))
  })
})

Try the tibblify package in your browser

Any scripts or data that you put into this service are public.

tibblify documentation built on Nov. 16, 2022, 5:07 p.m.