# Tests for specific uncovered lines to reach 100% test coverage # See comments for exact line numbers being tested # Test 1: R/plot-htna.R lines 150-151 - Matrix input path test_that("plot_htna works with matrix input", { trans_mat <- matrix(c( 0.7, 0.2, 0.1, 0.1, 0.6, 0.3, 0.3, 0.1, 0.6 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C") with_temp_png({ plot_htna(trans_mat, node_list = list(g1 = c("A", "B"), g2 = c("C"))) }) }) test_that("plot_htna with matrix without colnames", { trans_mat <- matrix(c( 0.7, 0.2, 0.1, 0.1, 0.6, 0.3, 0.3, 0.1, 0.6 ), nrow = 3, byrow = TRUE) # Matrix without colnames will get auto-generated names "1", "2", "3" # Test with character group names matching auto-generated names with_temp_png({ plot_htna(trans_mat, node_list = list(g1 = c("1", "2"), g2 = c("3"))) }) }) # Test 2: R/plot-htna.R line 200 - Circular layout with < 2 groups # Line 200 checks for circular layout specifically needing at least 2 groups # But line 139 already checks for 2+ groups in general, so line 200 is unreachable # with current code structure. The circular layout validation would only trigger # if bipartite/polygon validations weren't there. Let's test the working circular layout instead. test_that("plot_htna works with circular layout", { trans_mat <- matrix(c( 0.7, 0.2, 0.1, 0.1, 0.6, 0.3, 0.3, 0.1, 0.6 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C") # Test circular layout with 2 groups with_temp_png({ plot_htna(trans_mat, node_list = list(g1 = c("A", "B"), g2 = c("C")), layout = "circular") }) }) # Test 3: R/plot-htna.R line 439 - shape_to_pch mapping in legend test_that("plot_htna legend handles non-standard shapes", { trans_mat <- matrix(c( 0.7, 0.2, 0.1, 0.1, 0.6, 0.3, 0.3, 0.1, 0.6 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C") # Use shapes that will trigger the 'else 21' path in line 439 # "ellipse" is not in the standard shape_to_pch mapping with_temp_png({ plot_htna(trans_mat, node_list = list(g1 = c("A"), g2 = c("B"), g3 = c("C")), group_shapes = c("ellipse", "pentagon", "hexagon"), legend = TRUE) }) }) # Test 4: R/plot-htna.R line 643 - outward vector flipping test_that("plot_htna polygon layout with outward vector flip", { # 4-state network, 4 groups in polygon layout to trigger line 643 trans_mat <- matrix(0.1, nrow = 4, ncol = 4) diag(trans_mat) <- 0.7 colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C", "D") with_temp_png({ plot_htna(trans_mat, node_list = list(g1 = c("A"), g2 = c("B"), g3 = c("C"), g4 = c("D")), layout = "polygon") }) }) # Test 5: R/plot-htna-multi.R line 360 - negative angle normalization test_that("plot_mtna handles triangle shape with negative angles", { skip_if_not_installed("tna") # 3-group network to get triangle shape trans_mat <- matrix(c( 0, 0.3, 0.1, 0.2, 0, 0.3, 0.1, 0.2, 0 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C") tna_obj <- tna::tna(trans_mat) with_temp_png({ plot_mtna(tna_obj, cluster_list = list(g1 = c("A"), g2 = c("B"), g3 = c("C"))) }) }) # Test 6: R/plot-htna-multi.R lines 399, 402 - triangle edge_center paths test_that("plot_mtna triangle edge_center calculation for different angles", { skip_if_not_installed("tna") trans_mat <- matrix(c( 0.5, 0.2, 0.3, 0.3, 0.4, 0.3, 0.2, 0.3, 0.5 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("X", "Y", "Z") tna_obj <- tna::tna(trans_mat) with_temp_png({ plot_mtna(tna_obj, cluster_list = list(top = c("X"), left = c("Y"), right = c("Z")), node_size = 15) }) }) # Test 7: R/plot-htna-multi.R lines 466-467 - zero-length edge offset test_that("plot_mtna handles self-loops (zero-length edges)", { skip_if_not_installed("tna") trans_mat <- matrix(c( 0.5, 0.3, 0.2, 0.2, 0.6, 0.2, 0.3, 0.1, 0.6 ), nrow = 3, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C") tna_obj <- tna::tna(trans_mat) with_temp_png({ plot_mtna(tna_obj, cluster_list = list(g1 = c("A", "B"), g2 = c("C"))) }) }) # Test 8: R/plot-htna-multi.R line 598 - max_within == 0 fallback width test_that("plot_mtna with groups having zero within-group weights", { skip_if_not_installed("tna") # Matrix where within-group transitions are 0 trans_mat <- matrix(c( 0, 0, 0.5, 0.5, 0, 0, 0.5, 0.5, 0.5, 0.5, 0, 0, 0.5, 0.5, 0, 0 ), nrow = 4, byrow = TRUE) colnames(trans_mat) <- rownames(trans_mat) <- c("A", "B", "C", "D") tna_obj <- tna::tna(trans_mat) with_temp_png({ plot_mtna(tna_obj, cluster_list = list(g1 = c("A", "B"), g2 = c("C", "D"))) }) }) # Test 9: R/from-qgraph.R lines 21, 27, 33, 39 - RColorBrewer/colorspace fallbacks # These lines have fallback logic when RColorBrewer/colorspace are not available # Test by calling the color palette function which uses these fallbacks test_that("tna_color_palette works with different state counts", { skip_if_not_installed("tna") # Test different state counts to exercise all switch branches # This will hit the appropriate fallback lines if packages aren't available colors_2 <- cograph:::tna_color_palette(2) expect_length(colors_2, 2) expect_true(is.character(colors_2)) colors_8 <- cograph:::tna_color_palette(8) expect_length(colors_8, 8) colors_12 <- cograph:::tna_color_palette(12) expect_length(colors_12, 12) colors_15 <- cograph:::tna_color_palette(15) expect_length(colors_15, 15) }) test_that("tna_color_palette returns valid colors", { skip_if_not_installed("tna") # Test that colors are valid regardless of which branch is taken colors <- cograph:::tna_color_palette(5) expect_length(colors, 5) # Verify all colors are valid for (col in colors) { expect_no_error(grDevices::col2rgb(col)) } }) # Test 10: R/input-statnet.R line 39 - fallback labels # This tests the path where network.vertex.names returns NULL or all NA # The network package typically returns defaults, but our code has a fallback test_that("parse_statnet handles basic network correctly", { skip_if_not_installed("network") # Create a basic network - this will exercise the parse_statnet function net <- network::network.initialize(3, directed = FALSE) network::add.edges(net, tail = c(1, 2), head = c(2, 3)) result <- cograph:::parse_statnet(net) expect_equal(nrow(result$nodes), 3) expect_true(all(as.character(result$nodes$label) %in% c("1", "2", "3"))) expect_true(is.data.frame(result$nodes)) expect_true(is.data.frame(result$edges)) }) test_that("parse_statnet handles networks with custom vertex names", { skip_if_not_installed("network") # Create network with custom names net <- network::network.initialize(3, directed = FALSE) network::add.edges(net, tail = c(1, 2), head = c(2, 3)) network::set.vertex.attribute(net, "vertex.names", c("A", "B", "C")) result <- cograph:::parse_statnet(net) expect_equal(as.character(result$nodes$label), c("A", "B", "C")) })