testautoa 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +7 -7
- data/bin/calabash-android +8 -1
- data/bin/calabash-android-build.rb +1 -1
- data/bin/calabash-android-console.rb +4 -4
- data/bin/calabash-android-run.rb +2 -10
- data/bin/testautoa +461 -0
- data/calabash-android.gemspec +3 -1
- data/features-skeleton/support/app_life_cycle_hooks.rb +0 -1
- data/irbrc +3 -1
- data/lib/calabash-android/helpers.rb +45 -17
- data/lib/calabash-android/lib/TestServer.apk +0 -0
- data/lib/calabash-android/lib/unsign.jar +0 -0
- data/lib/calabash-android/operations.rb +150 -66
- data/lib/calabash-android/steps/list_steps.rb +1 -1
- data/lib/calabash-android/steps/time_picker_steps.rb +1 -1
- data/lib/calabash-android/touch_helpers.rb +9 -0
- data/lib/calabash-android/version.rb +1 -1
- data/lib/calabash-android/wait_helpers.rb +93 -0
- data/test-server/AndroidManifest.xml +2 -0
- data/test-server/build.xml +1 -0
- data/test-server/instrumentation-backend/.classpath +0 -1
- data/test-server/instrumentation-backend/AndroidManifest.xml +1 -1
- data/test-server/instrumentation-backend/antlr/UIQuery.g +48 -5
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Command.java +4 -3
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/FranklyResult.java +95 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +7 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java +14 -29
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/FinishOpenedActivities.java +19 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/GetOpenedActivities.java +31 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/GoBackToActivity.java +67 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/DragCoordinates.java +28 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/Swipe.java +11 -5
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/location/FakeGPSLocation.java +13 -10
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/LeftKey.java +24 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/RightKey.java +24 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/UpKey.java +24 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/version/Version.java +31 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/CalabashChromeClient.java +131 -36
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpBodyHtml.java +38 -18
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpHtml.java +38 -16
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/EnterTextByCssSelector.java +94 -66
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteAsyncJavascript.java +55 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteJavascript.java +53 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +44 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +52 -27
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +39 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ScrollTo.java +56 -41
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetPropertyByCssSelector.java +50 -25
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +19 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/CompletedFuture.java +40 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/InvocationOperation.java +222 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Operation.java +7 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/PropertyOperation.java +56 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Query.java +151 -43
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQuery.tokens +19 -12
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQueryResultVoid.java +22 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +41 -11
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryLexer.java +1010 -242
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryParser.java +406 -98
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/BeginsWithRelation.java +45 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ComparisonOperator.java +54 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ContainsRelation.java +41 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/EndsWithRelation.java +42 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/LikeRelation.java +79 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/PartialFutureList.java +100 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryAST.java +1 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTClassName.java +54 -25
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicate.java +147 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicateRelation.java +5 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +153 -89
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryDirection.java +12 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryEvaluator.java +58 -141
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +162 -7
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryVisibility.java +32 -0
- metadata +130 -97
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Query.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Touch.java +0 -44
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQuery.tokens +0 -10
- data/test-server/instrumentation-backend/tests/sh/calaba/instrumentationbackend/query/tests/UIQueryTest.java +0 -134
@@ -0,0 +1,45 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
import android.annotation.SuppressLint;
|
4
|
+
|
5
|
+
public class BeginsWithRelation implements UIQueryASTPredicateRelation {
|
6
|
+
|
7
|
+
private final boolean caseSensitive;
|
8
|
+
|
9
|
+
public BeginsWithRelation(boolean isCaseSensitive) {
|
10
|
+
super();
|
11
|
+
this.caseSensitive = isCaseSensitive;
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
public boolean isCaseSensitive() {
|
16
|
+
return caseSensitive;
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Does firstValue BEGIN WITH secondValue?
|
21
|
+
*/
|
22
|
+
@SuppressLint("DefaultLocale")
|
23
|
+
@Override
|
24
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
25
|
+
if (firstValue == secondValue) {
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
if (firstValue == null || secondValue == null) {
|
29
|
+
return false;
|
30
|
+
}
|
31
|
+
if (firstValue instanceof CharSequence && secondValue instanceof CharSequence) {
|
32
|
+
String firstStr = firstValue.toString();
|
33
|
+
String secondStr = secondValue.toString();
|
34
|
+
if (!isCaseSensitive()) {
|
35
|
+
firstStr = firstStr.toLowerCase();
|
36
|
+
secondStr = secondStr.toLowerCase();
|
37
|
+
}
|
38
|
+
return firstStr.startsWith(secondStr);
|
39
|
+
}
|
40
|
+
else {
|
41
|
+
return false;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
public enum ComparisonOperator implements UIQueryASTPredicateRelation {
|
4
|
+
|
5
|
+
LESSTHAN {
|
6
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
7
|
+
if (areNumbers(firstValue, secondValue)) {
|
8
|
+
Number firstNum = (Number) firstValue;
|
9
|
+
Number secondNum = (Number) secondValue;
|
10
|
+
return firstNum.doubleValue() < secondNum.doubleValue();
|
11
|
+
} else {
|
12
|
+
return false;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
},
|
16
|
+
|
17
|
+
LESSTHANOREQUAL {
|
18
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
19
|
+
return EQUAL.areRelated(firstValue, secondValue) || LESSTHAN.areRelated(firstValue, secondValue);
|
20
|
+
}
|
21
|
+
},
|
22
|
+
|
23
|
+
EQUAL {
|
24
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
25
|
+
if (firstValue == secondValue) {
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
return (firstValue != null) && firstValue.equals(secondValue);
|
29
|
+
}
|
30
|
+
},
|
31
|
+
|
32
|
+
GREATERTHAN {
|
33
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
34
|
+
if (areNumbers(firstValue, secondValue)) {
|
35
|
+
Number firstNum = (Number) firstValue;
|
36
|
+
Number secondNum = (Number) secondValue;
|
37
|
+
return firstNum.doubleValue() > secondNum.doubleValue();
|
38
|
+
} else {
|
39
|
+
return false;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
},
|
43
|
+
|
44
|
+
GREATERTHANOREQUAL {
|
45
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
46
|
+
return EQUAL.areRelated(firstValue, secondValue) || GREATERTHAN.areRelated(firstValue, secondValue);
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
protected boolean areNumbers(Object firstValue, Object secondValue) {
|
51
|
+
return (firstValue instanceof Number && secondValue instanceof Number);
|
52
|
+
}
|
53
|
+
|
54
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
public class ContainsRelation implements UIQueryASTPredicateRelation {
|
4
|
+
|
5
|
+
private final boolean caseSensitive;
|
6
|
+
|
7
|
+
public ContainsRelation(boolean isCaseSensitive) {
|
8
|
+
super();
|
9
|
+
this.caseSensitive = isCaseSensitive;
|
10
|
+
}
|
11
|
+
|
12
|
+
public boolean isCaseSensitive() {
|
13
|
+
return caseSensitive;
|
14
|
+
}
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Does firstValue CONTAIN secondValue?
|
18
|
+
*/
|
19
|
+
@Override
|
20
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
21
|
+
if (firstValue == secondValue) {
|
22
|
+
return true;
|
23
|
+
}
|
24
|
+
if (firstValue == null || secondValue == null) {
|
25
|
+
return false;
|
26
|
+
}
|
27
|
+
if (firstValue instanceof CharSequence && secondValue instanceof CharSequence) {
|
28
|
+
String firstStr = firstValue.toString();
|
29
|
+
String secondStr = secondValue.toString();
|
30
|
+
if (!isCaseSensitive()) {
|
31
|
+
firstStr = firstStr.toLowerCase();
|
32
|
+
secondStr = secondStr.toLowerCase();
|
33
|
+
}
|
34
|
+
return firstStr.indexOf(secondStr) != -1;
|
35
|
+
}
|
36
|
+
else {
|
37
|
+
return false;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
public class EndsWithRelation implements UIQueryASTPredicateRelation {
|
4
|
+
|
5
|
+
private final boolean caseSensitive;
|
6
|
+
|
7
|
+
public EndsWithRelation(boolean isCaseSensitive) {
|
8
|
+
super();
|
9
|
+
this.caseSensitive = isCaseSensitive;
|
10
|
+
}
|
11
|
+
|
12
|
+
public boolean isCaseSensitive() {
|
13
|
+
return caseSensitive;
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Does firstValue END WITH secondValue?
|
19
|
+
*/
|
20
|
+
@Override
|
21
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
22
|
+
if (firstValue == secondValue) {
|
23
|
+
return true;
|
24
|
+
}
|
25
|
+
if (firstValue == null || secondValue == null) {
|
26
|
+
return false;
|
27
|
+
}
|
28
|
+
if (firstValue instanceof CharSequence && secondValue instanceof CharSequence) {
|
29
|
+
String firstStr = firstValue.toString();
|
30
|
+
String secondStr = secondValue.toString();
|
31
|
+
if (!isCaseSensitive()) {
|
32
|
+
firstStr = firstStr.toLowerCase();
|
33
|
+
secondStr = secondStr.toLowerCase();
|
34
|
+
}
|
35
|
+
return firstStr.endsWith(secondStr);
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
return false;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
import java.util.regex.Matcher;
|
4
|
+
import java.util.regex.Pattern;
|
5
|
+
|
6
|
+
public class LikeRelation implements UIQueryASTPredicateRelation {
|
7
|
+
|
8
|
+
private final boolean caseSensitive;
|
9
|
+
|
10
|
+
public LikeRelation(boolean isCaseSensitive) {
|
11
|
+
super();
|
12
|
+
this.caseSensitive = isCaseSensitive;
|
13
|
+
}
|
14
|
+
|
15
|
+
public boolean isCaseSensitive() {
|
16
|
+
return caseSensitive;
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Is firstValue LIKE secondValue? In this case secondValue is a pattern ala
|
21
|
+
* 'Cou* Down' which will match a string 'Count Down'.
|
22
|
+
*/
|
23
|
+
@Override
|
24
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
25
|
+
if (firstValue == secondValue) {
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
if (firstValue == null || secondValue == null) {
|
29
|
+
return false;
|
30
|
+
}
|
31
|
+
if (firstValue instanceof CharSequence
|
32
|
+
&& secondValue instanceof CharSequence) {
|
33
|
+
String firstStr = firstValue.toString();
|
34
|
+
String patternStr = secondValue.toString();
|
35
|
+
Matcher matcher = matcherFrom(patternStr, firstStr);
|
36
|
+
return matcher.matches();
|
37
|
+
} else {
|
38
|
+
return false;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
private Matcher matcherFrom(String patternStr, String stringToMatch) {
|
43
|
+
Pattern compiledPat;
|
44
|
+
if (isCaseSensitive()) {
|
45
|
+
compiledPat = Pattern.compile(translatePatternString(patternStr));
|
46
|
+
} else {
|
47
|
+
compiledPat = Pattern.compile(translatePatternString(patternStr),
|
48
|
+
Pattern.CASE_INSENSITIVE);
|
49
|
+
}
|
50
|
+
return compiledPat.matcher(stringToMatch);
|
51
|
+
}
|
52
|
+
|
53
|
+
private String translatePatternString(String patternStr) {
|
54
|
+
|
55
|
+
StringBuilder converted = new StringBuilder();
|
56
|
+
int beginAt = 0;
|
57
|
+
for (int i = 0; i < patternStr.length(); i++) {
|
58
|
+
char charAti = patternStr.charAt(i);
|
59
|
+
if (charAti == '*' || charAti == '%') {
|
60
|
+
String subString = patternStr.substring(beginAt, i);
|
61
|
+
beginAt = i + 1;
|
62
|
+
converted.append(Pattern.quote(subString));
|
63
|
+
if (charAti == '*') {
|
64
|
+
converted.append(".*");
|
65
|
+
} else if (charAti == '%') {
|
66
|
+
converted.append(".");
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
if (beginAt < patternStr.length()) {
|
71
|
+
String subString = patternStr.substring(beginAt,
|
72
|
+
patternStr.length());
|
73
|
+
converted.append(Pattern.quote(subString));
|
74
|
+
}
|
75
|
+
|
76
|
+
return "^" + converted.toString() + "$";
|
77
|
+
}
|
78
|
+
|
79
|
+
}
|
@@ -0,0 +1,100 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.List;
|
5
|
+
import java.util.concurrent.ExecutionException;
|
6
|
+
import java.util.concurrent.Future;
|
7
|
+
import java.util.concurrent.TimeUnit;
|
8
|
+
import java.util.concurrent.TimeoutException;
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Represents a List where at most one result is a Future.
|
12
|
+
* This class is itself a Future which is realized if the list contains no future,
|
13
|
+
* and if the list does contain a Future, this object is realized once that Future is.
|
14
|
+
*
|
15
|
+
* We can think of it as a way to "lift" a list containing a Future into the set of Futures.
|
16
|
+
* @author krukow
|
17
|
+
*
|
18
|
+
*/
|
19
|
+
@SuppressWarnings("rawtypes")
|
20
|
+
public class PartialFutureList implements Future {
|
21
|
+
|
22
|
+
|
23
|
+
private final Future theFutureResult;
|
24
|
+
private final List originalList;
|
25
|
+
|
26
|
+
public PartialFutureList(List listWithOneFuture) {
|
27
|
+
this.theFutureResult = extractFuture(listWithOneFuture);
|
28
|
+
this.originalList = listWithOneFuture;
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
@Override
|
33
|
+
public boolean cancel(boolean mayInterruptIfRunning) {
|
34
|
+
if (theFutureResult == null) {
|
35
|
+
return false;
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
return theFutureResult.cancel(mayInterruptIfRunning);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
@Override
|
43
|
+
public Object get() throws InterruptedException, ExecutionException {
|
44
|
+
if (theFutureResult == null) {
|
45
|
+
return originalList;
|
46
|
+
}
|
47
|
+
return fillListWithResult(theFutureResult.get());
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
@Override
|
52
|
+
public Object get(long timeout, TimeUnit unit) throws InterruptedException,
|
53
|
+
ExecutionException, TimeoutException {
|
54
|
+
if (theFutureResult == null) {
|
55
|
+
return originalList;
|
56
|
+
}
|
57
|
+
return fillListWithResult(theFutureResult.get(timeout,unit));
|
58
|
+
}
|
59
|
+
|
60
|
+
@Override
|
61
|
+
public boolean isCancelled() {
|
62
|
+
if (theFutureResult == null) {
|
63
|
+
return false;
|
64
|
+
}
|
65
|
+
return theFutureResult.isCancelled();
|
66
|
+
}
|
67
|
+
|
68
|
+
@Override
|
69
|
+
public boolean isDone() {
|
70
|
+
if (theFutureResult == null) {
|
71
|
+
return false;
|
72
|
+
}
|
73
|
+
return theFutureResult.isDone();
|
74
|
+
}
|
75
|
+
|
76
|
+
@SuppressWarnings({ "unchecked" })
|
77
|
+
private Object fillListWithResult(Object futureResultObject) {
|
78
|
+
List result = new ArrayList(this.originalList.size());
|
79
|
+
for (Object o : this.originalList) {
|
80
|
+
if (o instanceof Future) {//Assume only one future
|
81
|
+
result.add(futureResultObject);
|
82
|
+
} else {
|
83
|
+
result.add(o);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return result;
|
87
|
+
}
|
88
|
+
|
89
|
+
private Future extractFuture(List evaluateWithViews) {
|
90
|
+
for (Object o : evaluateWithViews) {
|
91
|
+
if (o instanceof Future) {
|
92
|
+
return (Future) o;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
return null;
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
}
|
@@ -4,5 +4,5 @@ import java.util.List;
|
|
4
4
|
|
5
5
|
public interface UIQueryAST {
|
6
6
|
@SuppressWarnings("rawtypes")
|
7
|
-
public List
|
7
|
+
public List evaluateWithViews(List inputViews, UIQueryDirection direction, UIQueryVisibility visibility);
|
8
8
|
}
|
@@ -2,6 +2,9 @@ package sh.calaba.instrumentationbackend.query.ast;
|
|
2
2
|
|
3
3
|
import java.util.ArrayList;
|
4
4
|
import java.util.List;
|
5
|
+
import java.util.concurrent.Callable;
|
6
|
+
|
7
|
+
import android.view.View;
|
5
8
|
|
6
9
|
public class UIQueryASTClassName implements UIQueryAST {
|
7
10
|
public final String simpleClassName;
|
@@ -20,42 +23,68 @@ public class UIQueryASTClassName implements UIQueryAST {
|
|
20
23
|
{
|
21
24
|
if (qualifiedClassName == null) {throw new IllegalArgumentException("Cannot instantiate with null class");}
|
22
25
|
this.qualifiedClassName = qualifiedClassName;
|
23
|
-
this.simpleClassName = null;
|
24
|
-
|
26
|
+
this.simpleClassName = null;
|
25
27
|
}
|
26
28
|
|
27
29
|
@SuppressWarnings({ "rawtypes"})
|
28
30
|
@Override
|
29
|
-
public List
|
30
|
-
UIQueryDirection direction) {
|
31
|
-
// TODO Auto-generated method stub
|
31
|
+
public List evaluateWithViews(final List inputViews,
|
32
|
+
final UIQueryDirection direction, final UIQueryVisibility visibility) {
|
32
33
|
|
33
|
-
List
|
34
|
-
for (Object o : inputViews)
|
35
|
-
{
|
36
|
-
switch(direction) {
|
37
|
-
case DESCENDANT:
|
38
|
-
addDecendantMatchesToResult(o,result);
|
39
|
-
break;
|
40
|
-
case CHILD:
|
41
|
-
addChildMatchesToResult(o,result);
|
42
|
-
break;
|
43
|
-
case PARENT:
|
44
|
-
addParentMatchesToResult(o,result);
|
45
|
-
break;
|
46
|
-
}
|
47
|
-
|
34
|
+
return (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
|
48
35
|
|
49
|
-
|
36
|
+
public Object call() throws Exception {
|
37
|
+
List result = new ArrayList(8);
|
38
|
+
for (Object o : inputViews)
|
39
|
+
{
|
40
|
+
switch(direction) {
|
41
|
+
case DESCENDANT:
|
42
|
+
addDecendantMatchesToResult(o,result);
|
43
|
+
break;
|
44
|
+
case CHILD:
|
45
|
+
addChildMatchesToResult(o,result);
|
46
|
+
break;
|
47
|
+
case PARENT:
|
48
|
+
addParentMatchesToResult(o,result);
|
49
|
+
break;
|
50
|
+
case SIBLING:
|
51
|
+
addSiblingMatchesToResult(o,result);
|
52
|
+
break;
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
}
|
57
|
+
|
58
|
+
List filteredResult = visibility.evaluateWithViews(result, direction, visibility);
|
59
|
+
return filteredResult;
|
60
|
+
}
|
61
|
+
});
|
50
62
|
|
51
63
|
|
52
|
-
return result;
|
53
64
|
}
|
54
65
|
|
55
|
-
@SuppressWarnings("rawtypes")
|
66
|
+
@SuppressWarnings({ "rawtypes", "unchecked" })
|
67
|
+
protected void addSiblingMatchesToResult(Object o, List result) {
|
68
|
+
List parents = UIQueryUtils.parents(o);
|
69
|
+
if (parents != null && !parents.isEmpty()) {
|
70
|
+
Object immediateParent = parents.get(0);
|
71
|
+
for (Object v : UIQueryUtils.subviews(immediateParent)) {
|
72
|
+
if (v != o && match(v)) {
|
73
|
+
result.add(v);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
@SuppressWarnings({ "rawtypes", "unchecked" })
|
56
80
|
private void addParentMatchesToResult(Object o, List result) {
|
57
|
-
|
58
|
-
|
81
|
+
for (Object parent : UIQueryUtils.parents(o))
|
82
|
+
{
|
83
|
+
if (match(parent))
|
84
|
+
{
|
85
|
+
result.add(parent);
|
86
|
+
}
|
87
|
+
}
|
59
88
|
}
|
60
89
|
|
61
90
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@@ -0,0 +1,147 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query.ast;
|
2
|
+
|
3
|
+
import java.lang.reflect.Method;
|
4
|
+
import java.util.ArrayList;
|
5
|
+
import java.util.List;
|
6
|
+
import java.util.Map;
|
7
|
+
import java.util.concurrent.Callable;
|
8
|
+
|
9
|
+
import org.antlr.runtime.tree.CommonTree;
|
10
|
+
|
11
|
+
import android.view.View;
|
12
|
+
|
13
|
+
public class UIQueryASTPredicate implements UIQueryAST {
|
14
|
+
|
15
|
+
private final String propertyName;
|
16
|
+
private final UIQueryASTPredicateRelation relation;
|
17
|
+
private final Object valueToMatch;
|
18
|
+
|
19
|
+
public UIQueryASTPredicate(String text,
|
20
|
+
UIQueryASTPredicateRelation parsedRelation, Object parsedValue) {
|
21
|
+
this.propertyName = text;
|
22
|
+
this.relation = parsedRelation;
|
23
|
+
this.valueToMatch = parsedValue;
|
24
|
+
}
|
25
|
+
|
26
|
+
@SuppressWarnings("rawtypes")
|
27
|
+
@Override
|
28
|
+
public List evaluateWithViews(final List inputViews,
|
29
|
+
final UIQueryDirection direction, final UIQueryVisibility visibility) {
|
30
|
+
return (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
|
31
|
+
|
32
|
+
@SuppressWarnings("unchecked")
|
33
|
+
@Override
|
34
|
+
public Object call() throws Exception {
|
35
|
+
List filteredResult = new ArrayList(16);
|
36
|
+
for (int i = 0; i < inputViews.size(); i++) {
|
37
|
+
Object o = inputViews.get(i);
|
38
|
+
|
39
|
+
if (o instanceof Map) {
|
40
|
+
Map result = evaluateForMap((Map) o);
|
41
|
+
if (result != null) {
|
42
|
+
filteredResult.add(result);
|
43
|
+
}
|
44
|
+
|
45
|
+
} else {
|
46
|
+
Object result = evaluateForObject(o, i);
|
47
|
+
if (result != null) {
|
48
|
+
filteredResult.add(result);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
}
|
53
|
+
|
54
|
+
return visibility.evaluateWithViews(filteredResult, direction, visibility);
|
55
|
+
}
|
56
|
+
});
|
57
|
+
}
|
58
|
+
|
59
|
+
@SuppressWarnings("rawtypes")
|
60
|
+
private Map evaluateForMap(Map map) {
|
61
|
+
if (map.containsKey(this.propertyName)) {
|
62
|
+
Object value = map.get(this.propertyName);
|
63
|
+
if (this.relation.areRelated(value, this.valueToMatch)) {
|
64
|
+
return map;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return null;
|
68
|
+
}
|
69
|
+
|
70
|
+
private Object evaluateForObject(Object o, int index) {
|
71
|
+
if (o instanceof View && this.propertyName.equals("id")) {
|
72
|
+
View view = (View) o;
|
73
|
+
String id = UIQueryUtils.getId(view);
|
74
|
+
if (this.relation.areRelated(id, this.valueToMatch)) {
|
75
|
+
return o;
|
76
|
+
} else {
|
77
|
+
// let it fall through and check via general property access
|
78
|
+
// in case the user actually wants to compre the real value of
|
79
|
+
// getId()
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
Method propertyAccessor = UIQueryUtils
|
84
|
+
.hasProperty(o, this.propertyName);
|
85
|
+
if (propertyAccessor == null) {
|
86
|
+
return null;
|
87
|
+
}
|
88
|
+
Object value = UIQueryUtils.getProperty(o, propertyAccessor);
|
89
|
+
|
90
|
+
if (this.relation.areRelated(value, this.valueToMatch)) {
|
91
|
+
return o;
|
92
|
+
} else if (this.valueToMatch instanceof String
|
93
|
+
&& this.relation
|
94
|
+
.areRelated(value.toString(), this.valueToMatch)) {
|
95
|
+
return o;
|
96
|
+
} else {
|
97
|
+
return null;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
public static UIQueryASTPredicate newPredicateFromAST(CommonTree step) {
|
102
|
+
// TODO Auto-generated method stub
|
103
|
+
if (step.getChildCount() != 3) {
|
104
|
+
throw new IllegalStateException("Bad Predicate query: "+step+". Expected form {getter RELATION value}.");
|
105
|
+
}
|
106
|
+
CommonTree prop = (CommonTree) step.getChild(0);
|
107
|
+
CommonTree rel = (CommonTree) step.getChild(1);
|
108
|
+
CommonTree val = (CommonTree) step.getChild(2);
|
109
|
+
return new UIQueryASTPredicate(prop.getText(),
|
110
|
+
UIQueryASTPredicate.parseRelation(rel),
|
111
|
+
UIQueryUtils.parseValue(val));
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
private static UIQueryASTPredicateRelation parseRelation(CommonTree rel) {
|
116
|
+
String relText = rel.getText().toUpperCase();
|
117
|
+
boolean caseSensitive = true;
|
118
|
+
final String CASE_INSENSITIVE_SPEC = "[C]";
|
119
|
+
if (relText.endsWith(CASE_INSENSITIVE_SPEC)) {
|
120
|
+
caseSensitive = false;
|
121
|
+
relText = relText.substring(0,relText.length() - CASE_INSENSITIVE_SPEC.length());
|
122
|
+
}
|
123
|
+
|
124
|
+
if ("BEGINSWITH".equals(relText)) {
|
125
|
+
return new BeginsWithRelation(caseSensitive);
|
126
|
+
} else if ("ENDSWITH".equals(relText)) {
|
127
|
+
return new EndsWithRelation(caseSensitive);
|
128
|
+
} else if ("CONTAINS".equals(relText)) {
|
129
|
+
return new ContainsRelation(caseSensitive);
|
130
|
+
} else if ("LIKE".equals(relText)) {
|
131
|
+
return new LikeRelation(caseSensitive);
|
132
|
+
} else if ("<".equals(relText)) {
|
133
|
+
return ComparisonOperator.LESSTHAN;
|
134
|
+
} else if ("<=".equals(relText)) {
|
135
|
+
return ComparisonOperator.LESSTHANOREQUAL;
|
136
|
+
} else if ("=".equals(relText)) {
|
137
|
+
return ComparisonOperator.EQUAL;
|
138
|
+
} else if (">".equals(relText)) {
|
139
|
+
return ComparisonOperator.GREATERTHAN;
|
140
|
+
} else if (">=".equals(relText)) {
|
141
|
+
return ComparisonOperator.GREATERTHANOREQUAL;
|
142
|
+
} else {
|
143
|
+
throw new IllegalStateException("Unsupported Relation: " + relText);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
}
|