Nothing
# test-coverage-input-qgraph-41.R - Comprehensive Tests for input-qgraph.R
# Targets all code paths in R/input-qgraph.R for full coverage
# =============================================================================
# SETUP: Access internal functions
# =============================================================================
skip_on_cran()
parse_qgraph <- cograph:::parse_qgraph
create_nodes_df <- cograph:::create_nodes_df
create_edges_df <- cograph:::create_edges_df
# =============================================================================
# SECTION 1: Basic parse_qgraph() functionality
# =============================================================================
test_that("parse_qgraph requires qgraph package", {
# We'll just check that the function exists and works when qgraph is present
skip_if_not_installed("qgraph")
# Create a simple qgraph object
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_type(result, "list")
expect_true("nodes" %in% names(result))
expect_true("edges" %in% names(result))
expect_true("directed" %in% names(result))
expect_true("weights" %in% names(result))
})
test_that("parse_qgraph validates qgraph input", {
skip_if_not_installed("qgraph")
# Non-qgraph object without Arguments should fail
not_qgraph <- list(foo = 1, bar = 2)
expect_error(parse_qgraph(not_qgraph), "must be a qgraph object")
})
test_that("parse_qgraph accepts object with Arguments field", {
skip_if_not_installed("qgraph")
# Create mock object with Arguments (mimics qgraph structure)
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Verify it has Arguments
expect_true(!is.null(q$Arguments))
result <- parse_qgraph(q)
expect_type(result, "list")
})
# =============================================================================
# SECTION 2: Directed/undirected detection
# =============================================================================
test_that("parse_qgraph detects directed from Edgelist$directed", {
skip_if_not_installed("qgraph")
# Asymmetric (directed) matrix
adj <- matrix(c(0, 1, 0, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = TRUE)
result <- parse_qgraph(q)
expect_true(result$directed)
})
test_that("parse_qgraph detects undirected from symmetric matrix", {
skip_if_not_installed("qgraph")
# Symmetric matrix
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = FALSE)
result <- parse_qgraph(q)
expect_false(result$directed)
})
test_that("parse_qgraph respects forced directed parameter", {
skip_if_not_installed("qgraph")
# Symmetric matrix but force directed
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q, directed = TRUE)
expect_true(result$directed)
result2 <- parse_qgraph(q, directed = FALSE)
expect_false(result2$directed)
})
test_that("parse_qgraph falls back to matrix symmetry when no directed info", {
skip_if_not_installed("qgraph")
# Create qgraph and remove directed field from Edgelist
adj <- matrix(c(0, 0.5, 0.3, 0.5, 0, 0.8, 0.3, 0.8, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Manually remove directed from Edgelist to test fallback
q_modified <- q
q_modified$Edgelist$directed <- NULL
result <- parse_qgraph(q_modified)
# Symmetric matrix should be undirected
expect_false(result$directed)
})
test_that("parse_qgraph defaults to FALSE when no matrix to check symmetry", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove both directed field and input matrix
q_modified <- q
q_modified$Edgelist$directed <- NULL
q_modified$Arguments$input <- NULL
result <- parse_qgraph(q_modified)
expect_false(result$directed)
})
# =============================================================================
# SECTION 3: Node information extraction
# =============================================================================
test_that("parse_qgraph extracts node names from graphAttributes", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
rownames(adj) <- colnames(adj) <- c("NodeA", "NodeB")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# qgraph may store names as labels or truncate - check nodes are present
expect_equal(nrow(result$nodes), 2)
expect_true(all(!is.na(result$nodes$label)))
})
test_that("parse_qgraph extracts labels when available", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, labels = c("X", "Y"))
result <- parse_qgraph(q)
expect_true(is.data.frame(result$nodes))
expect_equal(nrow(result$nodes), 2)
})
test_that("parse_qgraph infers n from input matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove names/labels to force inference from matrix
q_modified <- q
q_modified$graphAttributes$Nodes$names <- NULL
q_modified$graphAttributes$Nodes$labels <- NULL
result <- parse_qgraph(q_modified)
expect_equal(nrow(result$nodes), 3)
})
test_that("parse_qgraph infers n from edge list when no matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove names, labels, and input matrix
q_modified <- q
q_modified$graphAttributes$Nodes$names <- NULL
q_modified$graphAttributes$Nodes$labels <- NULL
q_modified$Arguments$input <- NULL
result <- parse_qgraph(q_modified)
# n should be inferred from max(from, to) in edge list
expect_true(nrow(result$nodes) >= 1)
})
# =============================================================================
# SECTION 4: Edge extraction
# =============================================================================
test_that("parse_qgraph handles empty edge list", {
skip_if_not_installed("qgraph")
# Empty network (no edges)
adj <- matrix(0, 3, 3)
rownames(adj) <- colnames(adj) <- c("A", "B", "C")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_equal(nrow(result$edges), 0)
expect_equal(length(result$weights), 0)
})
test_that("parse_qgraph extracts edge weights", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 0.5, 0.3, 0.5, 0, 0.8, 0.3, 0.8, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(all(result$weights > 0))
expect_true(all(result$edges$weight > 0))
})
test_that("parse_qgraph handles edges without weight field", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove weight field from Edgelist
q_modified <- q
q_modified$Edgelist$weight <- NULL
result <- parse_qgraph(q_modified)
# Should default to weight = 1
expect_true(all(result$edges$weight == 1))
})
test_that("parse_qgraph extracts correct from/to indices", {
skip_if_not_installed("qgraph")
# Specific directed network
adj <- matrix(c(0, 1, 0, 0, 0, 1, 0, 0, 0), 3, 3, byrow = TRUE)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = TRUE)
result <- parse_qgraph(q)
# Should have 2 edges: 1->2 and 2->3
expect_equal(nrow(result$edges), 2)
})
# =============================================================================
# SECTION 5: NULL Edgelist handling
# =============================================================================
test_that("parse_qgraph handles NULL Edgelist", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Set Edgelist to NULL
q_modified <- q
q_modified$Edgelist <- NULL
result <- parse_qgraph(q_modified)
# Should handle gracefully with empty edges
expect_equal(nrow(result$edges), 0)
expect_equal(length(result$weights), 0)
})
test_that("parse_qgraph handles Edgelist with empty from", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Set from to empty
q_modified <- q
q_modified$Edgelist$from <- integer(0)
q_modified$Edgelist$to <- integer(0)
q_modified$Edgelist$weight <- numeric(0)
result <- parse_qgraph(q_modified)
expect_equal(nrow(result$edges), 0)
})
# =============================================================================
# SECTION 6: Layout extraction
# =============================================================================
test_that("parse_qgraph handles layout extraction", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, layout = "circle")
result <- parse_qgraph(q)
# Layout should be in nodes (may be NA if conditions don't match)
expect_true("x" %in% names(result$nodes))
expect_true("y" %in% names(result$nodes))
})
test_that("parse_qgraph handles NULL layout", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove layout
q_modified <- q
q_modified$layout <- NULL
result <- parse_qgraph(q_modified)
# Should work without layout (x, y remain NA)
expect_true(is.data.frame(result$nodes))
})
test_that("parse_qgraph handles layout with wrong dimensions", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Set layout with wrong number of rows
q_modified <- q
q_modified$layout <- matrix(c(0, 0, 1, 1, 2, 2), nrow = 3, ncol = 2)
result <- parse_qgraph(q_modified)
# Should not crash - layout might not be copied
expect_true(is.data.frame(result$nodes))
})
# =============================================================================
# SECTION 7: Large networks
# =============================================================================
test_that("parse_qgraph handles larger networks", {
skip_if_not_installed("qgraph")
set.seed(123)
n <- 20
adj <- matrix(runif(n * n), n, n)
adj <- adj * (adj > 0.7) # Sparse
diag(adj) <- 0
rownames(adj) <- colnames(adj) <- paste0("N", 1:n)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$nodes) > 0)
expect_true(nrow(result$edges) >= 0)
})
# =============================================================================
# SECTION 8: Weighted networks
# =============================================================================
test_that("parse_qgraph preserves weight values", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 0.25, 0.75, 0.25, 0, 0.5, 0.75, 0.5, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# Weights should be preserved (at least present)
expect_true(length(result$weights) > 0)
expect_true(all(result$weights > 0 & result$weights <= 1))
})
test_that("parse_qgraph handles negative weights", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, -0.5, 0.3, -0.5, 0, -0.8, 0.3, -0.8, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(any(result$weights < 0))
})
# =============================================================================
# SECTION 9: Return structure validation
# =============================================================================
test_that("parse_qgraph returns correct list structure", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_type(result, "list")
expect_named(result, c("nodes", "edges", "directed", "weights"))
expect_s3_class(result$nodes, "data.frame")
expect_s3_class(result$edges, "data.frame")
expect_type(result$directed, "logical")
expect_type(result$weights, "double")
})
test_that("parse_qgraph nodes dataframe has correct structure", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
rownames(adj) <- colnames(adj) <- c("A", "B")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true("id" %in% names(result$nodes))
expect_true("label" %in% names(result$nodes))
expect_true("name" %in% names(result$nodes))
expect_true("x" %in% names(result$nodes))
expect_true("y" %in% names(result$nodes))
})
test_that("parse_qgraph edges dataframe has correct structure", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true("from" %in% names(result$edges))
expect_true("to" %in% names(result$edges))
expect_true("weight" %in% names(result$edges))
})
# =============================================================================
# SECTION 10: Edge cases - single node networks
# =============================================================================
test_that("parse_qgraph handles single node network", {
skip_if_not_installed("qgraph")
adj <- matrix(0, 1, 1)
rownames(adj) <- colnames(adj) <- "Solo"
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$nodes) >= 1)
expect_equal(nrow(result$edges), 0)
})
test_that("parse_qgraph handles single node with self-loop", {
skip_if_not_installed("qgraph")
adj <- matrix(0.5, 1, 1)
rownames(adj) <- colnames(adj) <- "Self"
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$nodes) >= 1)
# Self-loop might or might not be included depending on qgraph version
expect_true(nrow(result$edges) <= 1)
})
# =============================================================================
# SECTION 11: Bidirectional edges
# =============================================================================
test_that("parse_qgraph handles bidirectional edges correctly", {
skip_if_not_installed("qgraph")
# Asymmetric weights indicate directed
adj <- matrix(c(0, 0.3, 0.7, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = TRUE)
result <- parse_qgraph(q)
expect_true(result$directed)
expect_equal(nrow(result$edges), 2) # Two separate edges
})
# =============================================================================
# SECTION 12: Mixed qgraph configurations
# =============================================================================
test_that("parse_qgraph handles qgraph with custom layout matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
custom_layout <- matrix(c(0, 1, 0, 1), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, layout = custom_layout)
result <- parse_qgraph(q)
expect_true(is.data.frame(result$nodes))
expect_true(nrow(result$nodes) >= 1)
})
test_that("parse_qgraph handles qgraph with groups", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0), 4, 4)
groups <- list(GroupA = 1:2, GroupB = 3:4)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, groups = groups)
result <- parse_qgraph(q)
# Groups may affect how qgraph stores node info
expect_true(is.data.frame(result$nodes))
expect_true(nrow(result$nodes) >= 1)
})
# =============================================================================
# SECTION 13: Sparse networks
# =============================================================================
test_that("parse_qgraph handles sparse network", {
skip_if_not_installed("qgraph")
# Only one edge in a 5-node network
adj <- matrix(0, 5, 5)
adj[1, 2] <- 0.5
adj[2, 1] <- 0.5
rownames(adj) <- colnames(adj) <- LETTERS[1:5]
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$edges) >= 1)
})
# =============================================================================
# SECTION 14: Dense networks
# =============================================================================
test_that("parse_qgraph handles fully connected network", {
skip_if_not_installed("qgraph")
n <- 5
adj <- matrix(1, n, n)
diag(adj) <- 0
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# Should have edges
expect_true(nrow(result$edges) >= 1)
})
# =============================================================================
# SECTION 15: Numeric labels
# =============================================================================
test_that("parse_qgraph generates numeric labels when no names given", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3, 3)
# No dimnames
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Clear any automatically assigned names
q_modified <- q
q_modified$graphAttributes$Nodes$names <- NULL
q_modified$graphAttributes$Nodes$labels <- NULL
q_modified$Arguments$input <- adj # Keep matrix for n inference
result <- parse_qgraph(q_modified)
expect_equal(nrow(result$nodes), 3)
})
# =============================================================================
# SECTION 16: Integration with cograph
# =============================================================================
test_that("parse_qgraph output works with splot", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 0.5, 0.3, 0.5, 0, 0.8, 0.3, 0.8, 0), 3, 3)
rownames(adj) <- colnames(adj) <- c("A", "B", "C")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
parsed <- parse_qgraph(q)
# Use the parsed data to create a cograph_network
result <- safe_plot({
splot(adj)
})
expect_true(result$success, info = result$error)
})
# =============================================================================
# SECTION 17: Edge case - all zero weights
# =============================================================================
test_that("parse_qgraph handles all-zero matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(0, 3, 3)
rownames(adj) <- colnames(adj) <- c("A", "B", "C")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_equal(nrow(result$edges), 0)
})
# =============================================================================
# SECTION 18: Various matrix types
# =============================================================================
test_that("parse_qgraph handles integer matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(as.integer(c(0, 1, 2, 1, 0, 3, 2, 3, 0)), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$edges) > 0)
})
test_that("parse_qgraph handles very small weights", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1e-10, 1e-10, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(is.data.frame(result$nodes))
})
# =============================================================================
# SECTION 19: Multiple edges between same nodes
# =============================================================================
test_that("parse_qgraph extracts all unique edges", {
skip_if_not_installed("qgraph")
# Simple network to verify edge extraction
adj <- matrix(c(
0, 0.5, 0.3,
0.5, 0, 0.7,
0.3, 0.7, 0
), 3, 3, byrow = TRUE)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# For undirected, should have 3 unique edges
expect_true(nrow(result$edges) >= 3)
})
# =============================================================================
# SECTION 20: Asymmetric input forcing direction check
# =============================================================================
test_that("parse_qgraph detects asymmetric matrix as directed via isSymmetric", {
skip_if_not_installed("qgraph")
# Clearly asymmetric
adj <- matrix(c(0, 1, 0, 0, 0, 1, 0, 0, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove directed field to force isSymmetric check
q_modified <- q
q_modified$Edgelist$directed <- NULL
result <- parse_qgraph(q_modified)
expect_true(result$directed)
})
# =============================================================================
# SECTION 21: Layout as non-matrix object
# =============================================================================
test_that("parse_qgraph handles layout not being a matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Set layout to non-matrix
q_modified <- q
q_modified$layout <- list(x = c(0, 1), y = c(0, 1))
result <- parse_qgraph(q_modified)
# Should not crash - x, y may be NA
expect_true(is.data.frame(result$nodes))
})
# =============================================================================
# SECTION 22: Verify correct edge weight alignment
# =============================================================================
test_that("parse_qgraph maintains weight-edge alignment", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 0.25, 0.50, 0.75, 0.25, 0, 0.33, 0.67,
0.50, 0.33, 0, 0.80, 0.75, 0.67, 0.80, 0), 4, 4)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# weights vector should match edges df weight column
expect_equal(length(result$weights), nrow(result$edges))
expect_equal(result$weights, result$edges$weight)
})
# =============================================================================
# SECTION 23: Various graphAttributes configurations
# =============================================================================
test_that("parse_qgraph handles missing graphAttributes$Nodes", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove Nodes entirely
q_modified <- q
q_modified$graphAttributes$Nodes <- NULL
# Should infer from matrix
result <- parse_qgraph(q_modified)
expect_true(is.data.frame(result$nodes))
expect_true(nrow(result$nodes) >= 1)
})
# =============================================================================
# SECTION 24: Verify node ID sequence
# =============================================================================
test_that("parse_qgraph assigns sequential node IDs", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Force n inference from edge list
q_modified <- q
q_modified$graphAttributes$Nodes <- NULL
result <- parse_qgraph(q_modified)
expect_equal(result$nodes$id, seq_len(nrow(result$nodes)))
})
# =============================================================================
# SECTION 25: From/to indices are valid
# =============================================================================
test_that("parse_qgraph produces valid from/to indices", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
if (nrow(result$edges) > 0) {
# From/to should be positive integers
expect_true(all(result$edges$from >= 1))
expect_true(all(result$edges$to >= 1))
# They should be integers
expect_true(all(result$edges$from == as.integer(result$edges$from)))
expect_true(all(result$edges$to == as.integer(result$edges$to)))
}
})
# =============================================================================
# SECTION 26: Consistency with qgraph structure
# =============================================================================
test_that("parse_qgraph creates valid network structure", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0), 4, 4)
rownames(adj) <- colnames(adj) <- c("A", "B", "C", "D")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$nodes) >= 1)
expect_true(is.data.frame(result$edges))
})
# =============================================================================
# SECTION 27: Test with qgraph using different layouts
# =============================================================================
test_that("parse_qgraph works with spring layout", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, layout = "spring")
result <- parse_qgraph(q)
expect_true(is.data.frame(result$nodes))
expect_true(nrow(result$edges) > 0)
})
test_that("parse_qgraph works with circular layout", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, layout = "circle")
result <- parse_qgraph(q)
expect_true(is.data.frame(result$nodes))
})
# =============================================================================
# SECTION 28: Directed parameter override behavior
# =============================================================================
test_that("parse_qgraph directed=TRUE overrides any detection", {
skip_if_not_installed("qgraph")
# Clearly symmetric matrix
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = FALSE)
result <- parse_qgraph(q, directed = TRUE)
expect_true(result$directed)
})
test_that("parse_qgraph directed=FALSE overrides any detection", {
skip_if_not_installed("qgraph")
# Asymmetric matrix
adj <- matrix(c(0, 1, 0, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = TRUE)
result <- parse_qgraph(q, directed = FALSE)
expect_false(result$directed)
})
# =============================================================================
# SECTION 29: Verify proper creation of helper structures
# =============================================================================
test_that("parse_qgraph uses create_nodes_df correctly", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# Verify structure matches create_nodes_df output
expected_cols <- c("id", "label", "name", "x", "y")
expect_true(all(expected_cols %in% names(result$nodes)))
})
test_that("parse_qgraph uses create_edges_df correctly", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
# Verify structure matches create_edges_df output
expected_cols <- c("from", "to", "weight")
expect_true(all(expected_cols %in% names(result$edges)))
})
# =============================================================================
# SECTION 30: Stress test - complex network
# =============================================================================
test_that("parse_qgraph handles complex weighted directed network", {
skip_if_not_installed("qgraph")
set.seed(456)
n <- 10
adj <- matrix(runif(n * n, -1, 1), n, n)
adj <- adj * (abs(adj) > 0.5) # Sparsify
diag(adj) <- 0
rownames(adj) <- colnames(adj) <- paste0("Node", 1:n)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE, directed = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$nodes) >= 1)
expect_true(result$directed)
expect_equal(length(result$weights), nrow(result$edges))
})
# =============================================================================
# SECTION 31: Edge case - qgraph with no Arguments$input but has Edgelist
# =============================================================================
test_that("parse_qgraph works with Edgelist but no input matrix", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
# Remove input but keep Edgelist
q_modified <- q
q_modified$Arguments$input <- NULL
q_modified$graphAttributes$Nodes$names <- NULL
q_modified$graphAttributes$Nodes$labels <- NULL
result <- parse_qgraph(q_modified)
# Should infer n from max(from, to)
expect_true(nrow(result$nodes) >= 1)
})
# =============================================================================
# SECTION 32: Additional validation
# =============================================================================
test_that("parse_qgraph edges have positive count when network has connections", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(nrow(result$edges) > 0)
expect_true(length(result$weights) > 0)
})
test_that("parse_qgraph directed field is logical", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_type(result$directed, "logical")
expect_length(result$directed, 1)
})
# =============================================================================
# SECTION 33: Test label handling
# =============================================================================
test_that("parse_qgraph handles labels with special characters", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 1, 0, 1, 1, 1, 0), 3, 3)
rownames(adj) <- colnames(adj) <- c("A1", "B2", "C3")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(all(nchar(result$nodes$label) > 0))
})
test_that("parse_qgraph handles various label lengths", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 1, 1, 0), 2, 2)
rownames(adj) <- colnames(adj) <- c("Short", "VeryLongLabelName")
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_equal(nrow(result$nodes), 2)
expect_true(all(!is.na(result$nodes$label)))
})
# =============================================================================
# SECTION 34: Test various weight ranges
# =============================================================================
test_that("parse_qgraph handles weights close to zero", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 0.001, 0.001, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(is.data.frame(result$edges))
})
test_that("parse_qgraph handles large weights", {
skip_if_not_installed("qgraph")
adj <- matrix(c(0, 100, 100, 0), 2, 2)
q <- qgraph::qgraph(adj, DoNotPlot = TRUE)
result <- parse_qgraph(q)
expect_true(all(result$weights > 0))
})
# =============================================================================
# SECTION 35: Error condition tests
# =============================================================================
test_that("parse_qgraph error on invalid input types", {
skip_if_not_installed("qgraph")
# String input causes error (either invalid access or validation)
expect_error(parse_qgraph("not a qgraph"))
# NULL input causes error
expect_error(parse_qgraph(NULL))
# Simple list without Arguments field causes error
not_qgraph <- list(foo = 1, bar = 2)
expect_error(parse_qgraph(not_qgraph), "must be a qgraph object")
# Data frame input causes error
df <- data.frame(from = 1:3, to = 2:4)
expect_error(parse_qgraph(df), "must be a qgraph object")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.