context("Combinations")

test_that("Combinations - ncombinations", {
    L = c(LETTERS, letters)
    expect_equal(ncombinations(10, 3), 120)
    expect_equal(ncombinations(x = L[1:10], k = 3), 120)
    expect_error(ncombinations(40, 15), "integer overflow")
    expect_error(ncombinations(x = L[1:40], k = 15), "integer overflow")
    expect_equal(ncombinations(40, 15, bigz = TRUE), gmp::as.bigz("40225345056"))
    expect_equal(ncombinations(10, 0), 1)
    expect_equal(ncombinations(10, 11), 0)
    expect_error(ncombinations(10, -1), "expect integer")
    expect_error(ncombinations(10, 1.5), "expect integer")

    expect_equal(ncombinations(0, 0), 1)
    expect_equal(ncombinations(0, 1), 0)
})

test_that("Combinations - combinations", {
    comb <- combinations(10, 3)
    expect_equal(nrow(comb), 120)
    expect_equal(ncol(comb), 3)
    expect_equal(comb[1, ], 1:3)
    expect_equal(comb[120, ], 8:10)

    comb <- combinations(10, 3, layout = "row")
    expect_equal(nrow(comb), 120)
    expect_equal(ncol(comb), 3)
    expect_equal(comb[1, ], 1:3)
    expect_equal(comb[120, ], 8:10)

    comb <- combinations(10, 3, layout = "column")
    expect_equal(ncol(comb), 120)
    expect_equal(nrow(comb), 3)
    expect_equal(comb[, 1], 1:3)
    expect_equal(comb[, 120], 8:10)

    comb <- combinations(10, 3, layout = "list")
    expect_equal(length(comb), 120)
    expect_equal(comb[[1]], 1:3)
    expect_equal(comb[[120]], 8:10)

    comb <- combinations(x = LETTERS[1:10], k = 3)
    expect_equal(nrow(comb), 120)
    expect_equal(ncol(comb), 3)
    expect_equal(comb[1, ], LETTERS[1:3])
    expect_equal(comb[120, ], LETTERS[8:10])

    expect_error(combinations(40, 15), "too many results")
    expect_error(combinations(10, -1), "expect integer")
    expect_error(combinations(10, 1.5), "expect integer")
    expect_equal(dim(combinations(10, 0)), c(1, 0))
    expect_equal(dim(combinations(10, 11)), c(0, 11))
    expect_equal(dim(combinations(0, 0)), c(1, 0))
    expect_equal(dim(combinations(0, 1)), c(0, 1))
})

test_that("Combinations - icombinations", {
    icomb <- icombinations(10, 3)
    comb <- combinations(10, 3)
    expect_equal(icomb$collect(), comb)
    expect_equal(icomb$getnext(), 1:3)
    expect_equal(icomb$getnext(), c(1, 2, 4))
    icomb$getnext(110)
    expect_equal(nrow(icomb$getnext(10)), 8)
    expect_equal(icomb$getnext(), NULL)

    comb <- combinations(10, 3, layout = "row")
    expect_equal(icomb$collect(layout = "row"), comb)
    expect_equal(icomb$getnext(layout = "row"), t(1:3))
    expect_equal(icomb$getnext(layout = "row"), t(c(1, 2, 4)))
    icomb$getnext(110, layout = "row")
    expect_equal(nrow(icomb$getnext(10, layout = "row")), 8)
    expect_equal(icomb$getnext(layout = "row"), NULL)

    comb <- combinations(10, 3, layout = "column")
    expect_equal(icomb$collect(layout = "column"), comb)
    expect_equal(icomb$getnext(layout = "column"), t(t(1:3)))
    expect_equal(icomb$getnext(layout = "column"), t(t(c(1, 2, 4))))
    icomb$getnext(110, layout = "column")
    expect_equal(ncol(icomb$getnext(10, layout = "column")), 8)
    expect_equal(icomb$getnext(layout = "column"), NULL)

    comb <- combinations(10, 3, layout = "list")
    expect_equal(icomb$collect(layout = "list"), comb)
    expect_equal(icomb$getnext(layout = "list"), list(1:3))
    expect_equal(icomb$getnext(layout = "list"), list(c(1, 2, 4)))
    icomb$getnext(110, layout = "list")
    expect_equal(length(icomb$getnext(10, layout = "list")), 8)
    expect_equal(icomb$getnext(layout = "list"), NULL)

    icomb <- icombinations(10, 0)
    expect_equal(dim(icomb$collect()), c(1, 0))
    expect_equal(icomb$getnext(), integer(0))
    icomb <- icombinations(10, 11)
    expect_equal(dim(icomb$collect()), c(0, 11))
    expect_equal(icomb$getnext(), NULL)
    expect_error(icombinations(10, -1), "expect integer")
    expect_error(icombinations(10, 1.5), "expect integer")
})

test_that("Combinations - index", {
    expect_equal(combinations(5, 3, index = 1:10), combinations(5, 3))
    expect_equal(combinations(5, 3, index = as.numeric(1:10)), combinations(5, 3))
    expect_equal(combinations(5, 3, index = as.character(1:10)), combinations(5, 3))
    expect_equal(combinations(5, 3, index = gmp::as.bigz(1:10)), combinations(5, 3))
    expect_equal(combinations(5, 3, index = 2), c(1, 2, 4))
    expect_equal(combinations(5, 3, index = 10), c(3, 4, 5))
    expect_error(combinations(5, 3, index = -1), "invalid index")
    expect_error(combinations(5, 3, index = 1.5), "invalid index")
    expect_error(combinations(5, 3, index = "-1"), "invalid index")
    expect_error(combinations(5, 3, index = "1.5"), "invalid index")

    expect_equal(combinations(50, 30, index = 2), c(1:29, 31))
    expect_equal(combinations(50, 30, index = ncombinations(50, 30, bigz = TRUE)), 21:50)
    expect_error(combinations(50, 30, index = -1), "invalid index")
    expect_error(combinations(50, 30, index = 1.5), "invalid index")
    expect_error(combinations(50, 30, index = "-1"), "invalid index")
    expect_error(combinations(50, 30, index = "1.5"), "invalid index")

    expect_equal(combinations(5, 3, index = 1:10, layout = "row"), combinations(5, 3, layout = "row"))
    expect_equal(combinations(5, 3, index = as.numeric(1:10), layout = "row"), combinations(5, 3, layout = "row"))
    expect_equal(combinations(5, 3, index = as.character(1:10), layout = "row"), combinations(5, 3, layout = "row"))
    expect_equal(combinations(5, 3, index = gmp::as.bigz(1:10), layout = "row"), combinations(5, 3, layout = "row"))
    expect_equal(combinations(5, 3, index = 2, layout = "row")[1, ], c(1, 2, 4))
    expect_equal(combinations(5, 3, index = 10, layout = "row")[1, ], c(3, 4, 5))
    expect_equal(combinations(50, 30, index = 2, layout = "row")[1, ], c(1:29, 31))

    expect_equal(combinations(5, 3, index = 1:10, layout = "column"), combinations(5, 3, layout = "column"))
    expect_equal(combinations(5, 3, index = as.numeric(1:10), layout = "column"), combinations(5, 3, layout = "column"))
    expect_equal(combinations(5, 3, index = as.character(1:10), layout = "column"), combinations(5, 3, layout = "column"))
    expect_equal(combinations(5, 3, index = gmp::as.bigz(1:10), layout = "column"), combinations(5, 3, layout = "column"))
    expect_equal(combinations(5, 3, index = 2, layout = "column")[, 1], c(1, 2, 4))
    expect_equal(combinations(5, 3, index = 10, layout = "column")[, 1], c(3, 4, 5))
    expect_equal(combinations(50, 30, index = 2, layout = "column")[, 1], c(1:29, 31))

    expect_equal(combinations(5, 3, index = 1:10, layout = "list"), combinations(5, 3, layout = "list"))
    expect_equal(combinations(5, 3, index = as.numeric(1:10), layout = "list"), combinations(5, 3, layout = "list"))
    expect_equal(combinations(5, 3, index = as.character(1:10), layout = "list"), combinations(5, 3, layout = "list"))
    expect_equal(combinations(5, 3, index = gmp::as.bigz(1:10), layout = "list"), combinations(5, 3, layout = "list"))
    expect_equal(combinations(5, 3, index = 2, layout = "list"), list(c(1, 2, 4)))
    expect_equal(combinations(5, 3, index = 10, layout = "list"), list(c(3, 4, 5)))
    expect_equal(combinations(50, 30, index = 2, layout = "list"), list(c(1:29, 31)))

    expect_error(combinations(0, 1, index = 1), "invalid index")
    expect_equal(combinations(0, 0, index = 1), integer(0))
    expect_error(combinations(0, 1, index = gmp::as.bigz(1)), "invalid index")
    expect_equal(combinations(0, 0, index = gmp::as.bigz(1)), integer(0))
})

test_that("Combinations - skip", {
    expect_equal(combinations(5, 3, skip = 10), combinations(5, 3))
    expect_equal(combinations(5, 3, skip = 3), combinations(5, 3)[4:10, ])
    expect_equal(combinations(5, 3, skip = 3, nitem = 4), combinations(5, 3)[4:7, ])
    expect_equal(combinations(5, 3, skip = gmp::as.bigz(3), nitem = 4), combinations(5, 3)[4:7, ])
})


test_that("Combinations - small cases", {
    expect_equal(combinations(0), matrix(0, nr = 1, nc = 0))
    expect_equal(combinations(0, 1), matrix(0, nr = 0, nc = 1))
    expect_equal(combinations(1), matrix(1, nr = 1, nc = 1))
    expect_equal(combinations(1, 0), matrix(1, nr = 1, nc = 0))

    icomb <- icombinations(0, 0)
    expect_equal(icomb$getnext(), integer(0))
    expect_equal(icomb$getnext(), NULL)

    icomb <- icombinations(0, 1)
    expect_equal(icomb$getnext(), NULL)
    expect_equal(icomb$getnext(), NULL)

    icomb <- icombinations(1, 1)
    expect_equal(icomb$getnext(), 1)
    expect_equal(icomb$getnext(), NULL)

    icomb <- icombinations(1, 0)
    expect_equal(icomb$getnext(), integer(0))
    expect_equal(icomb$getnext(), NULL)
})
