test_that("find_cycle() works", { g <- make_graph(c(1, 2, 2, 3, 1, 3, 1, 1), directed = TRUE) cycle <- find_cycle(g) expect_equal(length(cycle$vertices), 1) expect_equal(length(cycle$edges), 1) # Finding a cycle of length 1 or 3 are both valid here cycle <- find_cycle(g, mode = "all") expect_equal(length(cycle$vertices), 3) expect_equal(length(cycle$edges), 3) }) test_that("simple_cycle() works directed", { g <- graph_from_literal(A -+ B -+ C -+ A -+ D -+ E +- F -+ A, E -+ E, A -+ F, simplify = FALSE) all_simple_cycles <- simple_cycles(g) expect_length(all_simple_cycles$vertices, 3) expect_length(all_simple_cycles$edges, 3) true_length <- list(vertices = c(3, 2, 1), edges = c(3, 2, 1)) for (i in 1:3) { expect_length(all_simple_cycles$vertices[[i]], true_length$vertices[[i]]) expect_length(all_simple_cycles$edges[[i]], true_length$edges[[i]]) } expect_equal(as.numeric(all_simple_cycles$vertices[[1]]), 1:3) }) test_that("simple_cycle() works undirected", { g <- graph_from_literal(A -+ B -+ C -+ A -+ D -+ E +- F -+ A, E -+ E, A -+ F, simplify = FALSE) all_simple_cycles <- simple_cycles(g, mode = "all") expect_length(all_simple_cycles$vertices, 5) expect_length(all_simple_cycles$edges, 5) true_length <- list(vertices = c(3, 4, 4, 2, 1), edges = c(3, 4, 4, 2, 1)) for (i in 1:5) { expect_length(all_simple_cycles$vertices[[i]], true_length$vertices[[i]]) expect_length(all_simple_cycles$edges[[i]], true_length$edges[[i]]) } expect_equal(as.numeric(all_simple_cycles$vertices[[2]]), c(1, 4, 5, 6)) all_simple_cycles_23 <- simple_cycles(g, mode = "all", min = 2, max = 3) expect_length(all_simple_cycles$vertices, 5) expect_length(all_simple_cycles$edges, 5) }) # Tests for callback function test_that("simple_cycles_callback works", { withr::local_seed(123) g <- graph_from_literal(A -+ B -+ C -+ A -+ D -+ E +- F -+ A) # Count cycles using callback count <- 0 cycle_lengths <- integer(0) simple_cycles(g, callback = function(vertices, edges) { count <<- count + 1 cycle_lengths <<- c(cycle_lengths, length(vertices)) TRUE # continue search }) expect_true(count > 0) expect_true(all(cycle_lengths >= 1)) }) test_that("simple_cycles_callback can stop early", { withr::local_seed(123) g <- graph_from_literal(A -+ B -+ C -+ A -+ D -+ E -+ D) # Stop after finding 2 cycles count <- 0 simple_cycles(g, callback = function(vertices, edges) { count <<- count + 1 if (count >= 2) { TRUE # stop after 2 cycles } else { FALSE # continue } }) expect_equal(count, 2) }) test_that("simple_cycles_callback receives correct arguments", { g <- make_ring(5, directed = TRUE) # Check argument types simple_cycles(g, callback = function(vertices, edges) { expect_true(is.integer(vertices)) expect_true(is.integer(edges)) expect_equal(length(vertices), length(edges)) expect_true(length(vertices) >= 1) FALSE # stop after first cycle }) }) test_that("simple_cycles_callback handles errors in callback", { g <- make_ring(5, directed = TRUE) # Callback that throws an error expect_error( simple_cycles(g, callback = function(vertices, edges) { stop("Intentional error in callback") }), "Error in R callback function" ) })