context("Combinations with replacement")

test_that("combinations with replacement - ncombinations", {
    L = c(LETTERS, letters)
    expect_equal(ncombinations(8, 3, replace = TRUE), 120)
    expect_equal(ncombinations(x = LETTERS[1:8], k = 3, replace = TRUE), 120)
    expect_error(ncombinations(40, 10, replace = TRUE), "integer overflow")
    expect_error(ncombinations(x = L[1:40], k = 10, replace = TRUE), "integer overflow")
    expect_equal(ncombinations(40, 10, replace = TRUE, bigz = TRUE), gmp::as.bigz("8217822536"))
    expect_equal(ncombinations(8, 0, replace = TRUE), 1)
    expect_equal(ncombinations(4, 5, replace = TRUE), 56)
    expect_error(ncombinations(6, -1, replace = TRUE), "expect integer")
    expect_error(ncombinations(6, 1.5, replace = TRUE), "expect integer")

    expect_equal(ncombinations(0, 0, replace = TRUE), 1)
    expect_equal(ncombinations(0, 1, replace = TRUE), 0)
})

test_that("Combinations with replacement - combinations", {
    comb <- combinations(8, 3, replace= TRUE)
    expect_equal(nrow(comb), 120)
    expect_equal(ncol(comb), 3)
    expect_equal(comb[1, ], rep(1, 3))
    expect_equal(comb[120, ], rep(8, 3))

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

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

    comb <- combinations(8, 3, replace= TRUE, layout = "list")
    expect_equal(length(comb), 120)
    expect_equal(comb[[1]], rep(1, 3))
    expect_equal(comb[[120]], rep(8, 3))

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

    expect_error(combinations(40, 10, replace = TRUE), "too many results")
    expect_error(combinations(5, -1, replace= TRUE), "expect integer")
    expect_error(combinations(5, 1.5, replace= TRUE), "expect integer")
    expect_equal(dim(combinations(8, 0, replace= TRUE)), c(1, 0))
    expect_equal(dim(combinations(4, 5, replace= TRUE)), c(56, 5))
    expect_equal(dim(combinations(0, 0, replace= TRUE)), c(1, 0))
    expect_equal(dim(combinations(0, 1, replace= TRUE)), c(0, 1))
})

test_that("Combinations with replacement - icombinations", {
    icomb <- icombinations(8, 3, replace= TRUE)
    perm <- combinations(8, 3, replace= TRUE)
    expect_equal(icomb$collect(), perm)
    expect_equal(icomb$getnext(), rep(1, 3))
    expect_equal(icomb$getnext(), c(1, 1, 2))
    icomb$getnext(110)
    expect_equal(nrow(icomb$getnext(10)), 8)
    expect_equal(icomb$getnext(), NULL)

    perm <- combinations(8, 3, replace= TRUE, layout = "row")
    expect_equal(icomb$collect(layout = "row"), perm)
    expect_equal(icomb$getnext(layout = "row"), t(rep(1, 3)))
    expect_equal(icomb$getnext(layout = "row"), t(c(1, 1, 2)))
    icomb$getnext(110, layout = "row")
    expect_equal(nrow(icomb$getnext(10, layout = "row")), 8)
    expect_equal(icomb$getnext(layout = "row"), NULL)

    perm <- combinations(8, 3, replace= TRUE, layout = "column")
    expect_equal(icomb$collect(layout = "column"), perm)
    expect_equal(icomb$getnext(layout = "column"), t(t(rep(1, 3))))
    expect_equal(icomb$getnext(layout = "column"), t(t(c(1, 1, 2))))
    icomb$getnext(110, layout = "column")
    expect_equal(ncol(icomb$getnext(10, layout = "column")), 8)
    expect_equal(icomb$getnext(layout = "column"), NULL)

    perm <- combinations(8, 3, replace= TRUE, layout = "list")
    expect_equal(icomb$collect(layout = "list"), perm)
    expect_equal(icomb$getnext(layout = "list"), list(rep(1, 3)))
    expect_equal(icomb$getnext(layout = "list"), list(c(1, 1, 2)))
    icomb$getnext(110, layout = "list")
    expect_equal(length(icomb$getnext(10, layout = "list")), 8)
    expect_equal(icomb$getnext(layout = "list"), NULL)

    icomb <- icombinations(8, 0, replace= TRUE)
    expect_equal(dim(icomb$collect()), c(1, 0))
    expect_equal(icomb$getnext(), integer(0))
    icomb <- icombinations(4, 5, replace= TRUE)
    expect_equal(nrow(icomb$collect()), 56)
    expect_error(icombinations(5, -1, replace= TRUE), "expect integer")
    expect_error(icombinations(5, 1.5, replace= TRUE), "expect integer")
})

test_that("Combinations with replacement - index", {
    comb <- combinations(5, 3, replace = TRUE)
    expect_equal(combinations(5, 3, replace = TRUE, index = 1:35), comb)
    expect_equal(combinations(5, 3, replace = TRUE, index = as.numeric(1:35)), comb)
    expect_equal(combinations(5, 3, replace = TRUE, index = as.character(1:35)), comb)
    expect_equal(combinations(5, 3, replace = TRUE, index = gmp::as.bigz(1:35)), comb)
    expect_equal(combinations(5, 3, replace = TRUE, index = 2), c(1, 1, 2))
    expect_equal(combinations(5, 3, replace = TRUE, index = 35), rep(5, 3))
    expect_equal(combinations(40, 10, replace = TRUE, index = 2), c(rep(1, 9), 2))
    expect_equal(combinations(40, 10, replace = TRUE, index = "8217822536"), rep(40, 10))

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

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