testautoa 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }