calabash-android 0.4.0.pre6 → 0.4.0.pre7

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