Files
wifi-densepose/crates/ruvector-graph/tests/cypher_parser_tests.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

224 lines
5.8 KiB
Rust

//! Cypher query parser tests
//!
//! Tests for parsing valid and invalid Cypher queries to ensure syntax correctness.
use ruvector_graph::cypher::parse_cypher;
// ============================================================================
// Valid Cypher Queries
// ============================================================================
#[test]
fn test_parse_simple_match() {
let result = parse_cypher("MATCH (n) RETURN n");
assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}
#[test]
fn test_parse_match_with_label() {
let result = parse_cypher("MATCH (n:Person) RETURN n");
assert!(result.is_ok());
}
#[test]
fn test_parse_match_with_properties() {
let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) RETURN n");
assert!(result.is_ok());
}
#[test]
fn test_parse_match_relationship() {
let result = parse_cypher("MATCH (a)-[r:KNOWS]->(b) RETURN a, r, b");
assert!(result.is_ok());
}
#[test]
fn test_parse_match_undirected_relationship() {
let result = parse_cypher("MATCH (a)-[r:FRIEND]-(b) RETURN a, b");
assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}
#[test]
fn test_parse_match_path() {
let result = parse_cypher("MATCH p = (a)-[:KNOWS*1..3]->(b) RETURN p");
assert!(result.is_ok());
}
#[test]
fn test_parse_create_node() {
let result = parse_cypher("CREATE (n:Person {name: 'Bob', age: 30})");
assert!(result.is_ok());
}
#[test]
fn test_parse_create_relationship() {
let result =
parse_cypher("CREATE (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})");
assert!(result.is_ok());
}
#[test]
fn test_parse_merge() {
let result = parse_cypher("MERGE (n:Person {name: 'Charlie'})");
assert!(result.is_ok());
}
#[test]
fn test_parse_delete() {
let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) DELETE n");
assert!(result.is_ok());
}
#[test]
fn test_parse_set_property() {
let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) SET n.age = 31");
assert!(result.is_ok());
}
#[test]
fn test_parse_remove_property() {
let result = parse_cypher("MATCH (n:Person {name: 'Alice'}) REMOVE n.age");
assert!(result.is_ok(), "Parse failed: {:?}", result.err());
}
#[test]
fn test_parse_where_clause() {
let result = parse_cypher("MATCH (n:Person) WHERE n.age > 25 RETURN n");
assert!(result.is_ok());
}
#[test]
fn test_parse_order_by() {
let result = parse_cypher("MATCH (n:Person) RETURN n ORDER BY n.age DESC");
assert!(result.is_ok());
}
#[test]
fn test_parse_limit() {
let result = parse_cypher("MATCH (n:Person) RETURN n LIMIT 10");
assert!(result.is_ok());
}
#[test]
fn test_parse_skip() {
let result = parse_cypher("MATCH (n:Person) RETURN n SKIP 5 LIMIT 10");
assert!(result.is_ok());
}
#[test]
fn test_parse_aggregate_count() {
let result = parse_cypher("MATCH (n:Person) RETURN COUNT(n)");
assert!(result.is_ok());
}
#[test]
fn test_parse_aggregate_sum() {
let result = parse_cypher("MATCH (n:Person) RETURN SUM(n.age)");
assert!(result.is_ok());
}
#[test]
fn test_parse_aggregate_avg() {
let result = parse_cypher("MATCH (n:Person) RETURN AVG(n.age)");
assert!(result.is_ok());
}
#[test]
fn test_parse_with_clause() {
let result = parse_cypher("MATCH (n:Person) WITH n.age AS age WHERE age > 25 RETURN age");
assert!(result.is_ok());
}
#[test]
fn test_parse_optional_match() {
let result = parse_cypher("OPTIONAL MATCH (n:Person)-[r:KNOWS]->(m) RETURN n, m");
assert!(result.is_ok());
}
// ============================================================================
// Complex Query Tests
// ============================================================================
#[test]
#[ignore = "Complex multi-direction patterns with <- not yet fully implemented"]
fn test_parse_complex_graph_pattern() {
let result = parse_cypher(
"
MATCH (user:User)-[:PURCHASED]->(product:Product)<-[:PURCHASED]-(other:User)
WHERE other.id <> 123
WITH other, COUNT(*) AS commonProducts
WHERE commonProducts > 3
RETURN other.name
ORDER BY commonProducts DESC
LIMIT 10
",
);
assert!(result.is_ok());
}
#[test]
fn test_parse_variable_length_path() {
let result =
parse_cypher("MATCH (a:Person)-[:KNOWS*1..5]->(b:Person) WHERE a.name = 'Alice' RETURN b");
assert!(result.is_ok());
}
#[test]
fn test_parse_multiple_patterns() {
let result = parse_cypher(
"
MATCH (a:Person)-[:KNOWS]->(b:Person)
MATCH (b)-[:WORKS_AT]->(c:Company)
RETURN a.name, b.name, c.name
",
);
assert!(result.is_ok());
}
#[test]
fn test_parse_collect_aggregation() {
let result = parse_cypher(
"MATCH (p:Person)-[:KNOWS]->(f:Person) RETURN p.name, COLLECT(f.name) AS friends",
);
assert!(result.is_ok());
}
// ============================================================================
// Edge Cases
// ============================================================================
#[test]
#[ignore = "Empty query validation not yet implemented"]
fn test_parse_empty_query() {
let result = parse_cypher("");
// Empty query should fail
assert!(result.is_err());
}
#[test]
#[ignore = "Whitespace-only query validation not yet implemented"]
fn test_parse_whitespace_only() {
let result = parse_cypher(" \n\t ");
// Whitespace only should fail
assert!(result.is_err());
}
#[test]
fn test_parse_parameters() {
let result = parse_cypher("MATCH (n:Person {name: $name, age: $age}) RETURN n");
assert!(result.is_ok());
}
#[test]
fn test_parse_list_literal() {
let result = parse_cypher("RETURN [1, 2, 3, 4, 5] AS numbers");
assert!(result.is_ok());
}
#[test]
#[ignore = "Map literal in RETURN not yet implemented"]
fn test_parse_map_literal() {
let result = parse_cypher("RETURN {name: 'Alice', age: 30} AS person");
assert!(result.is_ok());
}