test_that("kbest: k=1 equals single best", {
  set.seed(1)
  for (n in 2:6) {
    M <- matrix(runif(n*n), n)
    a1 <- assignment(M, method = "jv")
    kb <- kbest_assignment(M, k = 1, method = "murty")
    expect_equal(kb$cost_total[1], a1$total_cost, tolerance = 1e-10)
    # reconstruct row->col from kb row 1
    col_by_row <- kb$col[kb$rank == 1][order(kb$row[kb$rank == 1])]
    expect_equal(col_by_row, a1$match)
  }
})

test_that("kbest: totals are non-decreasing by rank", {
  set.seed(2)
  n <- 4
  M <- matrix(runif(n*n), n)
  kb <- kbest_assignment(M, k = 5)
  by_rank <- tapply(kb$cost_total, kb$rank, function(v) unique(v))
  by_rank <- as.numeric(by_rank)
  expect_true(all(diff(by_rank) >= -1e-12))
})

test_that("kbest: handles NA, rectangular, and maximize", {
  set.seed(3)
  M <- matrix(runif(4*6), 4, 6)
  M[sample.int(length(M), 6)] <- NA
  # ensure feasibility
  for (i in 1:4) if (all(is.na(M[i,]))) M[i, sample.int(6,1)] <- runif(1)

  kb1 <- kbest_assignment(M, k = 3, maximize = FALSE)
  kb2 <- kbest_assignment(M, k = 3, maximize = TRUE)
  expect_equal(nrow(kb1), 3*4)
  expect_equal(nrow(kb2), 3*4)
  # k=1 should match assignment()
  a1 <- assignment(M, method = "jv")
  first_cols <- kb1$col[kb1$rank==1][order(kb1$row[kb1$rank==1])]
  expect_equal(first_cols, a1$match)
})
