testautoa 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|