Skip to content

Commit f8be01c

Browse files
committed
Move the lookup logic into a separate class
Moved lookup logic from Finder to the new FindOperation class. Finder manages the state of the whole lookup process, like remaining roots and recursion, while FindOperation performs a single lookup for a single root. Find and Find All both use the same executeLookup method for the lookup and cast the results respectively into either a Node or a Set. The type of lookup (first/all) is given as an argument in FindOperations constructor. Methods for getting the FindPrefix and removing it from the query string were moved to QueryParser.
1 parent adc58fa commit f8be01c

File tree

7 files changed

+261
-122
lines changed

7 files changed

+261
-122
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2017-2018 Eficode Oy
3+
* Copyright 2018- Robot Framework Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package javafxlibrary.utils.finder;
19+
20+
import javafx.collections.ObservableSet;
21+
import javafx.css.PseudoClass;
22+
import javafx.scene.Node;
23+
import javafx.scene.Parent;
24+
import javafxlibrary.exceptions.JavaFXLibraryNonFatalException;
25+
import javafxlibrary.matchers.InstanceOfMatcher;
26+
import javafxlibrary.utils.TestFxAdapter;
27+
import org.testfx.api.FxRobotInterface;
28+
import org.testfx.matcher.control.LabeledMatchers;
29+
import org.testfx.service.query.NodeQuery;
30+
31+
public class FindOperation {
32+
33+
private Parent root;
34+
private Query query;
35+
private boolean findAll;
36+
private FxRobotInterface robot;
37+
38+
public FindOperation(Parent root, Query query, boolean findAll) {
39+
this.root = root;
40+
this.query = query;
41+
this.findAll = findAll;
42+
this.robot = TestFxAdapter.getRobot();
43+
}
44+
45+
protected Object executeLookup() {
46+
FindPrefix prefix = query.getPrefix();
47+
String lookupQuery = query.getQuery();
48+
49+
switch (prefix) {
50+
case ID:
51+
case CSS:
52+
return findAll ? root.lookupAll(lookupQuery) : root.lookup(lookupQuery);
53+
case CLASS:
54+
NodeQuery classLookupResults = classLookup(root, lookupQuery);
55+
return findAll ? classLookupResults.queryAll() : classLookupResults.query();
56+
case TEXT:
57+
NodeQuery textLookupResults = robot.from(root).lookup(LabeledMatchers.hasText(lookupQuery));
58+
return findAll ? textLookupResults.queryAll() : textLookupResults.query();
59+
case XPATH:
60+
XPathFinder xPathFinder = new XPathFinder();
61+
return findAll ? xPathFinder.findAll(lookupQuery, root) : xPathFinder.find(lookupQuery, root);
62+
case PSEUDO:
63+
NodeQuery pseudoLookupResults = pseudoLookup(root, lookupQuery);
64+
return findAll ? pseudoLookupResults.queryAll() : pseudoLookupResults.query();
65+
}
66+
throw new IllegalArgumentException("FindPrefix value " + prefix + " of query " + query + " is not supported");
67+
}
68+
69+
private NodeQuery pseudoLookup(Parent root, String query) {
70+
String[] queries = query.split(";");
71+
return robot.from(root).lookup((Node n) -> {
72+
int matching = 0;
73+
ObservableSet<PseudoClass> pseudoStates = n.getPseudoClassStates();
74+
75+
for (PseudoClass c : pseudoStates)
76+
for (String q : queries)
77+
if (c.getPseudoClassName().equals(q))
78+
matching++;
79+
80+
return n != root && (matching == queries.length);
81+
});
82+
}
83+
84+
private NodeQuery classLookup(Parent root, String query) {
85+
try {
86+
Class<?> clazz = Class.forName(query);
87+
InstanceOfMatcher matcher = new InstanceOfMatcher(clazz);
88+
return robot.from(root).lookup(matcher);
89+
} catch (ClassNotFoundException e) {
90+
throw new JavaFXLibraryNonFatalException("Could not use \"" + query + "\" for " +
91+
"Node lookup: class was not found");
92+
}
93+
}
94+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2017-2018 Eficode Oy
3+
* Copyright 2018- Robot Framework Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package javafxlibrary.utils.finder;
19+
20+
public enum FindPrefix { ID, CSS, CLASS, TEXT, XPATH, PSEUDO }

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

Lines changed: 21 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1+
/*
2+
* Copyright 2017-2018 Eficode Oy
3+
* Copyright 2018- Robot Framework Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
118
package javafxlibrary.utils.finder;
219

3-
import javafx.collections.ObservableSet;
4-
import javafx.css.PseudoClass;
520
import javafx.scene.Node;
621
import javafx.scene.Parent;
722
import javafx.stage.Window;
8-
import javafxlibrary.exceptions.JavaFXLibraryNonFatalException;
9-
import javafxlibrary.matchers.InstanceOfMatcher;
1023
import javafxlibrary.utils.RobotLog;
1124
import javafxlibrary.utils.TestFxAdapter;
1225
import org.testfx.api.FxRobotInterface;
13-
import org.testfx.matcher.control.LabeledMatchers;
14-
import org.testfx.service.query.NodeQuery;
1526

1627
import java.util.*;
1728

18-
// import static javafxlibrary.utils.TestFxAdapter.robot;
19-
2029
public class Finder {
2130

22-
public enum FindPrefix { ID, CSS, CLASS, TEXT, XPATH, PSEUDO }
23-
2431
private String[] queries;
2532
private Set<Node> results = new LinkedHashSet<>();
2633
private FxRobotInterface robot;
@@ -141,98 +148,14 @@ private Set<Node> findAll(Parent root, int queryIndex) {
141148

142149
private Node executeFind(Parent root, String query) {
143150
RobotLog.debug("Executing find with root: " + root + " and query: " + query);
144-
FindPrefix prefix = getPrefix(query);
145-
146-
switch (prefix) {
147-
case ID:
148-
return root.lookup("#" + query.substring(3));
149-
case CSS:
150-
return root.lookup(query.substring(4));
151-
case CLASS:
152-
return classLookup(root, query).query();
153-
case TEXT:
154-
query = query.substring(6, query.length() - 1);
155-
return robot.from(root).lookup(LabeledMatchers.hasText(query)).query();
156-
case XPATH:
157-
return new XPathFinder().find(query.substring(6), root);
158-
case PSEUDO:
159-
return pseudoLookup(root, query).query();
160-
}
161-
throw new IllegalArgumentException("FindPrefix value " + prefix + " of query " + query + " is not supported");
151+
FindOperation findOperation = new FindOperation(root, new Query(query), false);
152+
return (Node) findOperation.executeLookup();
162153
}
163154

164155
// TODO: Add support for using indexes in queries (css=VBox[3]), xPath already implements this
165156
private Set<Node> executeFindAll(Parent root, String query) {
166157
RobotLog.debug("Executing find all with root: " + root + " and query: " + query);
167-
FindPrefix prefix = getPrefix(query);
168-
169-
switch (prefix) {
170-
case ID:
171-
return root.lookupAll("#" + query.substring(3));
172-
case CSS:
173-
return root.lookupAll(query.substring(4));
174-
case CLASS:
175-
return classLookup(root, query).queryAll();
176-
case TEXT:
177-
query = query.substring(6, query.length() - 1);
178-
return robot.from(root).lookup(LabeledMatchers.hasText(query)).queryAll();
179-
case XPATH:
180-
return new XPathFinder().findAll(query.substring(6), root);
181-
case PSEUDO:
182-
return pseudoLookup(root, query).queryAll();
183-
}
184-
throw new IllegalArgumentException("FindPrefix value " + prefix + " of query " + query + " is not supported");
185-
}
186-
187-
protected FindPrefix getPrefix(String query) {
188-
189-
try {
190-
String prefix = query.substring(0, query.indexOf('='));
191-
192-
switch (prefix) {
193-
case "id":
194-
return FindPrefix.ID;
195-
case "css":
196-
return FindPrefix.CSS;
197-
case "class":
198-
return FindPrefix.CLASS;
199-
case "text":
200-
return FindPrefix.TEXT;
201-
case "xpath":
202-
return FindPrefix.XPATH;
203-
case "pseudo":
204-
return FindPrefix.PSEUDO;
205-
default:
206-
throw new IllegalArgumentException("Query \"" + query + "\" does not contain any supported prefix");
207-
}
208-
} catch (StringIndexOutOfBoundsException e) {
209-
throw new IllegalArgumentException("Query \"" + query + "\" does not contain any supported prefix");
210-
}
211-
}
212-
213-
private NodeQuery pseudoLookup(Parent root, String query) {
214-
String[] queries = query.substring(7).split(";");
215-
return robot.from(root).lookup((Node n) -> {
216-
int matching = 0;
217-
ObservableSet<PseudoClass> pseudoStates = n.getPseudoClassStates();
218-
219-
for (PseudoClass c : pseudoStates)
220-
for (String q : queries)
221-
if (c.getPseudoClassName().equals(q))
222-
matching++;
223-
224-
return n != root && (matching == queries.length);
225-
});
226-
}
227-
228-
private NodeQuery classLookup(Parent root, String query) {
229-
try {
230-
Class<?> clazz = Class.forName(query.substring(6));
231-
InstanceOfMatcher matcher = new InstanceOfMatcher(clazz);
232-
return robot.from(root).lookup(matcher);
233-
} catch (ClassNotFoundException e) {
234-
throw new JavaFXLibraryNonFatalException("Could not use \"" + query.substring(6) + "\" for " +
235-
"Node lookup: class was not found");
236-
}
158+
FindOperation findOperation = new FindOperation(root, new Query(query), true);
159+
return (Set<Node>) findOperation.executeLookup();
237160
}
238161
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2017-2018 Eficode Oy
3+
* Copyright 2018- Robot Framework Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package javafxlibrary.utils.finder;
19+
20+
public class Query {
21+
22+
private FindPrefix prefix;
23+
private String query;
24+
25+
public Query(String query) {
26+
this.prefix = QueryParser.getPrefix(query);
27+
this.query = QueryParser.removePrefix(query, this.prefix);
28+
}
29+
30+
public FindPrefix getPrefix() {
31+
return this.prefix;
32+
}
33+
34+
public String getQuery() {
35+
return this.query;
36+
}
37+
}

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
/*
2+
* Copyright 2017-2018 Eficode Oy
3+
* Copyright 2018- Robot Framework Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
118
package javafxlibrary.utils.finder;
219

320
import java.util.ArrayList;
@@ -61,4 +78,47 @@ protected static boolean startsWithPrefix(String query) {
6178
return true;
6279
return false;
6380
}
81+
82+
protected static FindPrefix getPrefix(String query) {
83+
84+
try {
85+
String prefix = query.substring(0, query.indexOf('='));
86+
87+
switch (prefix) {
88+
case "id":
89+
return FindPrefix.ID;
90+
case "css":
91+
return FindPrefix.CSS;
92+
case "class":
93+
return FindPrefix.CLASS;
94+
case "text":
95+
return FindPrefix.TEXT;
96+
case "xpath":
97+
return FindPrefix.XPATH;
98+
case "pseudo":
99+
return FindPrefix.PSEUDO;
100+
default:
101+
throw new IllegalArgumentException("Query \"" + query + "\" does not contain any supported prefix");
102+
}
103+
} catch (StringIndexOutOfBoundsException e) {
104+
throw new IllegalArgumentException("Query \"" + query + "\" does not contain any supported prefix");
105+
}
106+
}
107+
108+
protected static String removePrefix(String query, FindPrefix prefix) {
109+
switch (prefix) {
110+
case ID:
111+
return "#" + query.substring(3);
112+
case CSS:
113+
return query.substring(4);
114+
case CLASS:
115+
case XPATH:
116+
return query.substring(6);
117+
case TEXT:
118+
return query.substring(6, query.length() - 1);
119+
case PSEUDO:
120+
return query.substring(7);
121+
}
122+
throw new IllegalArgumentException("FindPrefix value " + prefix + " of query " + query + " is not supported");
123+
}
64124
}

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

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,28 +81,4 @@ public void find_CustomRoot_TestFXSelector() {
8181
Node result = finder.find(".button", group);
8282
Assert.assertEquals(button, result);
8383
}
84-
85-
@Test
86-
public void getPrefix_AcceptedValues() {
87-
Assert.assertEquals(Finder.FindPrefix.ID, finder.getPrefix("id=nodeId"));
88-
Assert.assertEquals(Finder.FindPrefix.CLASS, finder.getPrefix("class=java.lang.String"));
89-
Assert.assertEquals(Finder.FindPrefix.CSS, finder.getPrefix("css=.vBox .hBox"));
90-
Assert.assertEquals(Finder.FindPrefix.XPATH, finder.getPrefix("xpath=//Rectangle[@id=\"lime\"]"));
91-
Assert.assertEquals(Finder.FindPrefix.PSEUDO, finder.getPrefix("pseudo=hover"));
92-
Assert.assertEquals(Finder.FindPrefix.TEXT, finder.getPrefix("text=\"Text\""));
93-
}
94-
95-
@Test
96-
public void getPrefix_NoEquals() {
97-
thrown.expect(IllegalArgumentException.class);
98-
thrown.expectMessage("Query \"noEquals\" does not contain any supported prefix");
99-
finder.getPrefix("noEquals");
100-
}
101-
102-
@Test
103-
public void getPrefix_InvalidValue() {
104-
thrown.expect(IllegalArgumentException.class);
105-
thrown.expectMessage("Query \"notaprefix=someValue\" does not contain any supported prefix");
106-
finder.getPrefix("notaprefix=someValue");
107-
}
10884
}

0 commit comments

Comments
 (0)