calabash-android 0.4.0.pre6 → 0.4.0.pre7

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 (50) hide show
  1. data/bin/calabash-android +7 -0
  2. data/bin/calabash-android-build.rb +1 -1
  3. data/bin/calabash-android-console.rb +1 -1
  4. data/bin/calabash-android-run.rb +1 -1
  5. data/calabash-android.gemspec +1 -0
  6. data/irbrc +2 -0
  7. data/lib/calabash-android/helpers.rb +4 -2
  8. data/lib/calabash-android/lib/TestServer.apk +0 -0
  9. data/lib/calabash-android/operations.rb +31 -22
  10. data/lib/calabash-android/version.rb +1 -1
  11. data/test-server/instrumentation-backend/.classpath +0 -1
  12. data/test-server/instrumentation-backend/antlr/UIQuery.g +11 -2
  13. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Command.java +4 -3
  14. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/FranklyResult.java +95 -0
  15. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +7 -1
  16. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java +15 -23
  17. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/location/FakeGPSLocation.java +13 -10
  18. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/CalabashChromeClient.java +136 -36
  19. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpBodyHtml.java +38 -18
  20. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpHtml.java +38 -16
  21. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/EnterTextByCssSelector.java +94 -66
  22. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteAsyncJavascript.java +55 -33
  23. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteJavascript.java +54 -31
  24. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +44 -0
  25. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +52 -27
  26. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +39 -32
  27. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ScrollTo.java +56 -41
  28. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetPropertyByCssSelector.java +50 -25
  29. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +19 -22
  30. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/CompletedFuture.java +40 -0
  31. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/InvocationOperation.java +201 -0
  32. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Operation.java +7 -0
  33. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/PropertyOperation.java +56 -0
  34. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Query.java +144 -72
  35. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQuery.tokens +15 -12
  36. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQueryResultVoid.java +22 -0
  37. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +38 -11
  38. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryLexer.java +226 -109
  39. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryParser.java +237 -84
  40. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/PartialFutureList.java +100 -0
  41. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryAST.java +1 -1
  42. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTClassName.java +26 -22
  43. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +170 -102
  44. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryEvaluator.java +54 -155
  45. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +97 -2
  46. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryVisibility.java +32 -0
  47. metadata +27 -5
  48. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Query.java +0 -24
  49. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Touch.java +0 -44
  50. data/test-server/instrumentation-backend/tests/sh/calaba/instrumentationbackend/query/tests/UIQueryTest.java +0 -134
@@ -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,7 @@ 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;
5
6
 
6
7
  public class UIQueryASTClassName implements UIQueryAST {
7
8
  public final String simpleClassName;
@@ -20,36 +21,39 @@ public class UIQueryASTClassName implements UIQueryAST {
20
21
  {
21
22
  if (qualifiedClassName == null) {throw new IllegalArgumentException("Cannot instantiate with null class");}
22
23
  this.qualifiedClassName = qualifiedClassName;
23
- this.simpleClassName = null;
24
-
24
+ this.simpleClassName = null;
25
25
  }
26
26
 
27
27
  @SuppressWarnings({ "rawtypes"})
28
28
  @Override
29
- public List evaluateWithViewsAndDirection(List inputViews,
30
- UIQueryDirection direction) {
31
- // TODO Auto-generated method stub
29
+ public List evaluateWithViews(final List inputViews,
30
+ final UIQueryDirection direction, final UIQueryVisibility visibility) {
32
31
 
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
- }
32
+ return (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
47
33
 
48
-
49
- }
34
+ public Object call() throws Exception {
35
+ List result = new ArrayList(8);
36
+ for (Object o : inputViews)
37
+ {
38
+ switch(direction) {
39
+ case DESCENDANT:
40
+ addDecendantMatchesToResult(o,result);
41
+ break;
42
+ case CHILD:
43
+ addChildMatchesToResult(o,result);
44
+ break;
45
+ case PARENT:
46
+ addParentMatchesToResult(o,result);
47
+ break;
48
+ }
49
+
50
+
51
+ }
52
+ return result;
53
+ }
54
+ });
50
55
 
51
56
 
52
- return result;
53
57
  }
54
58
 
55
59
  @SuppressWarnings("rawtypes")
@@ -3,155 +3,223 @@ package sh.calaba.instrumentationbackend.query.ast;
3
3
  import java.lang.reflect.Method;
4
4
  import java.util.ArrayList;
5
5
  import java.util.List;
6
+ import java.util.Map;
7
+ import java.util.concurrent.Callable;
8
+ import java.util.concurrent.Future;
6
9
 
7
10
  import org.antlr.runtime.tree.CommonTree;
8
11
 
9
- import sh.calaba.instrumentationbackend.InstrumentationBackend;
12
+ import sh.calaba.instrumentationbackend.actions.webview.QueryHelper;
10
13
  import sh.calaba.instrumentationbackend.query.antlr.UIQueryParser;
11
- import android.content.res.Resources.NotFoundException;
12
14
  import android.view.View;
15
+ import android.webkit.WebView;
13
16
 
14
17
  public class UIQueryASTWith implements UIQueryAST {
15
- public final String propertyName;
18
+ public final String propertyName;
16
19
  public final Object value;
17
-
18
- public UIQueryASTWith(String property, Object value)
19
- {
20
- if (property == null) {throw new IllegalArgumentException("Cannot instantiate Filter with null property name");}
20
+
21
+ public UIQueryASTWith(String property, Object value) {
22
+ if (property == null) {
23
+ throw new IllegalArgumentException(
24
+ "Cannot instantiate Filter with null property name");
25
+ }
21
26
  this.propertyName = property;
22
27
  this.value = value;
23
28
  }
24
29
 
25
- @SuppressWarnings({ "rawtypes", "unchecked"})
30
+ @SuppressWarnings({ "rawtypes", "unchecked" })
26
31
  @Override
27
- public List evaluateWithViewsAndDirection(List inputViews,
28
- UIQueryDirection direction) {
29
- List result = new ArrayList(8);
30
-
31
- for (int i=0;i<inputViews.size();i++)
32
- {
33
- Object o = inputViews.get(i);
34
- if (this.propertyName.equals("id") && hasId(o,this.value))
35
- {
36
- result.add(o);
37
- }
38
- else if (this.propertyName.equals("marked") && isMarked(o,this.value))
39
- {
40
- result.add(o);
41
- }
42
- else if (this.propertyName.equals("index") && this.value.equals(i))
43
- {
44
- result.add(o);
45
- }
46
- else
47
- {
48
-
49
- Method propertyAccessor = UIQueryUtils.hasProperty(o, this.propertyName);
50
- if (propertyAccessor != null)
51
- {
52
- Object value = UIQueryUtils.getProperty(o, propertyAccessor);
53
-
54
- if (value == this.value || (value != null && value.equals(this.value)))
55
- {
56
- result.add(o);
57
- }
58
- else if (this.value instanceof String && this.value.equals(value.toString()))
59
- {
60
- result.add(o);
32
+ public List evaluateWithViews(final List inputViews, final UIQueryDirection direction,
33
+ final UIQueryVisibility visibility) {
34
+
35
+ List queryResult = (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
36
+
37
+ @Override
38
+ public Object call() throws Exception {
39
+ List futureResult = new ArrayList(8);
40
+
41
+ for (int i = 0; i < inputViews.size(); i++) {
42
+ Object o = inputViews.get(i);
43
+
44
+ if (o instanceof WebView) {
45
+ Future webResult = evaluateForWebView((WebView) o);
46
+ if (webResult != null) {
47
+ futureResult.add(webResult);
48
+ }
61
49
  }
62
-
63
-
50
+ else if (o instanceof Map) {
51
+ Map result = evaluateForMap((Map) o);
52
+ if (result != null) {
53
+ futureResult.add(result);
54
+ }
55
+
56
+ }
57
+ else {
58
+ Object result = evaluateForObject(o, i);
59
+ if (result != null) {
60
+ futureResult.add(result);
61
+ }
62
+ }
63
+
64
+ }
65
+ List visibilityFilteredResults = visibility.evaluateWithViews(futureResult, direction,
66
+ visibility);
67
+ return new PartialFutureList(visibilityFilteredResults);
68
+ }
69
+ });
70
+
71
+ List processedResult = new ArrayList(queryResult.size());
72
+ for (Object o : queryResult) {
73
+ if (o instanceof Map) {
74
+ Map m = (Map) o;
75
+ if (m.containsKey("result")) {
76
+ processedResult.addAll(UIQueryUtils.mapWebViewJsonResponse((String) m.get("result"),(WebView) m.get("webView")));
77
+ }
78
+ else {
79
+ processedResult.add(m);
64
80
  }
65
81
 
66
82
  }
67
-
83
+ else {
84
+ processedResult.add(o);
85
+ }
68
86
  }
87
+ return processedResult;
69
88
 
70
-
71
- return result;
89
+
90
+ }
91
+
92
+
93
+ @SuppressWarnings("rawtypes")
94
+ private Map evaluateForMap(Map map) {
95
+ if (map.containsKey(this.propertyName)) {
96
+ Object value = map.get(this.propertyName);
97
+ if (value == this.value || (value != null && value.equals(this.value))) {
98
+ return map;
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+
104
+ private Object evaluateForObject(Object o, int index) {
105
+ if (this.propertyName.equals("id") && hasId(o, this.value)) {
106
+ return o;
107
+ } else if (this.propertyName.equals("marked")
108
+ && isMarked(o, this.value)) {
109
+ return o;
110
+ } else if (this.propertyName.equals("index")
111
+ && this.value.equals(index)) {
112
+ return o;
113
+ } else {
114
+
115
+ Method propertyAccessor = UIQueryUtils.hasProperty(o,
116
+ this.propertyName);
117
+ if (propertyAccessor != null) {
118
+ Object value = UIQueryUtils.getProperty(o, propertyAccessor);
119
+
120
+ if (value == this.value
121
+ || (value != null && value.equals(this.value))) {
122
+ return o;
123
+ } else if (this.value instanceof String
124
+ && this.value.equals(value.toString())) {
125
+ return o;
126
+ }
127
+ }
128
+ }
129
+ return null;
130
+
131
+ }
132
+
133
+ @SuppressWarnings({ "rawtypes" })
134
+ private Future evaluateForWebView(WebView o) {
135
+ if (!(this.value instanceof String)) {
136
+ return null;
137
+ }
138
+ return QueryHelper.executeAsyncJavascriptInWebviews(o,
139
+ "calabash.js", (String) this.value,this.propertyName);
140
+
72
141
  }
73
142
 
74
143
  private boolean hasId(Object o, Object expectedValue) {
75
- if (! (o instanceof View)) { return false; }
76
- if (! (expectedValue instanceof String)) { return false; }
144
+ if (!(o instanceof View)) {
145
+ return false;
146
+ }
147
+ if (!(expectedValue instanceof String)) {
148
+ return false;
149
+ }
77
150
  View view = (View) o;
78
151
  String expected = (String) expectedValue;
79
-
80
- try {
81
- String id = InstrumentationBackend.solo.getCurrentActivity()
82
- .getResources().getResourceEntryName(view.getId());
83
-
84
- if (id != null && id.equals(expected)) {
85
- return true;
86
- }
87
- }
88
- catch (NotFoundException e) {}
89
- return false;
152
+ String id = UIQueryUtils.getId(view);
153
+ return (id != null && id.equals(expected));
90
154
  }
91
155
 
92
156
  private boolean isMarked(Object o, Object expectedValue) {
93
- if (! (o instanceof View)) { return false; }
94
- if (! (expectedValue instanceof String)) { return false; }
157
+ if (!(o instanceof View)) {
158
+ return false;
159
+ }
160
+ if (!(expectedValue instanceof String)) {
161
+ return false;
162
+ }
95
163
  View view = (View) o;
96
164
  String expected = (String) expectedValue;
97
-
98
- if (hasId(o, expectedValue))
99
- {
165
+
166
+ if (hasId(o, expectedValue)) {
100
167
  return true;
101
168
  }
102
-
103
-
104
- CharSequence contentDescription = view.getContentDescription();
105
- if (contentDescription != null && contentDescription.toString().equals(expected))
106
- {
169
+
170
+ CharSequence contentDescription = view.getContentDescription();
171
+ if (contentDescription != null
172
+ && contentDescription.toString().equals(expected)) {
107
173
  return true;
108
174
  }
109
-
175
+
110
176
  try {
111
177
  Method getTextM = view.getClass().getMethod("getText");
112
178
  Object text = getTextM.invoke(view);
113
- if (text != null && text.toString().equals(expected))
114
- {
179
+ if (text != null && text.toString().equals(expected)) {
115
180
  return true;
116
181
  }
117
-
118
- } catch (Exception e) {}
119
-
182
+
183
+ } catch (Exception e) {
184
+ }
185
+
120
186
  return false;
121
-
187
+
122
188
  }
123
189
 
124
190
  public static UIQueryASTWith fromAST(CommonTree step) {
125
191
  CommonTree prop = (CommonTree) step.getChild(0);
126
192
  CommonTree val = (CommonTree) step.getChild(1);
127
-
128
- switch(val.getType())
129
- {
130
- case UIQueryParser.STRING: {
131
- String textWithPings = val.getText();
132
- String text = textWithPings.substring(1, textWithPings.length()-1);
133
- return new UIQueryASTWith(prop.getText(), text);
134
- }
135
- case UIQueryParser.INT:
136
- return new UIQueryASTWith(prop.getText(), Integer.parseInt(val.getText(), 10));
137
- case UIQueryParser.BOOL:{
138
- String text = val.getText();
139
- return new UIQueryASTWith(prop.getText(), Boolean.parseBoolean(text));
140
- }
141
- case UIQueryParser.NIL:
142
- return new UIQueryASTWith(prop.getText(), null);
143
-
144
- default:
145
- throw new IllegalArgumentException("Unable to parse value type:" + val.getType()+ " text "+val.getText());
146
-
193
+
194
+ switch (val.getType()) {
195
+ case UIQueryParser.STRING: {
196
+ String textWithPings = val.getText();
197
+ String text = textWithPings
198
+ .substring(1, textWithPings.length() - 1);
199
+ return new UIQueryASTWith(prop.getText(), text);
147
200
  }
148
-
201
+ case UIQueryParser.INT:
202
+ return new UIQueryASTWith(prop.getText(), Integer.parseInt(
203
+ val.getText(), 10));
204
+ case UIQueryParser.BOOL: {
205
+ String text = val.getText();
206
+ return new UIQueryASTWith(prop.getText(),
207
+ Boolean.parseBoolean(text));
208
+ }
209
+ case UIQueryParser.NIL:
210
+ return new UIQueryASTWith(prop.getText(), null);
211
+
212
+ default:
213
+ throw new IllegalArgumentException("Unable to parse value type:"
214
+ + val.getType() + " text " + val.getText());
215
+
216
+ }
217
+
149
218
  }
150
-
151
-
219
+
152
220
  @Override
153
221
  public String toString() {
154
- return "With["+this.propertyName+":"+this.value+"]";
222
+ return "With[" + this.propertyName + ":" + this.value + "]";
155
223
  }
156
-
224
+
157
225
  }