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,222 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ import java.lang.reflect.Method;
4
+ import java.util.List;
5
+ import java.util.concurrent.atomic.AtomicReference;
6
+
7
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
8
+
9
+ public class InvocationOperation implements Operation {
10
+
11
+ private final String methodName;
12
+ @SuppressWarnings("rawtypes")
13
+ private final List arguments;
14
+ private final Class<?>[] classes;
15
+ private final Class<?>[] classesWithCharseq;
16
+
17
+ @SuppressWarnings("rawtypes")
18
+ public InvocationOperation(String methodName, List arguments) {
19
+ this.methodName = methodName;
20
+ this.arguments = arguments;
21
+ this.classes = extractArgumentTypes(false);
22
+ this.classesWithCharseq = extractArgumentTypes(true);
23
+ }
24
+
25
+ @SuppressWarnings("rawtypes")
26
+ @Override
27
+ public Object apply(final Object o) throws Exception {
28
+ final AtomicReference ref = new AtomicReference();
29
+ final AtomicReference<Exception> refEx = new AtomicReference<Exception>();
30
+
31
+ InstrumentationBackend.instrumentation.runOnMainSync(new Runnable() {
32
+
33
+ @SuppressWarnings("unchecked")
34
+ @Override
35
+ public void run() {
36
+ try {
37
+ Method method = o.getClass().getMethod(InvocationOperation.this.methodName, InvocationOperation.this.classes);
38
+ method.setAccessible(true);
39
+ try {
40
+ Object result;
41
+ if( method.getReturnType().equals(Void.TYPE)){
42
+ invokeMethod(o, method);
43
+ result = "<VOID>";
44
+ }
45
+ else {
46
+ result = invokeMethod(o, method);
47
+ }
48
+ ref.set(result);
49
+ return;
50
+ } catch (Exception e) {
51
+ refEx.set(e);
52
+ return;
53
+ }
54
+ } catch (NoSuchMethodException e) {
55
+ try {
56
+ Method method = o.getClass().getMethod(InvocationOperation.this.methodName, InvocationOperation.this.classesWithCharseq);
57
+ method.setAccessible(true);
58
+ try {
59
+ Object result;
60
+ if( method.getReturnType().equals(Void.TYPE)){
61
+ invokeMethod(o, method);
62
+ result = "<VOID>";
63
+ }
64
+ else {
65
+ result = invokeMethod(o, method);
66
+ }
67
+ ref.set(result);
68
+ return;
69
+ } catch (Exception ee) {
70
+ refEx.set(e);
71
+ return;
72
+ }
73
+ } catch (NoSuchMethodException ee) {
74
+ System.out.println("Method not found with correct argument types. Trying to type convert.");
75
+ }
76
+ }
77
+ //Warning: Slow path
78
+ Method[] methods = o.getClass().getMethods();
79
+ for (Method m : methods) {
80
+ if (m.getName().equals(InvocationOperation.this.methodName)) {
81
+ Class<?>[] parameterTypes = m.getParameterTypes();
82
+ if (parameterTypes.length == InvocationOperation.this.classes.length && areArgumentsConvertibleTo(parameterTypes)) {
83
+ try {
84
+ Object result;
85
+ if( m.getReturnType().equals(Void.TYPE)){
86
+ invokeMethod(o, m);
87
+ result = "<VOID>";
88
+ }
89
+ else {
90
+ result = invokeMethod(o, m);
91
+ }
92
+ ref.set(result);
93
+ return;
94
+ } catch (Exception e) {
95
+ e.printStackTrace();
96
+ refEx.set(e);
97
+ return;
98
+ }
99
+
100
+ }
101
+ }
102
+ }
103
+
104
+ }
105
+
106
+ });
107
+
108
+ if (refEx.get() != null) {
109
+ throw refEx.get();
110
+ }
111
+ return ref.get();
112
+ }
113
+
114
+ @SuppressWarnings("rawtypes")
115
+ private Class[] extractArgumentTypes(boolean convertStringCharSeq) {
116
+ Class[] types = new Class[arguments.size()];
117
+ for (int i=0;i<arguments.size(); i++) {
118
+ Object o = arguments.get(i);
119
+ if (o != null) {
120
+ Class<?> c = o.getClass();
121
+ if (convertStringCharSeq && c.equals(String.class)) {
122
+ c = CharSequence.class;//Android API specific optimization
123
+ }
124
+ types[i] = mapToPrimitiveClass(c);
125
+ }
126
+ else {
127
+ types[i] = null;
128
+ }
129
+ }
130
+ return types;
131
+ }
132
+
133
+ private Class<?> mapToPrimitiveClass(Class<?> c) {
134
+ if (c.equals(Integer.class)) {
135
+ return int.class;
136
+ }
137
+ else if (c.equals(Float.class)) {
138
+ return float.class;
139
+ }
140
+ else if (c.equals(Double.class)) {
141
+ return double.class;
142
+ }
143
+ else if (c.equals(Boolean.class)) {
144
+ return boolean.class;
145
+ }
146
+ return c;
147
+ }
148
+
149
+
150
+ //parameterType.length == this.classes.length
151
+ //Note: right now we don't do any clever mapping, we
152
+ //only use Java's sub type relation: isAssigableFrom
153
+ private boolean areArgumentsConvertibleTo(Class<?>[] parameterTypes) {
154
+ for (int i=0; i < parameterTypes.length; i++) {
155
+ Class<?> typei = parameterTypes[i];
156
+ if (this.arguments.get(i) == null) {
157
+ if (typei.isPrimitive()) {
158
+ //Can't pass null as primitive
159
+ return false;
160
+ }
161
+ continue; //can always pass null (unless primitive)
162
+ }
163
+ if (typei.isPrimitive() && typei.equals(mapToPrimitiveClass(this.classes[i]))) {
164
+ continue;
165
+ }
166
+ if (!typei.isAssignableFrom(this.classes[i])) {
167
+ return false;
168
+ }
169
+ }
170
+ return true;
171
+ }
172
+
173
+ private Object invokeMethod(Object o, Method m) throws Exception {
174
+ List<?> a = this.arguments;
175
+ int size = a.size();
176
+ switch(size) {
177
+ case 0:
178
+ return m.invoke(o);
179
+ case 1:
180
+ return m.invoke(o,a.get(0));
181
+ case 2:
182
+ return m.invoke(o,a.get(0),a.get(1));
183
+ case 3:
184
+ return m.invoke(o,a.get(0),a.get(1),a.get(2));
185
+ case 4:
186
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3));
187
+ case 5:
188
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4));
189
+ case 6:
190
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5));
191
+ case 7:
192
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6));
193
+ case 8:
194
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7));
195
+ case 9:
196
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8));
197
+ case 10:
198
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9));
199
+ case 11:
200
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10));
201
+ case 12:
202
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11));
203
+ case 13:
204
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12));
205
+ case 14:
206
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13));
207
+ case 15:
208
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13),a.get(14));
209
+ case 16:
210
+ return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13),a.get(14),a.get(15));
211
+ }
212
+ throw new UnsupportedOperationException("Method with more than 16 arguments are not supported");
213
+
214
+ }
215
+
216
+
217
+ @Override
218
+ public String getName() {
219
+ return "InvocationOp["+this.methodName+", arguments = " + this.arguments + "]";
220
+ }
221
+
222
+ }
@@ -0,0 +1,7 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ public interface Operation {
4
+
5
+ public Object apply(Object o) throws Exception;
6
+ public String getName();
7
+ }
@@ -0,0 +1,56 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ import java.lang.reflect.Method;
4
+ import java.util.Map;
5
+
6
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryUtils;
7
+ import android.view.View;
8
+
9
+ public class PropertyOperation implements Operation {
10
+
11
+ public final String propertyName;
12
+
13
+ public PropertyOperation(String propertyName) {
14
+ super();
15
+ this.propertyName = propertyName;
16
+ }
17
+
18
+
19
+ @SuppressWarnings({ "rawtypes" })
20
+ @Override
21
+ public Object apply(Object o) throws Exception {
22
+ if (o instanceof Map) {
23
+ Map objAsMap = (Map) o;
24
+ if (objAsMap.containsKey(propertyName)) {
25
+ return objAsMap.get(propertyName);
26
+ } else {
27
+ return UIQueryResultVoid.instance.asMap(
28
+ propertyName, o, "No key for "
29
+ + propertyName + ". Keys: "
30
+ + (objAsMap.keySet().toString()));
31
+ }
32
+ } else {
33
+ if (o instanceof View && "id".equals(propertyName)) {
34
+ return UIQueryUtils.getId((View) o);
35
+ } else {
36
+ Method m = UIQueryUtils
37
+ .hasProperty(o, propertyName);
38
+ if (m != null) {
39
+ return m.invoke(o);
40
+ } else {
41
+ return UIQueryResultVoid.instance
42
+ .asMap(propertyName, o,
43
+ "NO accessor for "
44
+ + propertyName);
45
+ }
46
+ }
47
+ }
48
+
49
+ }
50
+
51
+ @Override
52
+ public String getName() {
53
+ return "Property["+this.propertyName+"]";
54
+ }
55
+
56
+ }
@@ -6,64 +6,172 @@ import java.util.ArrayList;
6
6
  import java.util.Collections;
7
7
  import java.util.HashSet;
8
8
  import java.util.List;
9
+ import java.util.Map;
9
10
  import java.util.Set;
10
11
 
12
+ import org.antlr.runtime.ANTLRStringStream;
13
+ import org.antlr.runtime.CommonTokenStream;
14
+ import org.antlr.runtime.RecognitionException;
15
+ import org.antlr.runtime.tree.CommonTree;
16
+
17
+ import sh.calaba.instrumentationbackend.query.antlr.UIQueryLexer;
18
+ import sh.calaba.instrumentationbackend.query.antlr.UIQueryParser;
19
+ import sh.calaba.instrumentationbackend.query.ast.InvalidUIQueryException;
20
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryAST;
21
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryASTClassName;
22
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryASTPredicate;
23
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryASTWith;
24
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryDirection;
11
25
  import sh.calaba.instrumentationbackend.query.ast.UIQueryEvaluator;
12
- import sh.calaba.instrumentationbackend.query.ast.UIQueryUtils;
26
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryVisibility;
13
27
  import android.view.View;
14
28
 
15
29
  public class Query {
16
30
 
17
- private String queryString;
31
+ private String queryString;
18
32
  @SuppressWarnings("rawtypes")
19
- private List arguments;
33
+ private List operations;
20
34
 
21
- public Query(String queryString) {
22
- this.queryString = queryString;
23
- this.arguments = Collections.EMPTY_LIST;
24
- if (this.queryString == null || this.queryString.trim().equals(""))
25
- {
26
- throw new IllegalArgumentException("Illegal query: "+this.queryString);
27
- }
28
- }
35
+ public Query(String queryString) {
36
+ this.queryString = queryString;
37
+ this.operations = Collections.EMPTY_LIST;
38
+ if (this.queryString == null || this.queryString.trim().equals("")) {
39
+ throw new IllegalArgumentException("Illegal query: "
40
+ + this.queryString);
41
+ }
42
+ }
29
43
 
30
- @SuppressWarnings("rawtypes")
31
- public Query(String queryString,List args) {
32
- this(queryString);
33
- this.arguments = args;
34
- }
44
+ @SuppressWarnings("rawtypes")
45
+ public Query(String queryString, List args) {
46
+ this(queryString);
47
+ this.operations = args;
48
+ }
35
49
 
50
+ @SuppressWarnings("rawtypes")
51
+ public List executeQuery() {
52
+ return UIQueryEvaluator.evaluateQueryWithOptions(parseQuery(this.queryString), rootViews(), parseOperations(this.operations));
53
+ }
36
54
 
37
- @SuppressWarnings({"unchecked", "rawtypes" })
38
- public QueryResult execute() {
39
- List result = new ArrayList();
40
- List<View> all = rootViews();
41
-
42
- List queryResults = UIQueryEvaluator.evaluateQueryWithOptions(this.queryString, all, this.arguments);
43
-
44
- for (Object v : queryResults) {
45
- if (UIQueryUtils.isVisible(v)) {
46
- System.out.println("Query result: "+v);
47
- result.add(ViewMapper.extractDataFromView(v));
48
- }
49
-
50
- }
51
- return new QueryResult(result);
52
- }
55
+ @SuppressWarnings("rawtypes")
56
+ public static List<Operation> parseOperations(List ops) {
57
+ List<Operation> result = new ArrayList<Operation>(ops.size());
58
+ for (Object o : ops) {
59
+ Operation op = null;
60
+ if (o instanceof Operation) {
61
+ op = (Operation) o;
62
+ }
63
+ else if (o instanceof String) {
64
+ op = new PropertyOperation((String) o);
65
+ }
66
+ else if (o instanceof Map) {
67
+ Map mapOp = (Map) o;
68
+ String methodName = (String) mapOp.get("method_name");
69
+ if (methodName == null) {
70
+ throw new IllegalArgumentException("Trying to convert a Map without method_name to an operation. " + mapOp.toString());
71
+ }
72
+ List arguments = (List) mapOp.get("arguments");
73
+ if (arguments == null) {
74
+ throw new IllegalArgumentException("Trying to convert a Map without arguments to an operation. " + mapOp.toString());
75
+ }
76
+ op = new InvocationOperation(methodName, arguments);
77
+ }
78
+ result.add(op);
79
+ }
80
+ return result;
81
+ }
53
82
 
83
+ @SuppressWarnings("unchecked")
84
+ public static List<UIQueryAST> parseQuery(String query) {
85
+ UIQueryLexer lexer = new UIQueryLexer(new ANTLRStringStream(query));
86
+ UIQueryParser parser = new UIQueryParser(new CommonTokenStream(lexer));
54
87
 
55
- public List<View> allVisibleViews() {
56
- return viewFetcher.getAllViews(false);
57
- }
88
+ UIQueryParser.query_return q;
89
+ try {
90
+ q = parser.query();
91
+ } catch (RecognitionException e) {
92
+ throw new InvalidUIQueryException(e.getMessage());
93
+ }
94
+ if (q == null) {
95
+ throw new InvalidUIQueryException(query);
96
+ }
97
+ CommonTree rootNode = (CommonTree) q.getTree();
98
+ List<CommonTree> queryPath = rootNode.getChildren();
99
+
100
+ if (queryPath == null || queryPath.isEmpty()) {
101
+ queryPath = Collections.singletonList(rootNode);
102
+ }
103
+
104
+ return mapUIQueryFromAstNodes(queryPath);
105
+ }
106
+
107
+
108
+ public static List<UIQueryAST> mapUIQueryFromAstNodes(List<CommonTree> nodes) {
109
+ List<UIQueryAST> mapped = new ArrayList<UIQueryAST>(nodes.size());
110
+ for (CommonTree t : nodes) {
111
+ mapped.add(uiQueryFromAst(t));
112
+ }
113
+ return mapped;
114
+ }
115
+
116
+ public static UIQueryAST uiQueryFromAst(CommonTree step) {
117
+ String stepType = UIQueryParser.tokenNames[step.getType()];
118
+ switch (step.getType()) {
119
+ case UIQueryParser.QUALIFIED_NAME:
120
+ try {
121
+ return new UIQueryASTClassName(Class.forName(step.getText()));
122
+ } catch (ClassNotFoundException e) {
123
+ // TODO Auto-generated catch block
124
+ throw new InvalidUIQueryException("Qualified class name: "
125
+ + step.getText() + " not found. (" + e.getMessage()
126
+ + ")");
127
+ }
128
+ case UIQueryParser.NAME:
129
+ return new UIQueryASTClassName(step.getText());
130
+
131
+ case UIQueryParser.WILDCARD:
132
+ try {
133
+ return new UIQueryASTClassName(Class.forName("android.view.View"));
134
+ } catch (ClassNotFoundException e) {
135
+ //Cannot happen
136
+ throw new IllegalStateException(e);
137
+ }
138
+
139
+
140
+
141
+ case UIQueryParser.FILTER_COLON:
142
+ return UIQueryASTWith.fromAST(step);
143
+
144
+ case UIQueryParser.ALL:
145
+ return UIQueryVisibility.ALL;
146
+
147
+ case UIQueryParser.VISIBLE:
148
+ return UIQueryVisibility.VISIBLE;
149
+
150
+ case UIQueryParser.BEGINPRED:
151
+ return UIQueryASTPredicate.newPredicateFromAST(step);
152
+ case UIQueryParser.DIRECTION:
153
+ return UIQueryDirection.valueOf(step.getText().toUpperCase());
154
+
155
+ default:
156
+ throw new InvalidUIQueryException("Unknown query: " + stepType
157
+ + " with text: " + step.getText());
158
+
159
+ }
160
+
161
+ }
58
162
 
59
163
  public List<View> rootViews() {
60
- Set<View> parents = new HashSet<View>(8);
61
- for (View v : allVisibleViews())
62
- {
63
- parents.add(viewFetcher.getTopParent(v));
64
- }
65
- List<View> results = new ArrayList<View>();
66
- results.addAll(parents);
67
- return results;
164
+ Set<View> parents = new HashSet<View>();
165
+ for (View v : viewFetcher.getAllViews(false))
166
+ {
167
+ View parent = viewFetcher.getTopParent(v);
168
+ System.out.println(parent);
169
+ parents.add(parent);
170
+ }
171
+ List<View> results = new ArrayList<View>();
172
+ results.addAll(parents);
173
+ return results;
68
174
  }
175
+
176
+
69
177
  }
@@ -1,12 +1,19 @@
1
- BOOL=4
2
- ESC_SEQ=5
3
- FILTER_COLON=6
4
- HEX_DIGIT=7
5
- INT=8
6
- NAME=9
7
- NIL=10
8
- OCTAL_ESC=11
9
- QUALIFIED_NAME=12
10
- STRING=13
11
- UNICODE_ESC=14
12
- WHITE=15
1
+ ALL=4
2
+ BEGINPRED=5
3
+ BOOL=6
4
+ DIRECTION=7
5
+ ENDPRED=8
6
+ ESC_SEQ=9
7
+ FILTER_COLON=10
8
+ HEX_DIGIT=11
9
+ INT=12
10
+ NAME=13
11
+ NIL=14
12
+ OCTAL_ESC=15
13
+ QUALIFIED_NAME=16
14
+ RELATION=17
15
+ STRING=18
16
+ UNICODE_ESC=19
17
+ VISIBLE=20
18
+ WHITE=21
19
+ WILDCARD=22
@@ -0,0 +1,22 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ import java.util.HashMap;
4
+ import java.util.Map;
5
+
6
+
7
+ public class UIQueryResultVoid {
8
+ public static final UIQueryResultVoid instance = new UIQueryResultVoid();
9
+
10
+ private UIQueryResultVoid() {}
11
+
12
+ @SuppressWarnings({ "rawtypes", "unchecked" })
13
+ public Object asMap(String methodName, Object receiver,
14
+ String errorMessage) {
15
+ Map map = new HashMap();
16
+ map.put("error", errorMessage);
17
+ map.put("methodName", methodName);
18
+ map.put("receiverClass", receiver.getClass().getName());
19
+ map.put("receiverString", receiver.toString());
20
+ return map;
21
+ }
22
+ }
@@ -2,8 +2,10 @@ package sh.calaba.instrumentationbackend.query;
2
2
 
3
3
  import java.util.HashMap;
4
4
  import java.util.Map;
5
+ import java.util.Map.Entry;
5
6
 
6
7
  import sh.calaba.instrumentationbackend.InstrumentationBackend;
8
+ import sh.calaba.instrumentationbackend.query.ast.UIQueryUtils;
7
9
  import android.content.res.Resources;
8
10
  import android.view.View;
9
11
  import android.widget.Button;
@@ -13,12 +15,10 @@ import android.widget.TextView;
13
15
  public class ViewMapper {
14
16
 
15
17
  @SuppressWarnings({ "rawtypes", "unchecked" })
16
- public static Object extractDataFromView(Object obj) {
17
- if (!(obj instanceof View)) {return obj;}
18
- View v = (View) obj;
18
+ public static Object extractDataFromView(View v) {
19
+
19
20
  Map data = new HashMap();
20
- data.put("class", v.getClass().getSimpleName());
21
- data.put("qualified_class", v.getClass().getName());
21
+ data.put("class", v.getClass().getName());
22
22
  data.put("description", v.toString());
23
23
  CharSequence description = v.getContentDescription();
24
24
  data.put("contentDescription", description != null ? description.toString() : null);
@@ -33,16 +33,20 @@ public class ViewMapper {
33
33
  }
34
34
  data.put("id", id);
35
35
 
36
- Map frame = new HashMap();
36
+ Map rect = new HashMap();
37
37
  int[] location = new int[2];
38
38
  v.getLocationOnScreen(location);
39
39
 
40
- frame.put("x", location[0]);
41
- frame.put("y", location[1]);
42
- frame.put("width", v.getWidth());
43
- frame.put("height", v.getHeight());
40
+ rect.put("x", location[0]);
41
+ rect.put("y", location[1]);
42
+
43
+ rect.put("center_x", location[0] + v.getWidth()/2.0);
44
+ rect.put("center_y", location[1] + v.getHeight()/2.0);
45
+
46
+ rect.put("width", v.getWidth());
47
+ rect.put("height", v.getHeight());
44
48
 
45
- data.put("frame", frame);
49
+ data.put("rect", rect);
46
50
 
47
51
  if (v instanceof Button) {
48
52
  Button b = (Button) v;
@@ -60,4 +64,30 @@ public class ViewMapper {
60
64
 
61
65
  }
62
66
 
67
+ @SuppressWarnings({ "unchecked", "rawtypes" })
68
+ public static Object mapView(Object o) {
69
+ if (o instanceof View) {
70
+ return extractDataFromView((View) o);
71
+ }
72
+ else if (o instanceof Map) {
73
+ Map copy = new HashMap();
74
+ for (Object e : ((Map) o).entrySet()) {
75
+ Map.Entry entry = (Entry) e;
76
+ Object value = entry.getValue();
77
+ if (value instanceof View) {
78
+ copy.put(entry.getKey(), UIQueryUtils.getId((View) value));
79
+ }
80
+ else {
81
+ copy.put(entry.getKey(),entry.getValue());
82
+ }
83
+ }
84
+
85
+ return copy;
86
+ }
87
+ else if (o instanceof CharSequence) {
88
+ return o.toString();
89
+ }
90
+ return o;
91
+ }
92
+
63
93
  }