tests/testthat/test-od-matrix.R

# Tests for melt_od_matrix()

# --- Basic Functionality Tests ---

test_that("melt_od_matrix returns data.frame with correct columns", {
  od_mat <- matrix(c(0, 10, 20, 30), nrow = 2)

  result <- melt_od_matrix(od_mat)

  expect_true(is.data.frame(result))
  expect_true(all(c("from", "to", "flow") %in% names(result)))
})

test_that("melt_od_matrix filters zero flows", {
  od_mat <- matrix(c(0, 10, 0, 30), nrow = 2)

  result <- melt_od_matrix(od_mat)

  # Only non-zero values should remain
  expect_true(all(result$flow > 0))
  expect_equal(nrow(result), 2)  # Only 10 and 30
})

test_that("melt_od_matrix filters non-finite flows", {
  od_mat <- matrix(c(NA, 10, Inf, 30), nrow = 2)

  result <- melt_od_matrix(od_mat)

  # Only finite values should remain
  expect_true(all(is.finite(result$flow)))
  expect_equal(nrow(result), 2)  # Only 10 and 30
})

test_that("melt_od_matrix uses dimnames when nodes not provided", {
  od_mat <- matrix(c(0, 10, 20, 0), nrow = 2)
  dimnames(od_mat) <- list(c("100", "200"), c("100", "200"))

  result <- melt_od_matrix(od_mat)

  # Should use dimnames as node IDs (coerced to integer)
  expect_true(all(result$from %in% c(100, 200)))
  expect_true(all(result$to %in% c(100, 200)))
})

test_that("melt_od_matrix uses sequential IDs when no dimnames", {
  od_mat <- matrix(c(0, 10, 20, 0), nrow = 2)

  result <- melt_od_matrix(od_mat)

  # Should use 1:n as node IDs
  expect_true(all(result$from %in% 1:2))
  expect_true(all(result$to %in% 1:2))
})

test_that("melt_od_matrix uses nodes argument when provided", {
  od_mat <- matrix(c(0, 10, 20, 0), nrow = 2)
  node_ids <- c(50, 60)

  result <- melt_od_matrix(od_mat, nodes = node_ids)

  expect_true(all(result$from %in% node_ids))
  expect_true(all(result$to %in% node_ids))
})

test_that("melt_od_matrix nodes argument overrides dimnames", {
  od_mat <- matrix(c(0, 10, 20, 0), nrow = 2)
  dimnames(od_mat) <- list(c("100", "200"), c("100", "200"))
  node_ids <- c(50, 60)

  result <- melt_od_matrix(od_mat, nodes = node_ids)

  # Should use nodes, not dimnames
  expect_true(all(result$from %in% node_ids))
  expect_false(any(result$from %in% c(100, 200)))
})

test_that("melt_od_matrix sort=TRUE orders by from, to", {
  od_mat <- matrix(1:4, nrow = 2)
  dimnames(od_mat) <- list(c("2", "1"), c("2", "1"))

  result <- melt_od_matrix(od_mat, sort = TRUE)

  # Should be sorted by from, then to
  expected_order <- order(result$from, result$to)
  expect_equal(seq_len(nrow(result)), expected_order)
})

test_that("melt_od_matrix sort=FALSE preserves original order", {
  od_mat <- matrix(1:4, nrow = 2)

  result_sorted <- melt_od_matrix(od_mat, sort = TRUE)
  result_unsorted <- melt_od_matrix(od_mat, sort = FALSE)

  # Both should have same content but potentially different order
  expect_equal(sort(result_sorted$flow), sort(result_unsorted$flow))
})

# --- Edge Cases ---

test_that("melt_od_matrix handles 1x1 matrix", {
  od_mat <- matrix(5, nrow = 1)

  result <- melt_od_matrix(od_mat)

  expect_equal(nrow(result), 1)
  expect_equal(result$flow, 5)
})

test_that("melt_od_matrix handles all-zero matrix", {
  od_mat <- matrix(0, nrow = 3, ncol = 3)

  result <- melt_od_matrix(od_mat)

  expect_equal(nrow(result), 0)
})

test_that("melt_od_matrix handles non-square matrix", {
  od_mat <- matrix(1:6, nrow = 2, ncol = 3)

  result <- melt_od_matrix(od_mat)

  expect_equal(nrow(result), 6)  # All positive values
})

test_that("melt_od_matrix handles large values", {
  od_mat <- matrix(c(0, 1e12, 1e12, 0), nrow = 2)

  result <- melt_od_matrix(od_mat)

  expect_equal(result$flow, c(1e12, 1e12))
})

test_that("melt_od_matrix handles small positive values", {
  od_mat <- matrix(c(0, 1e-10, 1e-10, 0), nrow = 2)

  result <- melt_od_matrix(od_mat)

  expect_equal(nrow(result), 2)
  expect_true(all(result$flow > 0))
})

# --- Error Handling Tests ---

test_that("melt_od_matrix errors on non-matrix input", {
  expect_error(melt_od_matrix(data.frame(a = 1:3)), "matrix")
  expect_error(melt_od_matrix(c(1, 2, 3)), "matrix")
  expect_error(melt_od_matrix(list(a = 1)), "matrix")
})

test_that("melt_od_matrix errors on non-numeric matrix", {
  char_mat <- matrix(c("a", "b", "c", "d"), nrow = 2)

  expect_error(melt_od_matrix(char_mat), "numeric")
})

test_that("melt_od_matrix errors on mismatched nodes length (rows)", {
  od_mat <- matrix(1:4, nrow = 2)
  nodes <- c(1, 2, 3)  # Wrong length

  expect_error(melt_od_matrix(od_mat, nodes = nodes), "rows")
})

test_that("melt_od_matrix errors on mismatched nodes length (cols)", {
  od_mat <- matrix(1:6, nrow = 2, ncol = 3)
  nodes <- c(1, 2)  # Matches rows but not cols

  expect_error(melt_od_matrix(od_mat, nodes = nodes), "columns")
})

test_that("melt_od_matrix errors when dimnames don't match with nodes", {
  od_mat <- matrix(1:4, nrow = 2)
  dimnames(od_mat) <- list(c("a", "b"), c("c", "d"))  # Different row/col names
  nodes <- c(1, 2)

  expect_error(melt_od_matrix(od_mat, nodes = nodes), "match")
})

# --- Integration with run_assignment() ---

test_that("melt_od_matrix output works with run_assignment", {
  # Create simple OD matrix
  od_mat <- matrix(c(0, 100, 80, 0), nrow = 2)
  dimnames(od_mat) <- list(c("1", "3"), c("1", "3"))

  # Simple graph
  graph <- data.frame(
    from = c(1, 2),
    to = c(2, 3),
    cost = c(1, 1)
  )

  # Melt and use
  od_long <- melt_od_matrix(od_mat)

  result <- run_assignment(graph, od_long,
                           cost.column = "cost",
                           method = "AoN",
                           verbose = FALSE)

  expect_s3_class(result, "flownet")
  expect_true(sum(result$final_flows) > 0)
})

Try the flownet package in your browser

Any scripts or data that you put into this service are public.

flownet documentation built on March 22, 2026, 9:06 a.m.