test_that("can pivot all cols to wide", {
  df <- tibble(key = c("x", "y", "z"), val = 1:3)
  pv <- pivot_wider(df, names_from = key, values_from = val)

  expect_named(pv, c("x", "y", "z"))
  expect_equal(nrow(pv), 1)
})

test_that("non-pivoted cols are preserved", {
  df <- tibble(a = 1, key = c("x", "y"), val = 1:2)
  pv <- pivot_wider(df, names_from = key, values_from = val)

  expect_named(pv, c("a", "x", "y"))
  expect_equal(nrow(pv), 1)
})

test_that("implicit missings turn into explicit missings", {
  df <- tibble(a = 1:2, key = c("x", "y"), val = 1:2)
  pv <- pivot_wider(df, names_from = key, values_from = val)

  expect_equal(pv$a, c(1, 2))
  expect_equal(pv$x, c(1, NA))
  expect_equal(pv$y, c(NA, 2))
})

test_that("error if input is not a data.frame", {
  spec <- tibble(.name = "x", .value = "val", )
  expect_snapshot(
    pivot_wider_spec(list(), spec),
    error = TRUE
  )
})

test_that("error when overwriting existing column", {
  df <- tibble(
    a = c(1, 1),
    key = c("a", "b"),
    val = c(1, 2)
  )

  expect_snapshot(error = TRUE, {
    pivot_wider(df, names_from = key, values_from = val)
  })

  expect_snapshot(
    out <- pivot_wider(
      df,
      names_from = key,
      values_from = val,
      names_repair = "unique"
    )
  )
  expect_named(out, c("a...1", "a...2", "b"))
})

test_that("`names_repair` happens after spec column reorganization (#1107)", {
  df <- tibble(
    test = c("a", "b"),
    name = c("test", "test2"),
    value = c(1, 2)
  )

  out <- pivot_wider(df, names_repair = ~ make.unique(.x))

  expect_identical(out$test, c("a", "b"))
  expect_identical(out$test.1, c(1, NA))
  expect_identical(out$test2, c(NA, 2))
})

test_that("minimal `names_repair` doesn't overwrite a value column that collides with key column (#1107)", {
  df <- tibble(
    test = c("a", "b"),
    name = c("test", "test2"),
    value = c(1, 2)
  )

  out <- pivot_wider(df, names_repair = "minimal")

  expect_identical(out[[1]], c("a", "b"))
  expect_identical(out[[2]], c(1, NA))
  expect_identical(out[[3]], c(NA, 2))
})

test_that("grouping is preserved", {
  df <- tibble(g = 1, k = "x", v = 2)
  out <- df |>
    dplyr::group_by(g) |>
    pivot_wider(names_from = k, values_from = v)
  expect_equal(dplyr::group_vars(out), "g")
})

# https://github.com/tidyverse/tidyr/issues/804
test_that("column with `...j` name can be used as `names_from`", {
  df <- tibble(...8 = c("x", "y", "z"), val = 1:3)
  pv <- pivot_wider(df, names_from = ...8, values_from = val)
  expect_named(pv, c("x", "y", "z"))
  expect_equal(nrow(pv), 1)
})

test_that("data frame columns pivot correctly", {
  df <- tibble(
    i = c(1, 2, 1, 2),
    g = c("a", "a", "b", "b"),
    d = tibble(x = 1:4, y = 5:8)
  )

  out <- pivot_wider(df, names_from = g, values_from = d)
  expect_equal(out$a$x, 1:2)
  expect_equal(out$b$y, 7:8)
})

test_that("works with data.table and empty key_vars", {
  skip_if_not_installed("data.table")
  dt <- data.table::data.table(n = "a", v = 1)
  expect_equal(
    pivot_wider(dt, names_from = n, values_from = v),
    tibble(a = 1)
  )
})

test_that("`names_from` must be supplied if `name` isn't in `data` (#1240)", {
  df <- tibble(key = "x", val = 1)
  expect_snapshot(error = TRUE, {
    pivot_wider(df, values_from = val)
  })
})

test_that("`values_from` must be supplied if `value` isn't in `data` (#1240)", {
  df <- tibble(key = "x", val = 1)
  expect_snapshot(error = TRUE, {
    pivot_wider(df, names_from = key)
  })
})

test_that("`names_from` must identify at least 1 column (#1240)", {
  df <- tibble(key = "x", val = 1)
  expect_snapshot(error = TRUE, {
    pivot_wider(df, names_from = starts_with("foo"), values_from = val)
  })
})

test_that("`values_from` must identify at least 1 column (#1240)", {
  df <- tibble(key = "x", val = 1)
  expect_snapshot(error = TRUE, {
    pivot_wider(df, names_from = key, values_from = starts_with("foo"))
  })
})

test_that("`values_fn` emits an informative error when it doesn't result in unique values (#1238)", {
  df <- tibble(name = c("a", "a"), value = c(1, 2))
  expect_snapshot(error = TRUE, {
    pivot_wider(df, values_fn = list(value = ~.x))
  })
})

test_that("can pivot a manual spec with spec columns that don't identify any rows (#1250)", {
  # Looking for `x = 1L`
  spec <- tibble(.name = "name", .value = "value", x = 1L)

  # But that doesn't exist here...
  df <- tibble(key = "a", value = 1L, x = 2L)
  expect_identical(
    pivot_wider_spec(df, spec, id_cols = key),
    tibble(key = "a", name = NA_integer_)
  )

  # ...or here
  df <- tibble(key = character(), value = integer(), x = integer())
  expect_identical(
    pivot_wider_spec(df, spec, id_cols = key),
    tibble(key = character(), name = integer())
  )
})

test_that("pivoting with a manual spec and zero rows results in zero rows (#1252)", {
  spec <- tibble(.name = "name", .value = "value", x = 1L)

  df <- tibble(value = integer(), x = integer())
  expect_identical(pivot_wider_spec(df, spec), tibble(name = integer()))
})

test_that("can use `names_expand` to get sorted and expanded column names (#770)", {
  name1 <- factor(c(NA, "x"), levels = c("x", "y"))
  df <- tibble(name1 = name1, name2 = c("c", "d"), value = c(1, 2))

  na <- NA_real_

  expect_identical(
    pivot_wider(df, names_from = c(name1, name2), names_expand = TRUE),
    tibble(x_c = na, x_d = 2, y_c = na, y_d = na, NA_c = 1, NA_d = na)
  )
})

test_that("can fill only implicit missings from `names_expand`", {
  name1 <- factor(c(NA, "x"), levels = c("x", "y"))
  df <- tibble(name1 = name1, name2 = c("c", "d"), value = c(1, NA))

  res <- pivot_wider(
    data = df,
    names_from = c(name1, name2),
    names_expand = TRUE,
    values_fill = list(value = 0)
  )

  # But not the explicit missing!
  expect_identical(
    res,
    tibble(x_c = 0, x_d = NA_real_, y_c = 0, y_d = 0, NA_c = 1, NA_d = 0)
  )
})

test_that("expansion with `id_expand` and `names_expand` works with zero row data frames", {
  df <- tibble(
    id = factor(levels = c("b", "a")),
    name = factor(levels = c("a", "b")),
    value = integer()
  )

  res <- pivot_wider(df, names_expand = TRUE, id_expand = TRUE)

  expect_identical(res$id, factor(c("b", "a"), levels = c("b", "a")))
  expect_identical(res$a, c(NA_integer_, NA_integer_))
  expect_identical(res$b, c(NA_integer_, NA_integer_))
})

test_that("`build_wider_spec()` requires empty dots", {
  df <- tibble(name = c("x", "y", "z"), value = 1:3)

  expect_snapshot(error = TRUE, {
    build_wider_spec(df, 1)
  })
  expect_snapshot(error = TRUE, {
    build_wider_spec(df, name_prefix = "")
  })
})

test_that("`pivot_wider_spec()` requires empty dots", {
  df <- tibble(name = c("x", "y", "z"), value = 1:3)
  spec <- build_wider_spec(df)

  expect_snapshot(error = TRUE, {
    pivot_wider_spec(df, spec, 1)
  })
  expect_snapshot(error = TRUE, {
    pivot_wider_spec(df, spec, name_repair = "check_unique")
  })
})


test_that("doesn't crash when `id_cols` selects column removed by `names_from` (#1609)", {
  local_options(lifecycle_verbosity = "quiet")

  # Note how we have an "external vector" here. Ideally tidyselect would error
  # on this, but for legacy reasons we currently allow it with a warning, and it
  # produces a weird (but correct) tidyselect error
  x <- c(1, 100, 200, 300)

  df <- tibble(
    x = x,
    y = c(1, 2, 3, 4)
  )

  # Should get tidyselect error, not internal error
  expect_snapshot(error = TRUE, {
    pivot_wider(
      df,
      id_cols = x,
      values_from = y,
      names_from = x
    )
  })
})

test_that("doesn't crash when `id_cols` selects non-existent column (#1482)", {
  df <- tibble(name = c("x", "y"), value = c(1, 2))

  # Should get tidyselect error, not internal error
  expect_snapshot(error = TRUE, {
    pivot_wider(
      df,
      id_cols = c("non", "existent"),
      names_from = name,
      values_from = value
    )
  })

  df2 <- tibble(y = c("a", "a", "b", "c"), z = c(21, 22, 23, 24))

  expect_snapshot(error = TRUE, {
    pivot_wider(
      df2,
      id_cols = all_of(c("a", "b", "c")),
      names_from = y,
      values_from = z
    )
  })

  expect_snapshot(error = TRUE, {
    pivot_wider(df2, id_cols = 1:2, names_from = y, values_from = z)
  })
})

# column names -------------------------------------------------------------

test_that("names_glue affects output names", {
  df <- tibble(
    x = c("X", "Y"),
    y = 1:2,
    a = 1:2,
    b = 1:2
  )

  spec <- build_wider_spec(
    df,
    names_from = x:y,
    values_from = a:b,
    names_glue = "{x}{y}_{.value}"
  )
  expect_equal(spec$.name, c("X1_a", "Y2_a", "X1_b", "Y2_b"))
})

test_that("can sort column names", {
  df <- tibble(
    int = c(1, 3, 2),
    fac = factor(int, levels = 1:3, labels = c("Mon", "Tue", "Wed")),
  )
  spec <- build_wider_spec(
    df,
    names_from = fac,
    values_from = int,
    names_sort = TRUE
  )
  expect_equal(spec$.name, levels(df$fac))
})

test_that("can vary `names_from` values slowest (#839)", {
  df <- tibble(
    name = c("name1", "name2"),
    value1 = c(1, 2),
    value2 = c(4, 5)
  )

  spec <- build_wider_spec(
    df,
    names_from = name,
    values_from = c(value1, value2)
  )

  expect_identical(
    spec$.name,
    c("value1_name1", "value1_name2", "value2_name1", "value2_name2")
  )

  spec <- build_wider_spec(
    df,
    names_from = name,
    values_from = c(value1, value2),
    names_vary = "slowest"
  )

  expect_identical(
    spec$.name,
    c("value1_name1", "value2_name1", "value1_name2", "value2_name2")
  )
})

test_that("`names_vary` is validated", {
  df <- tibble(name = c("a", "b"), value = c(1, 2))

  expect_snapshot(error = TRUE, {
    build_wider_spec(df, names_vary = 1)
  })
  expect_snapshot(error = TRUE, {
    build_wider_spec(df, names_vary = "x")
  })
})

test_that("`names_expand` generates sorted column names even if no expansion is done", {
  df <- tibble(name = c(2, 1), value = c(1, 2))
  spec <- build_wider_spec(df, names_expand = TRUE)
  expect_identical(spec$.name, c("1", "2"))
})

test_that("`names_expand` does a cartesian expansion of `names_from` columns (#770)", {
  df <- tibble(name1 = c("a", "b"), name2 = c("c", "d"), value = c(1, 2))
  spec <- build_wider_spec(
    df,
    names_from = c(name1, name2),
    names_expand = TRUE
  )
  expect_identical(spec$.name, c("a_c", "a_d", "b_c", "b_d"))
})

test_that("`names_expand` expands all levels of a factor `names_from` column (#770)", {
  name1 <- factor(c(NA, "x"), levels = c("x", "y"))
  df <- tibble(name1 = name1, name2 = c("c", "d"), value = c(1, 2))
  spec <- build_wider_spec(
    df,
    names_from = c(name1, name2),
    names_expand = TRUE
  )
  expect_identical(spec$.name, c("x_c", "x_d", "y_c", "y_d", "NA_c", "NA_d"))
})

test_that("`names_expand` is validated", {
  df <- tibble(name = c("a", "b"), value = c(1, 2))

  expect_snapshot(error = TRUE, {
    build_wider_spec(df, names_expand = 1)
  })
  expect_snapshot(error = TRUE, {
    build_wider_spec(df, names_expand = "x")
  })
})

# keys ---------------------------------------------------------

test_that("can override default keys", {
  # fmt: skip
  df <- tribble(
    ~row, ~name, ~var, ~value,
    1, "Sam", "age", 10,
    2, "Sam", "height", 1.5,
    3, "Bob", "age", 20,
  )

  pv <- df |>
    pivot_wider(id_cols = name, names_from = var, values_from = value)
  expect_equal(nrow(pv), 2)
})

test_that("`id_cols = everything()` excludes `names_from` and `values_from`", {
  df <- tibble(key = "x", name = "a", value = 1L)

  expect_identical(
    pivot_wider(df, id_cols = everything()),
    tibble(key = "x", a = 1L)
  )

  spec <- build_wider_spec(df)

  expect_identical(
    pivot_wider_spec(df, spec, id_cols = everything()),
    tibble(key = "x", a = 1L)
  )
})

test_that("`id_cols` can't select columns from `names_from` or `values_from` (#1318)", {
  df <- tibble(name = c("x", "y"), value = c(1, 2))

  # And gives a nice error message!
  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_cols = name, names_from = name, values_from = value)
  })
  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_cols = value, names_from = name, values_from = value)
  })
})

test_that("`id_cols` returns a tidyselect error if a column selection is OOB (#1318)", {
  df <- tibble(name = c("x", "y"), value = c(1, 2))

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_cols = foo)
  })
})

test_that("named `id_cols` gives clear error (#1104)", {
  df <- tibble(name = c("x", "y"), value = c(1, 2), x = 1, y = 2)

  expect_snapshot(pivot_wider(df, id_cols = c(z = x)), error = TRUE)
})

test_that("pivoting a zero row data frame drops `names_from` and `values_from` (#1249)", {
  df <- tibble(key = character(), name = character(), value = integer())

  expect_identical(
    pivot_wider(df, names_from = name, values_from = value),
    tibble(key = character())
  )
})

test_that("known bug - building a wider spec with a zero row data frame loses `values_from` info (#1249)", {
  # We can't currently change this behavior in `pivot_wider_spec()`,
  # for fear of breaking backwards compatibility

  df <- tibble(key = character(), name = character(), value = integer())

  # Building the spec loses the fact that `value` was specified as `values_from`,
  # which would normally be in the `spec$.value` column
  spec <- build_wider_spec(df, names_from = name, values_from = value)

  # So pivoting with this spec accidentally keeps `value` around
  expect_identical(
    pivot_wider_spec(df, spec),
    tibble(key = character(), value = integer())
  )

  # If you specify `id_cols` to be the `key` column, it works right
  expect_identical(
    pivot_wider_spec(df, spec, id_cols = key),
    tibble(key = character())
  )

  # But `id_cols = everything()` won't work as intended, because we can't know
  # to remove `value` from `names(data)` before computing the tidy-selection
  expect_identical(
    pivot_wider_spec(df, spec, id_cols = everything()),
    tibble(key = character(), value = integer())
  )
})

test_that("`id_expand` generates sorted rows even if no expansion is done", {
  df <- tibble(id = c(2, 1), name = c("a", "b"), value = c(1, 2))
  res <- pivot_wider(df, id_expand = TRUE)
  expect_identical(res$id, c(1, 2))
})

test_that("`id_expand` does a cartesian expansion of `id_cols` columns (#770)", {
  df <- tibble(
    id1 = c(1, 2),
    id2 = c(3, 4),
    name = c("a", "b"),
    value = c(1, 2)
  )

  expect_identical(
    pivot_wider(df, id_expand = TRUE),
    tibble(
      id1 = c(1, 1, 2, 2),
      id2 = c(3, 4, 3, 4),
      a = c(1, NA, NA, NA),
      b = c(NA, NA, NA, 2),
    )
  )
})

test_that("`id_expand` expands all levels of a factor `id_cols` column (#770)", {
  id1 <- factor(c(NA, "x"), levels = c("x", "y"))
  df <- tibble(id1 = id1, id2 = c(1, 2), name = c("a", "b"), value = c(1, 2))

  res <- pivot_wider(df, id_expand = TRUE)

  expect_identical(res$id1, factor(c("x", "x", "y", "y", NA, NA)))
  expect_identical(res$id2, c(1, 2, 1, 2, 1, 2))
})

test_that("`id_expand` with `values_fill` only fills implicit missings", {
  id1 <- factor(c("x", "x"), levels = c("x", "y"))
  df <- tibble(id1 = id1, id2 = c(1, 2), name = c("a", "b"), value = c(1, NA))

  res <- pivot_wider(df, id_expand = TRUE, values_fill = 0)

  expect_identical(res$a, c(1, 0, 0, 0))
  expect_identical(res$b, c(0, NA, 0, 0))
})

test_that("`id_expand` with `values_fill` can't accidentally fill missings in `id_cols`", {
  id1 <- factor(c(NA, "x"), levels = c("x", "y"))
  df <- tibble(id1 = id1, id2 = c(1, 2), name = c("a", "b"), value = c(1, 2))

  res <- pivot_wider(df, id_expand = TRUE, values_fill = list(id1 = 0))

  # Still has NAs! Both implicit (new combination) and explicit (pre-existing combination)
  expect_identical(res$id1, factor(c("x", "x", "y", "y", NA, NA)))
})

test_that("`id_expand` is validated", {
  df <- tibble(name = c("a", "b"), value = c(1, 2))

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_expand = 1)
  })
  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_expand = "x")
  })
})

# non-unique keys ---------------------------------------------------------

test_that("duplicated keys produce list column with warning", {
  df <- tibble(a = c(1, 1, 2), key = c("x", "x", "x"), val = 1:3)

  expect_snapshot(pv <- pivot_wider(df, names_from = key, values_from = val))

  expect_equal(pv$a, c(1, 2))
  expect_equal(as.list(pv$x), list(c(1L, 2L), 3L))
})

test_that("duplicated key warning mentions every applicable column", {
  df <- tibble(
    key = c("x", "x"),
    a = c(1, 2),
    b = c(3, 4),
    c = c(5, 6)
  )

  expect_snapshot(
    pivot_wider(
      df,
      names_from = key,
      values_from = c(a, b, c)
    )
  )

  expect_snapshot(
    pivot_wider(
      df,
      names_from = key,
      values_from = c(a, b, c),
      values_fn = list(b = sum)
    )
  )
})

test_that("duplicated key warning backticks non-syntactic names", {
  df <- tibble(
    `a 1` = c(1, 1, 2),
    a2 = c(1, 1, 2),
    `the-key` = c("x", "x", "x"),
    val = 1:3
  )

  expect_snapshot(
    pv <- pivot_wider(df, names_from = `the-key`, values_from = val)
  )
})

test_that("warning suppressed by supplying values_fn", {
  df <- tibble(a = c(1, 1, 2), key = c("x", "x", "x"), val = 1:3)
  expect_no_warning(
    pv <- pivot_wider(
      df,
      names_from = key,
      values_from = val,
      values_fn = list(val = list)
    )
  )
  expect_equal(pv$a, c(1, 2))
  expect_equal(as.list(pv$x), list(c(1L, 2L), 3L))
})

test_that("values_fn can be a single function", {
  df <- tibble(a = c(1, 1, 2), key = c("x", "x", "x"), val = c(1, 10, 100))
  pv <- pivot_wider(df, names_from = key, values_from = val, values_fn = sum)
  expect_equal(pv$x, c(11, 100))
})

test_that("values_fn can be an anonymous function (#1114)", {
  df <- tibble(a = c(1, 1, 2), key = c("x", "x", "x"), val = c(1, 10, 100))
  pv <- pivot_wider(
    df,
    names_from = key,
    values_from = val,
    values_fn = ~ sum(.x)
  )
  expect_equal(pv$x, c(11, 100))
})

test_that("values_fn applied even when no-duplicates", {
  df <- tibble(a = c(1, 2), key = c("x", "x"), val = 1:2)
  pv <- pivot_wider(
    df,
    names_from = key,
    values_from = val,
    values_fn = list(val = list)
  )

  expect_equal(pv$a, c(1, 2))
  expect_equal(as.list(pv$x), list(1L, 2L))
})

test_that("values_fn is validated", {
  df <- tibble(name = "x", value = 1L)
  expect_snapshot(error = TRUE, {
    pivot_wider(df, values_fn = 1)
  })
})

# can fill missing cells --------------------------------------------------

test_that("can fill in missing cells", {
  df <- tibble(g = c(1, 2), var = c("x", "y"), val = c(1, 2))

  widen <- function(...) {
    df |> pivot_wider(names_from = var, values_from = val, ...)
  }

  expect_equal(widen()$x, c(1, NA))
  expect_equal(widen(values_fill = 0)$x, c(1, 0))
  expect_equal(widen(values_fill = list(val = 0))$x, c(1, 0))
})

test_that("values_fill only affects missing cells", {
  df <- tibble(g = c(1, 2), names = c("x", "y"), value = c(1, NA))
  out <- pivot_wider(
    df,
    names_from = names,
    values_from = value,
    values_fill = 0
  )
  expect_equal(out$y, c(0, NA))
})

test_that("values_fill works with data frame fill values", {
  df <- tibble(
    id = c(1L, 2L),
    name = c("x", "y"),
    value = tibble(a = 1:2, b = 2:3)
  )

  out <- pivot_wider(df, values_fill = tibble(a = 0L, b = 0L))

  expect_identical(out$x, tibble(a = c(1L, 0L), b = c(2L, 0L)))
  expect_identical(out$y, tibble(a = c(0L, 2L), b = c(0L, 3L)))
})

# multiple values ----------------------------------------------------------

test_that("can pivot from multiple measure cols", {
  df <- tibble(row = 1, var = c("x", "y"), a = 1:2, b = 3:4)
  sp <- build_wider_spec(df, names_from = var, values_from = c(a, b))
  pv <- pivot_wider_spec(df, sp)

  expect_named(pv, c("row", "a_x", "a_y", "b_x", "b_y"))
  expect_equal(pv$a_x, 1)
  expect_equal(pv$b_y, 4)
})

test_that("can pivot from multiple measure cols using all keys", {
  df <- tibble(var = c("x", "y"), a = 1:2, b = 3:4)
  sp <- build_wider_spec(df, names_from = var, values_from = c(a, b))
  pv <- pivot_wider_spec(df, sp)

  expect_named(pv, c("a_x", "a_y", "b_x", "b_y"))
  expect_equal(pv$a_x, 1)
  expect_equal(pv$b_y, 4)
})

test_that("column order in output matches spec", {
  # fmt: skip
  df <- tribble(
    ~hw,   ~name,  ~mark,   ~pr,
    "hw1", "anna",    95,  "ok",
    "hw2", "anna",    70, "meh",
  )

  # deliberately create weird order
  # fmt: skip
  sp <- tribble(
    ~hw, ~.value, ~.name,
    "hw1", "mark", "hw1_mark",
    "hw1", "pr", "hw1_pr",
    "hw2", "pr", "hw2_pr",
    "hw2", "mark", "hw2_mark",
  )

  pv <- pivot_wider_spec(df, sp)
  expect_named(pv, c("name", sp$.name))
})

# unused -------------------------------------------------------------------

test_that("`unused_fn` can summarize unused columns (#990)", {
  df <- tibble(
    id = c(1, 1, 2, 2),
    unused1 = c(1, 2, 4, 3),
    unused2 = c(1, 2, 4, 3),
    name = c("a", "b", "a", "b"),
    value = c(1, 2, 3, 4)
  )

  # By name
  res <- pivot_wider(df, id_cols = id, unused_fn = list(unused1 = max))
  expect_named(res, c("id", "a", "b", "unused1"))
  expect_identical(res$unused1, c(2, 4))

  # Globally
  res <- pivot_wider(df, id_cols = id, unused_fn = list)
  expect_named(res, c("id", "a", "b", "unused1", "unused2"))
  expect_identical(res$unused1, list(c(1, 2), c(4, 3)))
  expect_identical(res$unused2, list(c(1, 2), c(4, 3)))
})

test_that("`unused_fn` works with anonymous functions", {
  df <- tibble(
    id = c(1, 1, 2, 2),
    unused = c(1, NA, 4, 3),
    name = c("a", "b", "a", "b"),
    value = c(1, 2, 3, 4)
  )

  res <- pivot_wider(df, id_cols = id, unused_fn = ~ mean(.x, na.rm = TRUE))
  expect_identical(res$unused, c(1, 3.5))
})

test_that("`unused_fn` must result in single summary values", {
  df <- tibble(
    id = c(1, 1, 2, 2),
    unused = c(1, 2, 4, 3),
    name = c("a", "b", "a", "b"),
    value = c(1, 2, 3, 4)
  )

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_cols = id, unused_fn = identity)
  })
})

test_that("`unused_fn` works with expanded key from `id_expand`", {
  df <- tibble(
    id = factor(c(1, 1, 2, 2), levels = 1:3),
    unused = c(1, 2, 4, 3),
    name = c("a", "b", "a", "b"),
    value = c(1, 2, 3, 4)
  )

  res <- pivot_wider(df, id_cols = id, id_expand = TRUE, unused_fn = max)
  expect_identical(res$id, factor(1:3))
  expect_identical(res$unused, c(2, 4, NA))

  res <- pivot_wider(
    df,
    id_cols = id,
    id_expand = TRUE,
    unused_fn = ~ sum(is.na(.x))
  )
  expect_identical(res$unused, c(0L, 0L, 1L))
})

test_that("can't fill implicit missings in unused column with `values_fill`", {
  # (in theory this would need `unused_fill`, but it would only be used when
  # `id_expand = TRUE`, which doesn't feel that useful)

  df <- tibble(
    id = factor(c(1, 1, 2, 2), levels = 1:3),
    unused = c(1, 2, 4, 3),
    name = c("a", "b", "a", "b"),
    value = c(1, 2, 3, 4)
  )

  res <- pivot_wider(
    data = df,
    id_cols = id,
    id_expand = TRUE,
    unused_fn = list,
    values_fill = 0
  )

  expect_identical(res$a, c(1, 3, 0))
  expect_identical(res$b, c(2, 4, 0))
  expect_identical(res$unused, list(c(1, 2), c(4, 3), NA_real_))

  res <- pivot_wider(
    data = df,
    id_cols = id,
    id_expand = TRUE,
    unused_fn = list,
    values_fill = list(unused = 0)
  )

  expect_identical(res$unused, list(c(1, 2), c(4, 3), NA_real_))
})

test_that("`values_fill` is validated", {
  df <- tibble(name = "a", value = 1)

  expect_snapshot(error = TRUE, {
    pivot_wider(df, values_fill = 1:2)
  })
})

test_that("`unused_fn` is validated", {
  df <- tibble(id = 1, unused = 1, name = "a", value = 1)

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id_cols = id, unused_fn = 1)
  })
})

# deprecated ---------------------------------------------------------------

test_that("`id_cols` has noisy compat behavior (#1353)", {
  df <- tibble(
    id = c(1, 2),
    id2 = c(3, 4),
    name = c("a", "b"),
    value = c(5, 6)
  )

  # Noisy
  expect_snapshot({
    out <- pivot_wider(df, id)
  })

  # Silent
  expect_snapshot({
    expect <- pivot_wider(df, id_cols = id)
  })

  expect_identical(out, expect)
})

test_that("`id_cols` compat behavior doesn't trigger if `id_cols` is specified too", {
  df <- tibble(
    id = c(1, 2),
    id2 = c(3, 4),
    name = c("a", "b"),
    value = c(5, 6)
  )

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id, id_cols = id2)
  })
})

test_that("`id_cols` compat behavior doesn't trigger if multiple `...` are supplied", {
  df <- tibble(
    id = c(1, 2),
    id2 = c(3, 4),
    name = c("a", "b"),
    value = c(5, 6)
  )

  expect_snapshot(error = TRUE, {
    pivot_wider(df, id, id2)
  })
})

test_that("`id_cols` compat behavior doesn't trigger if named `...` are supplied", {
  df <- tibble(
    id = c(1, 2),
    id2 = c(3, 4),
    name = c("a", "b"),
    value = c(5, 6)
  )

  expect_snapshot(error = TRUE, {
    pivot_wider(df, ids = id)
  })
})
