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.
Files changed (79) hide show
  1. data/Rakefile +7 -7
  2. data/bin/calabash-android +8 -1
  3. data/bin/calabash-android-build.rb +1 -1
  4. data/bin/calabash-android-console.rb +4 -4
  5. data/bin/calabash-android-run.rb +2 -10
  6. data/bin/testautoa +461 -0
  7. data/calabash-android.gemspec +3 -1
  8. data/features-skeleton/support/app_life_cycle_hooks.rb +0 -1
  9. data/irbrc +3 -1
  10. data/lib/calabash-android/helpers.rb +45 -17
  11. data/lib/calabash-android/lib/TestServer.apk +0 -0
  12. data/lib/calabash-android/lib/unsign.jar +0 -0
  13. data/lib/calabash-android/operations.rb +150 -66
  14. data/lib/calabash-android/steps/list_steps.rb +1 -1
  15. data/lib/calabash-android/steps/time_picker_steps.rb +1 -1
  16. data/lib/calabash-android/touch_helpers.rb +9 -0
  17. data/lib/calabash-android/version.rb +1 -1
  18. data/lib/calabash-android/wait_helpers.rb +93 -0
  19. data/test-server/AndroidManifest.xml +2 -0
  20. data/test-server/build.xml +1 -0
  21. data/test-server/instrumentation-backend/.classpath +0 -1
  22. data/test-server/instrumentation-backend/AndroidManifest.xml +1 -1
  23. data/test-server/instrumentation-backend/antlr/UIQuery.g +48 -5
  24. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Command.java +4 -3
  25. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/FranklyResult.java +95 -0
  26. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +7 -1
  27. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java +14 -29
  28. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/FinishOpenedActivities.java +19 -0
  29. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/GetOpenedActivities.java +31 -0
  30. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/GoBackToActivity.java +67 -0
  31. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/DragCoordinates.java +28 -0
  32. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/Swipe.java +11 -5
  33. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/location/FakeGPSLocation.java +13 -10
  34. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/LeftKey.java +24 -0
  35. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/RightKey.java +24 -0
  36. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/UpKey.java +24 -0
  37. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/version/Version.java +31 -0
  38. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/CalabashChromeClient.java +131 -36
  39. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpBodyHtml.java +38 -18
  40. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpHtml.java +38 -16
  41. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/EnterTextByCssSelector.java +94 -66
  42. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteAsyncJavascript.java +55 -33
  43. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteJavascript.java +53 -31
  44. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +44 -0
  45. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +52 -27
  46. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +39 -32
  47. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ScrollTo.java +56 -41
  48. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetPropertyByCssSelector.java +50 -25
  49. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +19 -22
  50. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/CompletedFuture.java +40 -0
  51. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/InvocationOperation.java +222 -0
  52. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Operation.java +7 -0
  53. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/PropertyOperation.java +56 -0
  54. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Query.java +151 -43
  55. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQuery.tokens +19 -12
  56. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQueryResultVoid.java +22 -0
  57. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +41 -11
  58. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryLexer.java +1010 -242
  59. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryParser.java +406 -98
  60. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/BeginsWithRelation.java +45 -0
  61. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ComparisonOperator.java +54 -0
  62. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ContainsRelation.java +41 -0
  63. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/EndsWithRelation.java +42 -0
  64. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/LikeRelation.java +79 -0
  65. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/PartialFutureList.java +100 -0
  66. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryAST.java +1 -1
  67. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTClassName.java +54 -25
  68. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicate.java +147 -0
  69. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicateRelation.java +5 -0
  70. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +153 -89
  71. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryDirection.java +12 -2
  72. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryEvaluator.java +58 -141
  73. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +162 -7
  74. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryVisibility.java +32 -0
  75. metadata +130 -97
  76. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Query.java +0 -24
  77. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Touch.java +0 -44
  78. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQuery.tokens +0 -10
  79. 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 evaluateWithViewsAndDirection(List inputViews, UIQueryDirection direction);
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 evaluateWithViewsAndDirection(List inputViews,
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 result = new ArrayList(8);
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
- // TODO Auto-generated method stub
58
- throw new UnsupportedOperationException();
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
+ }
@@ -0,0 +1,5 @@
1
+ package sh.calaba.instrumentationbackend.query.ast;
2
+
3
+ public interface UIQueryASTPredicateRelation {
4
+ public boolean areRelated(Object firstValue, Object secondValue);
5
+ }