Skip to content

Commit 06f8184

Browse files
committed
2 parents 4df7493 + a5abee0 commit 06f8184

File tree

9 files changed

+217
-29
lines changed

9 files changed

+217
-29
lines changed

src/main/java/javafxlibrary/keywords/AdditionalKeywords/Find.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package javafxlibrary.keywords.AdditionalKeywords;
22

33
import javafx.scene.Parent;
4+
import javafxlibrary.exceptions.JavaFXLibraryFatalException;
45
import javafxlibrary.exceptions.JavaFXLibraryNonFatalException;
56
import javafxlibrary.utils.finder.Finder;
67
import javafxlibrary.utils.RobotLog;
@@ -46,11 +47,12 @@ public Object find(String query, boolean failIfNotFound, Parent root) {
4647
try {
4748
return mapObject(new Finder().find(query, root));
4849

49-
} catch (JavaFXLibraryNonFatalException e){
50+
} catch (JavaFXLibraryNonFatalException e) {
5051
if (failIfNotFound)
5152
throw new JavaFXLibraryNonFatalException("Unable to find anything with query: \"" + query + "\"");
5253
return "";
53-
54+
} catch (JavaFXLibraryFatalException e) {
55+
throw e;
5456
} catch (Exception e) {
5557
throw new JavaFXLibraryNonFatalException("Find operation failed for query: \"" + query + "\"", e);
5658
}
@@ -68,7 +70,8 @@ public Object find(String query, boolean failIfNotFound) {
6870
if (failIfNotFound)
6971
throw new JavaFXLibraryNonFatalException("Unable to find anything with query: \"" + query + "\"");
7072
return "";
71-
73+
} catch (JavaFXLibraryFatalException e) {
74+
throw e;
7275
} catch (Exception e) {
7376
throw new JavaFXLibraryNonFatalException("Find operation failed for query: \"" + query + "\"", e);
7477
}
@@ -95,6 +98,8 @@ public List<Object> findAll(String query, boolean failIfNotFound, Parent root) {
9598
if (failIfNotFound)
9699
throw new JavaFXLibraryNonFatalException("Unable to find anything with query: \"" + query + "\"");
97100
return new ArrayList<>();
101+
} catch (JavaFXLibraryFatalException e) {
102+
throw e;
98103
} catch (Exception e) {
99104
throw new JavaFXLibraryNonFatalException("Find operation failed for query: \"" + query + "\"", e);
100105
}
@@ -109,6 +114,8 @@ public List<Object> findAll(String query, boolean failIfNotFound) {
109114
if (failIfNotFound)
110115
throw new JavaFXLibraryNonFatalException("Unable to find anything with query: \"" + query + "\"");
111116
return new ArrayList<>();
117+
} catch (JavaFXLibraryFatalException e) {
118+
throw e;
112119
} catch (Exception e) {
113120
throw new JavaFXLibraryNonFatalException("Find operation failed for query: \"" + query + "\"", e);
114121
}

src/main/java/javafxlibrary/testapps/FinderApp.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@
55
import javafx.scene.Parent;
66
import javafx.scene.Scene;
77
import javafx.stage.Stage;
8+
import javafx.stage.StageStyle;
9+
import org.testfx.api.FxToolkit;
810

911
public class FinderApp extends Application {
1012

1113
int scale = 200;
1214

1315
@Override
14-
public void start(Stage firstStage) throws Exception {
16+
public void init() throws Exception {
17+
FxToolkit.registerStage(() -> new Stage());
18+
}
1519

20+
@Override
21+
public void start(Stage firstStage) throws Exception {
1622
Stage secondStage = new Stage();
1723
Stage thirdStage = new Stage();
1824
Stage fourthStage = new Stage();
@@ -27,14 +33,14 @@ public void start(Stage firstStage) throws Exception {
2733

2834
for (int i = 0; i < stages.length; i++) {
2935
Stage current = stages[i];
36+
current.initStyle(StageStyle.DECORATED);
3037
current.setWidth(scale);
3138
current.setHeight(scale);
3239
current.setX(i * scale);
40+
current.setY(100);
3341
current.setScene(scenes[i]);
3442
current.setTitle("Window " + (i + 1));
3543
current.show();
36-
37-
3844
}
3945

4046
}

src/main/java/javafxlibrary/utils/finder/FindOperation.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323
import javafx.scene.Parent;
2424
import javafxlibrary.exceptions.JavaFXLibraryNonFatalException;
2525
import javafxlibrary.matchers.InstanceOfMatcher;
26+
import javafxlibrary.utils.RobotLog;
2627
import javafxlibrary.utils.TestFxAdapter;
2728
import org.testfx.api.FxRobotInterface;
2829
import org.testfx.matcher.control.LabeledMatchers;
2930
import org.testfx.service.query.NodeQuery;
3031

32+
import java.util.*;
33+
3134
public class FindOperation {
3235

3336
private Parent root;
@@ -43,9 +46,30 @@ public FindOperation(Parent root, Query query, boolean findAll) {
4346
}
4447

4548
protected Object executeLookup() {
46-
FindPrefix prefix = query.getPrefix();
47-
String lookupQuery = query.getQuery();
49+
// If find is called with a query that contains an index, use findAll methods instead
50+
if (!findAll && query.containsIndex()) {
51+
return executeOverriddenLookup();
52+
} else if (query.containsIndex()) {
53+
Set<Node> lookupResults = new LinkedHashSet<>((Set<Node>)executeLookup(query.getPrefix(), query.getQuery()));
54+
lookupResults.remove(root);
55+
Node nodeAtIndex = getLookupResultByIndex(lookupResults, query.getIndex());
56+
57+
if (nodeAtIndex != null)
58+
return new LinkedHashSet<>(Collections.singletonList(nodeAtIndex));
59+
return Collections.emptySet();
60+
}
4861

62+
return executeLookup(query.getPrefix(), query.getQuery());
63+
}
64+
65+
protected Object executeOverriddenLookup() {
66+
this.findAll = true;
67+
Set<Node> result = new LinkedHashSet<>((Set<Node>)executeLookup(query.getPrefix(), query.getQuery()));
68+
result.remove(root);
69+
return getLookupResultByIndex(result, query.getIndex());
70+
}
71+
72+
private Object executeLookup(FindPrefix prefix, String lookupQuery) {
4973
switch (prefix) {
5074
case ID:
5175
case CSS:
@@ -91,4 +115,12 @@ private NodeQuery classLookup(Parent root, String query) {
91115
"Node lookup: class was not found");
92116
}
93117
}
118+
119+
private Node getLookupResultByIndex(Set<Node> lookupResults, int index) {
120+
try {
121+
return new ArrayList<>(lookupResults).get(index);
122+
} catch (IndexOutOfBoundsException e) {
123+
return null;
124+
}
125+
}
94126
}

src/main/java/javafxlibrary/utils/finder/Finder.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,10 @@ public Node find(String query, Parent root) {
7373
}
7474

7575
private Node find(Parent root, int queryIndex) {
76-
String query = queries[queryIndex];
76+
Query query = new Query(queries[queryIndex]);
7777

7878
if (queryIndex < queries.length - 1) {
79-
// lookupResults might be unmodifiable, copy contents to a new Set
80-
Set<Node> lookupResults = executeFindAll(root, query);
81-
Set<Node> nodes = new LinkedHashSet<>();
82-
nodes.addAll(lookupResults);
79+
Set<Node> nodes = new LinkedHashSet<>(executeFindAll(root, query));
8380
nodes.remove(root);
8481

8582
for (Node node : nodes) {
@@ -129,12 +126,8 @@ public Set<Node> findAll(String query, Parent root) {
129126
}
130127

131128
private Set<Node> findAll(Parent root, int queryIndex) {
132-
String query = queries[queryIndex];
133-
Set<Node> lookupResults = executeFindAll(root, query);
134-
Set<Node> nodes = new LinkedHashSet<>();
135-
nodes.addAll(lookupResults);
136-
nodes.remove(root);
137-
129+
Query query = new Query(queries[queryIndex]);
130+
Set<Node> nodes = new LinkedHashSet<>(executeFindAll(root, query));
138131
if (queryIndex < queries.length - 1) {
139132
for (Node node : nodes)
140133
if (node instanceof Parent)
@@ -146,16 +139,15 @@ private Set<Node> findAll(Parent root, int queryIndex) {
146139
return results;
147140
}
148141

149-
private Node executeFind(Parent root, String query) {
150-
RobotLog.debug("Executing find with root: " + root + " and query: " + query);
151-
FindOperation findOperation = new FindOperation(root, new Query(query), false);
142+
private Node executeFind(Parent root, Query query) {
143+
RobotLog.debug("Executing find with root: " + root + " and query: " + query.getQuery());
144+
FindOperation findOperation = new FindOperation(root, query, false);
152145
return (Node) findOperation.executeLookup();
153146
}
154147

155-
// TODO: Add support for using indexes in queries (css=VBox[3]), xPath already implements this
156-
private Set<Node> executeFindAll(Parent root, String query) {
157-
RobotLog.debug("Executing find all with root: " + root + " and query: " + query);
158-
FindOperation findOperation = new FindOperation(root, new Query(query), true);
159-
return (Set<Node>) findOperation.executeLookup();
148+
private Set<Node> executeFindAll(Parent root, Query query) {
149+
RobotLog.debug("Executing find all with root: " + root + " and query: " + query.getQuery());
150+
FindOperation findOperation = new FindOperation(root, query, true);
151+
return new LinkedHashSet<>((Set<Node>)findOperation.executeLookup());
160152
}
161153
}

src/main/java/javafxlibrary/utils/finder/Query.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,25 @@
1717

1818
package javafxlibrary.utils.finder;
1919

20+
import javafxlibrary.exceptions.JavaFXLibraryFatalException;
21+
2022
public class Query {
2123

2224
private FindPrefix prefix;
2325
private String query;
26+
private int index = -1;
2427

2528
public Query(String query) {
2629
this.prefix = QueryParser.getPrefix(query);
30+
31+
if (this.prefix != FindPrefix.XPATH && QueryParser.containsIndex(query)) {
32+
this.index = QueryParser.getQueryIndex(query);
33+
if (this.index < 0) {
34+
throw new JavaFXLibraryFatalException("Invalid query \"" + query + "\": Minimum index value is 1!");
35+
}
36+
query = QueryParser.removeQueryIndex(query);
37+
}
38+
2739
this.query = QueryParser.removePrefix(query, this.prefix);
2840
}
2941

@@ -34,4 +46,12 @@ public FindPrefix getPrefix() {
3446
public String getQuery() {
3547
return this.query;
3648
}
49+
50+
public int getIndex() {
51+
return this.index;
52+
}
53+
54+
public boolean containsIndex() {
55+
return this.index != -1;
56+
}
3757
}

src/main/java/javafxlibrary/utils/finder/QueryParser.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
2222
import java.util.List;
23+
import java.util.regex.Matcher;
24+
import java.util.regex.Pattern;
2325

2426
public class QueryParser {
2527

@@ -121,4 +123,18 @@ protected static String removePrefix(String query, FindPrefix prefix) {
121123
}
122124
throw new IllegalArgumentException("FindPrefix value " + prefix + " of query " + query + " is not supported");
123125
}
126+
127+
protected static boolean containsIndex(String query) {
128+
Pattern pattern = Pattern.compile(".*\\[\\d*]$");
129+
Matcher matcher = pattern.matcher(query);
130+
return matcher.matches();
131+
}
132+
133+
protected static int getQueryIndex(String query) {
134+
return Integer.parseInt(query.substring(query.lastIndexOf('[') + 1, query.length() - 1)) - 1;
135+
}
136+
137+
protected static String removeQueryIndex(String query) {
138+
return query.substring(0, query.lastIndexOf('['));
139+
}
124140
}

src/test/java/javafxlibrary/utils/finder/QueryParserTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,31 @@ public void getPrefix_InvalidValue() {
6262
thrown.expectMessage("Query \"notaprefix=someValue\" does not contain any supported prefix");
6363
QueryParser.getPrefix("notaprefix=someValue");
6464
}
65+
66+
@Test
67+
public void containsIndex() {
68+
Assert.assertTrue(QueryParser.containsIndex("Rectangle[0]"));
69+
Assert.assertTrue(QueryParser.containsIndex("Rectangle[8]"));
70+
Assert.assertTrue(QueryParser.containsIndex("Rectangle[22]"));
71+
Assert.assertTrue(QueryParser.containsIndex("Rectangle[1995]"));
72+
Assert.assertFalse(QueryParser.containsIndex("Node1"));
73+
Assert.assertFalse(QueryParser.containsIndex("xpath=Text[@text='text[2]'"));
74+
}
75+
76+
@Test
77+
public void getQueryIndex() {
78+
Assert.assertTrue(0 == QueryParser.getQueryIndex("Rectangle[1]"));
79+
Assert.assertTrue(8 == QueryParser.getQueryIndex("Rectangle[9]"));
80+
Assert.assertTrue(22 == QueryParser.getQueryIndex("Rectangle[23]"));
81+
Assert.assertTrue(1995 == QueryParser.getQueryIndex("Rectangle[1996]"));
82+
}
83+
84+
@Test
85+
public void removeQueryIndex() {
86+
Assert.assertEquals("Rectangle", QueryParser.removeQueryIndex("Rectangle[0]"));
87+
Assert.assertEquals("Rectangle", QueryParser.removeQueryIndex("Rectangle[22]"));
88+
Assert.assertEquals("Rectangle", QueryParser.removeQueryIndex("Rectangle[1995]"));
89+
Assert.assertEquals("VBox", QueryParser.removeQueryIndex("VBox[2]"));
90+
Assert.assertEquals("SomeClass", QueryParser.removeQueryIndex("SomeClass[12]"));
91+
}
6592
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package javafxlibrary.utils.finder;
2+
3+
import javafxlibrary.exceptions.JavaFXLibraryFatalException;
4+
import org.junit.Assert;
5+
import org.junit.Rule;
6+
import org.junit.Test;
7+
import org.junit.rules.ExpectedException;
8+
9+
public class QueryTest {
10+
11+
@Rule
12+
public ExpectedException thrown = ExpectedException.none();
13+
14+
@Test
15+
public void validQuery_withIndex() {
16+
Query query = new Query("css=VBox[1]");
17+
Assert.assertEquals("VBox", query.getQuery());
18+
Assert.assertEquals(FindPrefix.CSS, query.getPrefix());
19+
Assert.assertTrue(query.containsIndex());
20+
Assert.assertEquals(0, query.getIndex());
21+
}
22+
23+
@Test
24+
public void validQuery_noIndex() {
25+
Query query = new Query("class=javafx.scene.layout.VBox");
26+
Assert.assertEquals("javafx.scene.layout.VBox", query.getQuery());
27+
Assert.assertEquals(FindPrefix.CLASS, query.getPrefix());
28+
Assert.assertFalse(query.containsIndex());
29+
Assert.assertEquals(-1, query.getIndex());
30+
}
31+
32+
@Test
33+
public void invalidQueryIndex() {
34+
thrown.expect(JavaFXLibraryFatalException.class);
35+
thrown.expectMessage("Invalid query \"css=VBox[0]\": Minimum index value is 1!");
36+
new Query("css=VBox[0]");
37+
}
38+
}

0 commit comments

Comments
 (0)