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,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
  }