test_that("csflow == ssp on small squares", {
  set.seed(1)
  for (n in 2:7) {
    M <- matrix(runif(n*n), n)
    a <- assignment(M, method = "ssp")
    c <- assignment(M, method = "csflow")
    expect_equal(a$total_cost, c$total_cost, tolerance = 1e-10)
  }
})

test_that("csflow handles rectangles and NA", {
  set.seed(2)
  n <- 5; m <- 9
  M <- matrix(runif(n*m), n, m)
  M[sample.int(length(M), size = 8)] <- NA
  a <- assignment(M, method = "ssp")
  c <- assignment(M, method = "csflow")
  expect_equal(a$total_cost, c$total_cost, tolerance = 1e-10)
})

test_that("csflow works when m < n (auto-transpose)", {
  set.seed(3)
  n <- 9; m <- 5
  M <- matrix(runif(n*m), n, m)
  a <- assignment(M, method = "ssp")
  c <- assignment(M, method = "csflow")
  expect_equal(a$total_cost, c$total_cost, tolerance = 1e-10)
})

test_that("csflow errors when a row is entirely forbidden", {
  M <- matrix(1, 3, 5)
  M[1,] <- NA
  expect_error(assignment(M, method = "csflow"), "Infeasible")
})

test_that("maximize works for csflow", {
  set.seed(4)
  n <- 6
  M <- matrix(runif(n*n), n)
  a <- assignment(M, maximize = TRUE,  method = "csflow")
  b <- assignment(-M, maximize = FALSE, method = "csflow")
  expect_equal(a$total_cost, -b$total_cost, tolerance = 1e-10)
})

test_that("csflow matches ssp on larger sparse rectangular", {
  testthat::skip_on_cran()
  set.seed(5)
  n <- 80; m <- 150
  M <- matrix(Inf, n, m)
  # ~5% density with finite costs
  nz <- ceiling(0.05 * length(M))
  idx <- sample.int(length(M), nz)
  M[idx] <- runif(nz)
  # ensure feasibility: give each row at least one finite entry
  for (i in 1:n) {
    if (all(!is.finite(M[i,]))) {
      j <- sample.int(m, 1)
      M[i, j] <- runif(1)
    }
  }
  a <- assignment(M, method = "ssp")
  c <- assignment(M, method = "csflow")
  expect_equal(a$total_cost, c$total_cost, tolerance = 1e-8)
})
