Skip to content

Commit 75f7a1c

Browse files
committed
feat: test with graph from la-n-egg tests
1 parent 8faf9cf commit 75f7a1c

13 files changed

Lines changed: 87527 additions & 5 deletions

File tree

src/formats/mm.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use std::os::fd::IntoRawFd;
3131
use std::path::{Path, PathBuf};
3232

3333
use crate::formats::FormatError;
34-
use crate::graph::{ensure_grb_init, GraphError};
34+
use crate::graph::{GraphError, ensure_grb_init};
3535
use crate::la_ok;
3636
use crate::lagraph_sys::{FILE, GrB_Matrix, LAGraph_MMRead};
3737

@@ -40,10 +40,13 @@ pub fn load_mm_file(path: impl AsRef<Path>) -> Result<GrB_Matrix, FormatError> {
4040
let path = path.as_ref();
4141

4242
ensure_grb_init().map_err(|e| match e {
43-
GraphError::LAGraph(info, msg) => FormatError::MatrixMarket { code: info, message: msg },
43+
GraphError::LAGraph(info, msg) => FormatError::MatrixMarket {
44+
code: info,
45+
message: msg,
46+
},
4447
_ => FormatError::MatrixMarket {
4548
code: crate::lagraph_sys::GrB_Info::GrB_PANIC,
46-
message: "Failed to initialize GraphBLAS".to_string()
49+
message: "Failed to initialize GraphBLAS".to_string(),
4750
},
4851
})?;
4952

@@ -62,10 +65,12 @@ pub fn load_mm_file(path: impl AsRef<Path>) -> Result<GrB_Matrix, FormatError> {
6265
let err = la_ok!(LAGraph_MMRead(&mut matrix, f as *mut FILE));
6366
unsafe { libc::fclose(f) };
6467

65-
6668
match err {
6769
Ok(_) => Ok(matrix),
68-
Err(GraphError::LAGraph(info, msg)) => Err(FormatError::MatrixMarket { code: info, message: msg }),
70+
Err(GraphError::LAGraph(info, msg)) => Err(FormatError::MatrixMarket {
71+
code: info,
72+
message: msg,
73+
}),
6974
_ => unreachable!("should be either mm read error or ok"),
7075
}
7176
}

tests/mm_tests.rs

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
use pathrex::formats::mm::MatrixMarket;
2+
use pathrex::graph::{Backend, Graph, GraphDecomposition, GraphSource, InMemory, InMemoryGraph};
3+
4+
const GRAPH_DIR: &str = "tests/testdata/mm_graph";
5+
static INMEMORY_GRAPH: std::sync::LazyLock<InMemoryGraph> =
6+
std::sync::LazyLock::new(|| load_graph_from_mm::<InMemory>(GRAPH_DIR));
7+
8+
fn load_graph_from_mm<B: Backend>(dir: &str) -> B::Graph
9+
where
10+
MatrixMarket: GraphSource<B::Builder>,
11+
{
12+
let mm = MatrixMarket::from_dir(dir);
13+
Graph::<B>::try_from(mm).expect("Failed to load graph")
14+
}
15+
16+
#[test]
17+
fn test_load_mm_graph_basic() {
18+
let graph = &INMEMORY_GRAPH;
19+
let expected_nodes_number = 24225;
20+
21+
assert_eq!(graph.num_nodes(), expected_nodes_number);
22+
}
23+
24+
#[test]
25+
fn test_mm_graph_node_mapping() {
26+
let graph = &INMEMORY_GRAPH;
27+
28+
let test_nodes = vec![
29+
("<Article1>", 1),
30+
("<1940>", 2),
31+
("<Adamanta_Schlitt>", 3),
32+
("<Paul_Erdoes>", 4),
33+
];
34+
35+
for (name, expected_id) in test_nodes {
36+
let id = graph.get_node_id(name).expect("Node should exist");
37+
assert_eq!(id, expected_id);
38+
39+
let retrieved_name = graph
40+
.get_node_name(id)
41+
.expect("ID should map back to a name");
42+
assert_eq!(retrieved_name, name,);
43+
}
44+
}
45+
46+
#[test]
47+
fn test_mm_graph_edge_labels() {
48+
let graph = &INMEMORY_GRAPH;
49+
50+
let expected_labels = vec![
51+
"<journal>",
52+
"<creator>",
53+
"<references>",
54+
"<cite>",
55+
"<editor>",
56+
"<coauthor>",
57+
"<partOf>",
58+
"<record>",
59+
"<predecessor>",
60+
];
61+
62+
for label in expected_labels {
63+
let result = graph.get_graph(label);
64+
assert!(result.is_ok(),);
65+
}
66+
}
67+
68+
#[test]
69+
fn test_mm_graph_nonexistent_label() {
70+
let graph = &INMEMORY_GRAPH;
71+
72+
let result = graph.get_graph("<nonexistent_label>");
73+
assert!(result.is_err());
74+
}
75+
76+
#[test]
77+
fn test_mm_graph_nonexistent_node() {
78+
let graph = &INMEMORY_GRAPH;
79+
80+
assert!(graph.get_node_id("<NonexistentNode>").is_none(),);
81+
82+
assert!(graph.get_node_name(999999).is_none(),);
83+
}
84+
85+
#[test]
86+
fn test_mm_graph_specific_nodes_exist() {
87+
let graph = &INMEMORY_GRAPH;
88+
89+
let nodes_to_check = vec![
90+
"<Article1>",
91+
"<Article20>",
92+
"<Article100>",
93+
"<Paul_Erdoes>",
94+
"<1940>",
95+
"<1950>",
96+
"<1960>",
97+
"<Inproceeding1>",
98+
"<Incollection1>",
99+
];
100+
101+
for node in nodes_to_check {
102+
assert!(graph.get_node_id(node).is_some());
103+
}
104+
}
105+
106+
#[test]
107+
fn test_mm_graph_matrix_dimensions() {
108+
let graph = &INMEMORY_GRAPH;
109+
110+
let expected_labels = vec![
111+
"<journal>",
112+
"<creator>",
113+
"<references>",
114+
"<cite>",
115+
"<editor>",
116+
"<coauthor>",
117+
"<partOf>",
118+
"<record>",
119+
"<predecessor>",
120+
];
121+
122+
for label in expected_labels {
123+
let matrix = graph
124+
.get_graph(label)
125+
.expect(&format!("Should have matrix for label {}", label));
126+
matrix
127+
.check_graph()
128+
.expect(&format!("Matrix for {} should be valid", label));
129+
}
130+
}
131+
132+
#[test]
133+
fn test_mm_graph_load_from_nonexistent_dir() {
134+
let mm = MatrixMarket::from_dir("tests/testdata/nonexistent_dir");
135+
let result = Graph::<InMemory>::try_from(mm);
136+
137+
assert!(
138+
result.is_err(),
139+
"Loading from nonexistent directory should fail"
140+
);
141+
}
142+
143+
#[test]
144+
fn test_mm_graph_edge_label_mapping() {
145+
let mm = MatrixMarket::from_dir("tests/testdata/mm_graph");
146+
let graph = Graph::<InMemory>::try_from(mm).expect("Failed to load graph");
147+
148+
// Test that edge labels map correctly to their index files
149+
// From edges.txt:
150+
// <journal> 1 -> 1.txt
151+
// <creator> 2 -> 2.txt
152+
// <references> 3 -> 3.txt
153+
// etc.
154+
155+
let label_to_file = vec![
156+
("<journal>", "1.txt"),
157+
("<creator>", "2.txt"),
158+
("<references>", "3.txt"),
159+
("<cite>", "4.txt"),
160+
("<editor>", "5.txt"),
161+
("<coauthor>", "6.txt"),
162+
("<partOf>", "7.txt"),
163+
("<record>", "8.txt"),
164+
("<predecessor>", "9.txt"),
165+
];
166+
167+
for (label, _file) in label_to_file {
168+
let result = graph.get_graph(label);
169+
assert!(
170+
result.is_ok(),
171+
"Label {} should be loaded from its corresponding matrix file",
172+
label
173+
);
174+
}
175+
}
176+
177+
#[test]
178+
fn test_mm_graph_handles_large_indices() {
179+
let mm = MatrixMarket::from_dir("tests/testdata/mm_graph");
180+
let graph = Graph::<InMemory>::try_from(mm).expect("Failed to load graph");
181+
182+
// Test that we can handle nodes with large indices
183+
// The last node in vertices.txt should be around index 24225
184+
let num_nodes = graph.num_nodes();
185+
186+
// Try to get a node name for a valid high index
187+
let high_index = num_nodes;
188+
let name = graph.get_node_name(high_index);
189+
assert!(
190+
name.is_some(),
191+
"Should be able to retrieve node at index {}",
192+
high_index
193+
);
194+
}
195+
196+
#[test]
197+
fn test_mm_graph_empty_label_handling() {
198+
let mm = MatrixMarket::from_dir("tests/testdata/mm_graph");
199+
let graph = Graph::<InMemory>::try_from(mm).expect("Failed to load graph");
200+
201+
// Test that empty string label is handled correctly
202+
let result = graph.get_graph("");
203+
assert!(result.is_err(), "Empty label should not exist in the graph");
204+
}

0 commit comments

Comments
 (0)