Skip to content

Commit 847c3a7

Browse files
committed
test: regression test for ArcadeData#3285
1 parent 9884a06 commit 847c3a7

1 file changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package com.arcadedb.query.opencypher;
2+
3+
import com.arcadedb.database.Database;
4+
import com.arcadedb.database.DatabaseFactory;
5+
import com.arcadedb.graph.Vertex;
6+
import com.arcadedb.query.sql.executor.Result;
7+
import com.arcadedb.query.sql.executor.ResultSet;
8+
import org.junit.jupiter.api.AfterEach;
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Test;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
14+
/**
15+
* Regression test for GitHub Issue #3285: In New Cypher Engine - Traversal happens for One Hop.
16+
* <p>
17+
* The issue reports that multi-hop traversals in chained MATCH patterns return incorrect results.
18+
* Given: one -[:EDG]-> two -[:EDG]-> three
19+
* Query: MATCH(a:A {name:'one'})-[:EDG]->(aa:A)-[:EDG]->(aaa:A) RETURN aaa
20+
* Expected: returns vertex 'three'
21+
* Actual (buggy): returns vertex 'two' - traversal stops at one hop
22+
* <p>
23+
* This issue was reported for version 26.1.1.
24+
*/
25+
public class Issue3285Test {
26+
private Database database;
27+
28+
@BeforeEach
29+
void setUp() {
30+
final DatabaseFactory factory = new DatabaseFactory("./target/databases/test-issue-3285");
31+
if (factory.exists())
32+
factory.open().drop();
33+
database = factory.create();
34+
35+
// Create schema matching the issue description
36+
database.getSchema().createVertexType("A");
37+
database.getSchema().createEdgeType("EDG");
38+
39+
// Create test data: one -> two -> three
40+
database.transaction(() -> {
41+
final Vertex one = database.newVertex("A").set("name", "one").save();
42+
final Vertex two = database.newVertex("A").set("name", "two").save();
43+
final Vertex three = database.newVertex("A").set("name", "three").save();
44+
45+
one.newEdge("EDG", two, true, (Object[]) null).save();
46+
two.newEdge("EDG", three, true, (Object[]) null).save();
47+
});
48+
}
49+
50+
@AfterEach
51+
void tearDown() {
52+
if (database != null) {
53+
database.drop();
54+
database = null;
55+
}
56+
}
57+
58+
@Test
59+
void testExactQueryFromIssue() {
60+
// This is the EXACT query string from the issue (no spaces, lowercase 'return')
61+
final ResultSet result = database.query("opencypher",
62+
"MATCH(a:A {name:'one'})-[:EDG]->(aa:A)-[:EDG]->(aaa:A) return aaa");
63+
64+
assertThat(result.hasNext()).as("Should have at least one result").isTrue();
65+
final Result row = result.next();
66+
67+
// Single variable returns are returned as elements via toElement()
68+
Vertex aaa;
69+
if (row.isElement()) {
70+
aaa = (Vertex) row.toElement();
71+
} else {
72+
aaa = (Vertex) row.getProperty("aaa");
73+
}
74+
assertThat(aaa).as("Variable 'aaa' should not be null").isNotNull();
75+
76+
// The issue reports that this returns 'two' instead of 'three'
77+
assertThat((String) aaa.get("name")).isEqualTo("three");
78+
assertThat(result.hasNext()).isFalse();
79+
}
80+
81+
@Test
82+
void testMultiHopChainedPatternReturnsCorrectVertex() {
83+
// Same query with standard formatting
84+
final ResultSet result = database.query("opencypher",
85+
"MATCH (a:A {name:'one'})-[:EDG]->(aa:A)-[:EDG]->(aaa:A) RETURN aaa");
86+
87+
assertThat(result.hasNext()).as("Should have at least one result").isTrue();
88+
final Result row = result.next();
89+
90+
// Single variable returns are returned as elements via toElement()
91+
Vertex aaa;
92+
if (row.isElement()) {
93+
aaa = (Vertex) row.toElement();
94+
} else {
95+
aaa = (Vertex) row.getProperty("aaa");
96+
}
97+
assertThat(aaa).as("Variable 'aaa' should not be null").isNotNull();
98+
99+
// Verify correct vertex is returned at the end of the 2-hop chain
100+
assertThat((String) aaa.get("name")).isEqualTo("three");
101+
assertThat(result.hasNext()).isFalse();
102+
}
103+
104+
@Test
105+
void testMultiHopChainedPatternReturnsAllVariables() {
106+
// Test returning all three variables to ensure correct binding
107+
final ResultSet result = database.query("opencypher",
108+
"MATCH (a:A {name:'one'})-[:EDG]->(aa:A)-[:EDG]->(aaa:A) RETURN a, aa, aaa");
109+
110+
assertThat(result.hasNext()).as("Should have at least one result").isTrue();
111+
final Result row = result.next();
112+
113+
final Vertex a = (Vertex) row.getProperty("a");
114+
final Vertex aa = (Vertex) row.getProperty("aa");
115+
final Vertex aaa = (Vertex) row.getProperty("aaa");
116+
117+
assertThat(a).isNotNull();
118+
assertThat(aa).isNotNull();
119+
assertThat(aaa).isNotNull();
120+
121+
assertThat((String) a.get("name")).isEqualTo("one");
122+
assertThat((String) aa.get("name")).isEqualTo("two");
123+
assertThat((String) aaa.get("name")).isEqualTo("three");
124+
125+
assertThat(result.hasNext()).isFalse();
126+
}
127+
128+
@Test
129+
void testSingleHopPattern() {
130+
// Verify single hop works correctly
131+
final ResultSet result = database.query("opencypher",
132+
"MATCH (a:A {name:'one'})-[:EDG]->(aa:A) RETURN aa");
133+
134+
assertThat(result.hasNext()).isTrue();
135+
final Result row = result.next();
136+
137+
// Single variable returns are returned as elements via toElement()
138+
Vertex aa;
139+
if (row.isElement()) {
140+
aa = (Vertex) row.toElement();
141+
} else {
142+
aa = (Vertex) row.getProperty("aa");
143+
}
144+
145+
assertThat((String) aa.get("name")).isEqualTo("two");
146+
assertThat(result.hasNext()).isFalse();
147+
}
148+
149+
@Test
150+
void testThreeHopChainedPattern() {
151+
// Add a fourth vertex to test longer chains
152+
database.transaction(() -> {
153+
final ResultSet findThree = database.query("opencypher", "MATCH (v:A {name:'three'}) RETURN v");
154+
final Result threeResult = findThree.next();
155+
// Single variable returns are returned as elements
156+
final Vertex three = threeResult.isElement() ? (Vertex) threeResult.toElement() : (Vertex) threeResult.getProperty("v");
157+
final Vertex four = database.newVertex("A").set("name", "four").save();
158+
three.newEdge("EDG", four, true, (Object[]) null).save();
159+
});
160+
161+
// Test 3-hop chain
162+
final ResultSet result = database.query("opencypher",
163+
"MATCH (a:A {name:'one'})-[:EDG]->(b:A)-[:EDG]->(c:A)-[:EDG]->(d:A) RETURN a, b, c, d");
164+
165+
assertThat(result.hasNext()).isTrue();
166+
final Result row = result.next();
167+
168+
final Vertex a = (Vertex) row.getProperty("a");
169+
final Vertex b = (Vertex) row.getProperty("b");
170+
final Vertex c = (Vertex) row.getProperty("c");
171+
final Vertex d = (Vertex) row.getProperty("d");
172+
173+
assertThat((String) a.get("name")).isEqualTo("one");
174+
assertThat((String) b.get("name")).isEqualTo("two");
175+
assertThat((String) c.get("name")).isEqualTo("three");
176+
assertThat((String) d.get("name")).isEqualTo("four");
177+
178+
assertThat(result.hasNext()).isFalse();
179+
}
180+
}

0 commit comments

Comments
 (0)