on xenial help sign in
[ Albert Astals Cid ]
bf8ab8bMichael Zanetti
cmake/modules/QmlTest.cmake+10−8
@@ -155,10 +155,11 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
155 set(testCommand
155 set(testCommand
156 ${ENVVAR}
156 ${ENVVAR}
157 LD_LIBRARY_PATH=${LD_PATH}
157 LD_LIBRARY_PATH=${LD_PATH}
158− dbus-launch
158+ dbus-test-runner
159+ -m 300
159− ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
160+ -t ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
160− -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
161+ -p -o -p ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
161− -o -,txt)
162+ -p -o -p -,txt)
162
163
163 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
164 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
164 add_dependencies(test${CLASS_NAME} ${CLASS_NAME}TestExec ${DEPS})
165 add_dependencies(test${CLASS_NAME} ${CLASS_NAME}TestExec ${DEPS})
@@ -173,10 +174,11 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
173 ${ENVVAR}
174 ${ENVVAR}
174 LD_LIBRARY_PATH=${LD_PATH}
175 LD_LIBRARY_PATH=${LD_PATH}
175 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
176 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
176− dbus-launch
177+ dbus-test-runner
178+ -m 300
177− ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
179+ -t ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
178− -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
180+ -p -o -p ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
179− -o -,txt)
181+ -p -o -p -,txt)
180
182
181 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
183 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
182 add_dependencies(qmluitests xvfbtest${CLASS_NAME})
184 add_dependencies(qmluitests xvfbtest${CLASS_NAME})
data/unity8-dash.conf−5
@@ -18,11 +18,6 @@ respawn
18env APP_ID=unity8-dash
18env APP_ID=unity8-dash
19
19
20pre-start script
20pre-start script
21− if [ -z "$UNITY_SCOPES_LIST" ]; then
22− # FIXME: remove once we have this in dconf
23− initctl set-env UNITY_SCOPES_LIST="clickscope;musicaggregator;videoaggregator"
24− fi
25−
26 initctl emit scope-ui-starting
21 initctl emit scope-ui-starting
27end script
22end script
28
23
data/unity8.conf+1
@@ -54,4 +54,5 @@ post-stop script
54 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
54 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
55 initctl unset-env --global UNITY_MIR_SOCKET
55 initctl unset-env --global UNITY_MIR_SOCKET
56 initctl unset-env --global MIR_SERVER_PROMPT_FILE
56 initctl unset-env --global MIR_SERVER_PROMPT_FILE
57+ initctl emit application-end
57end script
58end script
debian/changelog+30−12
@@ -1,21 +1,39 @@
1−unity8 (8.02+15.04.20150423-0ubuntu1) vivid; urgency=medium
1+unity8 (8.02+15.04.20150505-0ubuntu1) vivid; urgency=medium
2
2
3− [ CI Train Bot ]
3+ [ Albert Astals Cid ]
4− * New rebuild forced.
4+ * Make runtests fake a test error if make fails
5+ * Make the test more stable
6+ * Use dbus-test-runner instead of dbus-launch
5
7
6 [ Daniel d'Andrada ]
8 [ Daniel d'Andrada ]
7− * Tapping home key shows unity8-dash home added:
9+ * DirectionalDragArea: improvements & API grooming (LP: #1417920)
8− plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
10+ * Fix EdgeDragEvaluator when a drag can happen both ways
9− plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
11+ (Direction.Horizontal)
10− plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp
12+
13+ [ Josh Arenson ]
14+ * Remove panelHeight property as it is unused.
15+
16+ [ Leo Arias ]
17+ * Initial clean up of the autopilot tests set up. Removed the touch
18+ device from the test case. Moved the restart of unity to a fixture.
19+ Removed the unused DragMixin. Updated the setUpClass to use
20+ process_helpers. Removed the workaround for bug #1238417, already
21+ fixed. Use the toolkit helper to set the testability environment
22+ variable. Fixed the indicators base class that was restarting unity
23+ twice. (LP: #1238417, #1447206)
24+ * Use the base class from the toolkit in autopilot tests.
25+
26+ [ Michael Zanetti ]
27+ * emit application-stop when we're going down (LP: #1326513)
11
28
12 [ Michał Sawicz ]
29 [ Michał Sawicz ]
13− * Tapping home key shows unity8-dash home added:
30+ * UNITY_SCOPES_LIST is no more
14− plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
31+
15− plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
32+ [ handsome_feng<445865575@qq.com> ]
16− plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp
33+ * When click the favorite scope in Dash Manager , it just return to
34+ the corresponding scope page. (LP: #1447056)
17
35
18− -- CI Train Bot <ci-train-bot@canonical.com> Thu, 23 Apr 2015 12:52:51 +0000
36+ -- CI Train Bot <ci-train-bot@canonical.com> Tue, 05 May 2015 14:47:24 +0000
19
37
20unity8 (8.02+15.04.20150422-0ubuntu1) vivid; urgency=medium
38unity8 (8.02+15.04.20150422-0ubuntu1) vivid; urgency=medium
21
39
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+14−1
@@ -176,6 +176,11 @@ bool DirectionalDragArea::dragging() const
176 return d->status == DirectionalDragAreaPrivate::Recognized;
176 return d->status == DirectionalDragAreaPrivate::Recognized;
177}
177}
178
178
179+bool DirectionalDragArea::pressed() const
180+{
181+ return d->status != DirectionalDragAreaPrivate::WaitingForTouch;
182+}
183+
179bool DirectionalDragArea::immediateRecognition() const
184bool DirectionalDragArea::immediateRecognition() const
180{
185{
181 return d->immediateRecognition;
186 return d->immediateRecognition;
@@ -189,6 +194,13 @@ void DirectionalDragArea::setImmediateRecognition(bool enabled)
189 }
194 }
190}
195}
191
196
197+void DirectionalDragArea::removeTimeConstraints()
198+{
199+ d->setMaxTime(60 * 60 * 1000);
200+ d->compositionTime = 0;
201+ ddaDebug("removed time constraints");
202+}
203+
192bool DirectionalDragArea::event(QEvent *event)
204bool DirectionalDragArea::event(QEvent *event)
193{
205{
194 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
206 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
@@ -371,7 +383,6 @@ void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event)
371 allGood = false;
383 allGood = false;
372 } else {
384 } else {
373 // that's our candidate
385 // that's our candidate
374− touchId = touchPoint.id();
375 newTouchPoint = &touchPoint;
386 newTouchPoint = &touchPoint;
376 }
387 }
377 }
388 }
@@ -588,9 +599,11 @@ void DirectionalDragAreaPrivate::setStatus(Status newStatus)
588 if (oldStatus == Recognized) {
599 if (oldStatus == Recognized) {
589 Q_EMIT q->draggingChanged(false);
600 Q_EMIT q->draggingChanged(false);
590 }
601 }
602+ Q_EMIT q->pressedChanged(false);
591 break;
603 break;
592 case Undecided:
604 case Undecided:
593 recognitionTimer->start();
605 recognitionTimer->start();
606+ Q_EMIT q->pressedChanged(true);
594 break;
607 break;
595 case Recognized:
608 case Recognized:
596 Q_EMIT q->draggingChanged(true);
609 Q_EMIT q->draggingChanged(true);
plugins/Ubuntu/Gestures/DirectionalDragArea.h+16
@@ -64,6 +64,9 @@ class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem {
64 // Whether a drag gesture is taking place
64 // Whether a drag gesture is taking place
65 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
65 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
66
66
67+ // Whether the drag area is pressed.
68+ Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
69+
67 // Whether a gesture should be Recognized as soon a touch lands on the area.
70 // Whether a gesture should be Recognized as soon a touch lands on the area.
68 // With this property enabled it will work pretty much like a MultiPointTouchArea,
71 // With this property enabled it will work pretty much like a MultiPointTouchArea,
69 // just with a different API.
72 // just with a different API.
@@ -92,14 +95,27 @@ public:
92
95
93 bool dragging() const;
96 bool dragging() const;
94
97
98+ bool pressed() const;
99+
95 bool immediateRecognition() const;
100 bool immediateRecognition() const;
96 void setImmediateRecognition(bool enabled);
101 void setImmediateRecognition(bool enabled);
97
102
98 bool event(QEvent *e) override;
103 bool event(QEvent *e) override;
99
104
105+ /*
106+ In qmltests, sequences of touch events are sent all at once, unlike in "real life".
107+ Also qmltests might run really slowly, e.g. when run from inside virtual machines.
108+ Thus to remove a variable that qmltests cannot really control, namely time, this
109+ function removes all constraints that are sensible to elapsed time.
110+
111+ This effectively makes the DirectionalDragArea easier to fool.
112+ */
113+ Q_INVOKABLE void removeTimeConstraints();
114+
100Q_SIGNALS:
115Q_SIGNALS:
101 void directionChanged(Direction::Type direction);
116 void directionChanged(Direction::Type direction);
102 void draggingChanged(bool value);
117 void draggingChanged(bool value);
118+ void pressedChanged(bool value);
103 void distanceChanged(qreal value);
119 void distanceChanged(qreal value);
104 void sceneDistanceChanged(qreal value);
120 void sceneDistanceChanged(qreal value);
105 void touchXChanged(qreal value);
121 void touchXChanged(qreal value);
po/fr.po+4−4
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-19 21:55+0000\n"
11+"PO-Revision-Date: 2015-05-10 15:54+0000\n"
12"Last-Translator: Anne <anneonyme017@gmail.com>\n"
12"Last-Translator: Anne <anneonyme017@gmail.com>\n"
13"Language-Team: French <fr@li.org>\n"
13"Language-Team: French <fr@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-11 05:41+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17487)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -377,7 +377,7 @@ msgstr "Appuyez ici pour continuer."
377
377
378#: qml/Tutorial/TutorialContent.qml:81
378#: qml/Tutorial/TutorialContent.qml:81
379msgid "Click here to finish."
379msgid "Click here to finish."
380−msgstr ""
380+msgstr "Cliquez ici pour terminer."
381
381
382#: qml/Tutorial/TutorialLeftFinish.qml:24
382#: qml/Tutorial/TutorialLeftFinish.qml:24
383msgid "These are the shortcuts to favorite apps"
383msgid "These are the shortcuts to favorite apps"
po/ur.po+1−1
@@ -15,7 +15,7 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-05-06 05:45+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-09 05:49+0000\n"
19"X-Generator: Launchpad (build 17474)\n"
19"X-Generator: Launchpad (build 17474)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
qml/Components/EdgeDragEvaluator.qml+17−14
@@ -61,18 +61,12 @@ AxisVelocityCalculator {
61 }
61 }
62
62
63 velocity = calculate();
63 velocity = calculate();
64+ minVelocity = __calculateMinimumVelocityForAutoCompletion();
64
65
65− if (direction == Direction.Horizontal) {
66+ if (_dragDirectionIsPositive()) {
66− minVelocity = __calculateMinimumVelocityForAutoCompletion(Math.abs(deltaPos));
67− return Math.abs(velocity) >= minVelocity;
67+ return velocity >= minVelocity;
68 } else {
68 } else {
69− minVelocity = __calculateMinimumVelocityForAutoCompletion(deltaPos);
70− if (Direction.isPositive(direction) && (velocity >= minVelocity)
71− || !Direction.isPositive(direction) && (velocity <= minVelocity)) {
69+ return velocity <= minVelocity;
72− return true;
73− } else {
74− return false;
75− }
76 }
70 }
77 }
71 }
78
72
@@ -81,11 +75,20 @@ AxisVelocityCalculator {
81 // speedThreshold in pixels per millisecond
75 // speedThreshold in pixels per millisecond
82 property real __speedThresholdMs: speedThreshold / 1000.0
76 property real __speedThresholdMs: speedThreshold / 1000.0
83
77
78+ function _dragDirectionIsPositive() {
79+ if (direction === Direction.Horizontal) {
80+ return (trackedPosition - __startPosition) > 0;
81+ } else {
82+ return Direction.isPositive(direction);
83+ }
84+ }
85+
86+ function __calculateMinimumVelocityForAutoCompletion() {
84− // Minimum velocity when a drag total distance is zero
87+ // Minimum velocity when a drag total distance is zero
85− property real __v0: Direction.isPositive(direction) ? __speedThresholdMs : - __speedThresholdMs
88+ var v0 = _dragDirectionIsPositive() ? __speedThresholdMs : - __speedThresholdMs;
89+ var deltaPos = trackedPosition - __startPosition;
86
90
87− function __calculateMinimumVelocityForAutoCompletion(distance) {
88− return __v0 - ((__speedThresholdMs / dragThreshold) * distance);
91+ return v0 - ((__speedThresholdMs / dragThreshold) * deltaPos);
89 }
92 }
90
93
91 function reset() {
94 function reset() {
qml/Dash/Dash.qml+5
@@ -187,6 +187,11 @@ Showable {
187 onRequestFavoriteMoveTo: {
187 onRequestFavoriteMoveTo: {
188 scopes.moveFavoriteTo(scopeId, index);
188 scopes.moveFavoriteTo(scopeId, index);
189 }
189 }
190+ onRequestRestore: {
191+ bottomEdgeController.enableAnimation = true;
192+ bottomEdgeController.progress = 0;
193+ dash.setCurrentScope(scopeId, false, false);
194+ }
190
195
191 Binding {
196 Binding {
192 target: scopesList.scope
197 target: scopesList.scope
qml/Dash/ScopesList.qml+2
@@ -31,6 +31,7 @@ Item {
31 signal storeClicked()
31 signal storeClicked()
32 signal requestFavorite(string scopeId, bool favorite)
32 signal requestFavorite(string scopeId, bool favorite)
33 signal requestFavoriteMoveTo(string scopeId, int index)
33 signal requestFavoriteMoveTo(string scopeId, int index)
34+ signal requestRestore(string scopeId)
34
35
35 state: "browse"
36 state: "browse"
36
37
@@ -124,6 +125,7 @@ Item {
124 onRequestEditMode: root.state = "edit";
125 onRequestEditMode: root.state = "edit";
125 onRequestScopeMoveTo: root.requestFavoriteMoveTo(scopeId, index);
126 onRequestScopeMoveTo: root.requestFavoriteMoveTo(scopeId, index);
126 onRequestActivate: root.scope.activate(result);
127 onRequestActivate: root.scope.activate(result);
128+ onRequestRestore: root.requestRestore(scopeId);
127 }
129 }
128 }
130 }
129 }
131 }
qml/Dash/ScopesListCategory.qml+5−1
@@ -35,6 +35,7 @@ Item {
35 signal requestEditMode()
35 signal requestEditMode()
36 signal requestScopeMoveTo(string scopeId, int index)
36 signal requestScopeMoveTo(string scopeId, int index)
37 signal requestActivate(var result)
37 signal requestActivate(var result)
38+ signal requestRestore(string scopeId)
38
39
39 implicitHeight: visible ? childrenRect.height : 0
40 implicitHeight: visible ? childrenRect.height : 0
40
41
@@ -93,7 +94,10 @@ Item {
93
94
94 onClicked: {
95 onClicked: {
95 if (!editMode) {
96 if (!editMode) {
97+ if (root.isFavoritesFeed)
98+ root.requestRestore(model.scopeId);
99+ else
96− root.requestActivate(result);
100+ root.requestActivate(result);
97 }
101 }
98 }
102 }
99 onPressAndHold: {
103 onPressAndHold: {
qml/Greeter/CoverPage.qml+2−2
@@ -135,8 +135,8 @@ Showable {
135 enabled: root.draggable
135 enabled: root.draggable
136 direction: Direction.Horizontal
136 direction: Direction.Horizontal
137
137
138− onDraggingChanged: {
138+ onPressedChanged: {
139− if (dragging) {
139+ if (pressed) {
140 root.tease();
140 root.tease();
141 showLabelAnimation.start();
141 showLabelAnimation.start();
142 }
142 }
qml/Launcher/Launcher.qml+3−3
@@ -210,7 +210,7 @@ Item {
210 bottom: parent.bottom
210 bottom: parent.bottom
211 }
211 }
212 x: -width
212 x: -width
213− visible: root.x > 0 || x > -width
213+ visible: root.x > 0 || x > -width || dragArea.pressed
214 model: LauncherModel
214 model: LauncherModel
215
215
216 property bool animate: true
216 property bool animate: true
@@ -283,11 +283,11 @@ Item {
283 width: root.dragAreaWidth
283 width: root.dragAreaWidth
284 height: root.height
284 height: root.height
285
285
286− onTouchXChanged: {
286+ onDistanceChanged: {
287 if (!dragging || launcher.state == "visible")
287 if (!dragging || launcher.state == "visible")
288 return;
288 return;
289
289
290− panel.x = Math.min(0, touchX - panel.width) - root.x
290+ panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
291 }
291 }
292
292
293 onDraggingChanged: {
293 onDraggingChanged: {
qml/Panel/IndicatorsMenu.qml+2−2
@@ -187,8 +187,8 @@ Showable {
187 autoCompleteDragThreshold: maxTotalDragDistance / 2
187 autoCompleteDragThreshold: maxTotalDragDistance / 2
188 stretch: true
188 stretch: true
189
189
190− onDraggingChanged: {
190+ onPressedChanged: {
191− if (dragging) {
191+ if (pressed) {
192 touchPressTime = new Date().getTime();
192 touchPressTime = new Date().getTime();
193 } else {
193 } else {
194 var touchReleaseTime = new Date().getTime();
194 var touchReleaseTime = new Date().getTime();
qml/Shell.qml−1
@@ -58,7 +58,6 @@ Item {
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61− readonly property real panelHeight: panel.panelHeight
62
61
63 property bool sideStageEnabled: shell.width >= units.gu(100)
62 property bool sideStageEnabled: shell.width >= units.gu(100)
64 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
63 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
qml/Stages/SpreadMaths.qml+8−1
@@ -86,7 +86,7 @@ Item {
86 return linearAnimation(0, 1, rightFoldingAreaX, flickableWidth - margins - stackWidth, rightEasing.value);
86 return linearAnimation(0, 1, rightFoldingAreaX, flickableWidth - margins - stackWidth, rightEasing.value);
87 }
87 }
88
88
89− return linearX;
89+ return linearX//margins + foldingAreaWidth + centerEasing.value * (linearX - margins - foldingAreaWidth);
90 }
90 }
91
91
92 readonly property int animatedY: sceneHeight - itemHeight - spreadBottomOffset
92 readonly property int animatedY: sceneHeight - itemHeight - spreadBottomOffset
@@ -128,6 +128,13 @@ Item {
128 return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
128 return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
129 }
129 }
130
130
131+ EasingCurve {
132+ id: centerEasing
133+ type: EasingCurve.InOutSine
134+ property int totalDistance: flickableWidth - foldingAreaWidth * 2 - margins * 2
135+ progress: (linearX - margins - foldingAreaWidth) / totalDistance
136+ }
137+
131 EasingCurve {
138 EasingCurve {
132 id: leftEasing
139 id: leftEasing
133 type: EasingCurve.OutSine
140 type: EasingCurve.OutSine
runtests.sh+3
@@ -42,6 +42,9 @@ sleep 1
42cd -
42cd -
43
43
44make -k qmltests
44make -k qmltests
45+if [ $? -ne 0 ]; then
46+ echo '<?xml version="1.0" encoding="UTF-8" ?><testsuite errors="0" failures="1" tests="1" name="makeExitStatusTest"><properties/><testcase result="fail" name="makeExitStatus"><failure message="Make test did not suceed" result="fail"/></testcase><system-err/></testsuite>' > testMakeExitStatus.xml
47+fi
45
48
46cd -
49cd -
47
50
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+1−1
@@ -47,7 +47,7 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
47 end_y = start_y
47 end_y = start_y
48
48
49 logger.info("Swiping screen from the right edge")
49 logger.info("Swiping screen from the right edge")
50− self.touch.drag(start_x, start_y, end_x, end_y)
50+ self.main_window.pointing_device.drag(start_x, start_y, end_x, end_y)
51
51
52 def launch_fake_app(self):
52 def launch_fake_app(self):
53 _, desktop_file_path = self.create_test_application()
53 _, desktop_file_path = self.create_test_application()
tests/autopilot/unity8/fixture_setup.py+69−3
@@ -18,20 +18,86 @@
18#
18#
19
19
20import fixtures
20import fixtures
21−import subprocess
22import logging
21import logging
22+import os
23+import subprocess
23
24
25+import ubuntuuitoolkit
24from autopilot import introspection
26from autopilot import introspection
25
27
26from unity8 import (
28from unity8 import (
27 get_binary_path,
29 get_binary_path,
28 process_helpers
30 process_helpers
29)
31)
30−from unity8.shell import emulators
32+
31
33
32logger = logging.getLogger(__name__)
34logger = logging.getLogger(__name__)
33
35
34
36
37+class RestartUnityWithTestability(fixtures.Fixture):
38+
39+ """Fixture to launch Unity8 with testability.
40+
41+ :ivar unity_proxy: The Autopilot proxy object for the Unity shell.
42+
43+ """
44+
45+ unity_proxy = None
46+
47+ def __init__(self, binary_path, variables):
48+ """Initialize the fixture instance.
49+
50+ :param str binary_path: The path to the Dash app binary.
51+ :param cli_arguments: The arguments to pass when launching the
52+ :param variables: The variables to use when launching the app.
53+ :type variables: A dictionary.
54+
55+ """
56+ super().__init__()
57+ self.binary_path = binary_path
58+ self.variables = variables
59+
60+ def setUp(self):
61+ """Restart unity with testability when the fixture is used."""
62+ super().setUp()
63+ self.addCleanup(self.stop_unity)
64+ self.restart_unity()
65+
66+ def restart_unity(self):
67+ self.restart_unity_with_testability()
68+
69+ def restart_unity_with_testability(self):
70+ self._unlink_mir_socket()
71+
72+ binary_arg = 'BINARY={}'.format(self.binary_path)
73+ variable_args = [
74+ '{}={}'.format(key, value) for key, value in self.variables.items()
75+ ]
76+ all_args = [binary_arg] + variable_args
77+
78+ self.unity_proxy = process_helpers.restart_unity_with_testability(
79+ *all_args)
80+
81+ def _unlink_mir_socket(self):
82+ # FIXME: we shouldn't be doing this
83+ # $MIR_SOCKET, fallback to $XDG_RUNTIME_DIR/mir_socket and
84+ # /tmp/mir_socket as last resort
85+ try:
86+ os.unlink(
87+ os.getenv('MIR_SOCKET',
88+ os.path.join(os.getenv('XDG_RUNTIME_DIR', "/tmp"),
89+ "mir_socket")))
90+ except OSError:
91+ pass
92+ try:
93+ os.unlink("/tmp/mir_socket")
94+ except OSError:
95+ pass
96+
97+ def stop_unity(self):
98+ process_helpers.stop_job('unity8')
99+
100+
35class LaunchDashApp(fixtures.Fixture):
101class LaunchDashApp(fixtures.Fixture):
36
102
37 """Fixture to launch the Dash app."""
103 """Fixture to launch the Dash app."""
@@ -65,7 +131,7 @@ class LaunchDashApp(fixtures.Fixture):
65 pid = process_helpers.start_job('unity8-dash', *all_args)
131 pid = process_helpers.start_job('unity8-dash', *all_args)
66 return introspection.get_proxy_object_for_existing_process(
132 return introspection.get_proxy_object_for_existing_process(
67 pid=pid,
133 pid=pid,
68− emulator_base=emulators.UnityEmulatorBase,
134+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
69 )
135 )
70
136
71 def stop_application(self):
137 def stop_application(self):
tests/autopilot/unity8/indicators/__init__.py+2−4
@@ -18,10 +18,8 @@
18import ubuntuuitoolkit
18import ubuntuuitoolkit
19from autopilot import introspection
19from autopilot import introspection
20
20
21−from unity8.shell import emulators
22
21
23−
22+class IndicatorPage(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
24−class IndicatorPage(emulators.UnityEmulatorBase):
25
23
26 """Autopilot helper for the IndicatorPage component."""
24 """Autopilot helper for the IndicatorPage component."""
27
25
@@ -166,7 +164,7 @@ class TestIndicatorPage(IndicatorPage):
166 return self.select_single(objectName='indicator.action.slider')
164 return self.select_single(objectName='indicator.action.slider')
167
165
168
166
169−class Slider(emulators.UnityEmulatorBase):
167+class Slider(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
170
168
171 """Autopilot helper for the Slider component."""
169 """Autopilot helper for the Slider component."""
172
170
tests/autopilot/unity8/indicators/tests/__init__.py−2
@@ -40,5 +40,3 @@ class DeviceIndicatorTestCase(IndicatorTestCase):
40 if platform.model() == 'Desktop':
40 if platform.model() == 'Desktop':
41 self.skipTest('Test cannot be run on the desktop.')
41 self.skipTest('Test cannot be run on the desktop.')
42 super().setUp()
42 super().setUp()
43− self.unity_proxy = self.launch_unity()
44− process_helpers.unlock_unity(self.unity_proxy)
tests/autopilot/unity8/process_helpers.py+2−1
@@ -21,6 +21,7 @@ import logging
21import subprocess
21import subprocess
22import dbus
22import dbus
23
23
24+import ubuntuuitoolkit
24from autopilot.exceptions import ProcessSearchError
25from autopilot.exceptions import ProcessSearchError
25from autopilot.introspection import get_proxy_object_for_existing_process
26from autopilot.introspection import get_proxy_object_for_existing_process
26
27
@@ -271,5 +272,5 @@ def _get_unity_pid():
271def _get_unity_proxy_object(pid):
272def _get_unity_proxy_object(pid):
272 return get_proxy_object_for_existing_process(
273 return get_proxy_object_for_existing_process(
273 pid=pid,
274 pid=pid,
274− emulator_base=emulators.UnityEmulatorBase,
275+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
275 )
276 )
tests/autopilot/unity8/shell/__init__.py−24
@@ -19,7 +19,6 @@
19
19
20"""unity shell autopilot tests and emulators - sub level package."""
20"""unity shell autopilot tests and emulators - sub level package."""
21
21
22−from time import sleep
23from functools import wraps
22from functools import wraps
24from gi.repository import Notify
23from gi.repository import Notify
25
24
@@ -38,29 +37,6 @@ def disable_qml_mocking(fn):
38 return wrapper
37 return wrapper
39
38
40
39
41−class DragMixin():
42− def _drag(self, x1, y1, x2, y2):
43− # XXX This ugly code is here just temporarily, waiting for drag
44− # improvements to land on autopilot so we don't have to access device
45− # private internal attributes. --elopio - 2014-02-12
46− cur_x = x1
47− cur_y = y1
48− dx = 1.0 * (x2 - x1) / 100
49− dy = 1.0 * (y2 - y1) / 100
50− for i in range(0, 100):
51− try:
52− self.touch._finger_move(int(cur_x), int(cur_y))
53− except AttributeError:
54− self.touch._device.finger_move(int(cur_x), int(cur_y))
55− sleep(0.002)
56− cur_x += dx
57− cur_y += dy
58− try:
59− self.touch._finger_move(int(x2), int(y2))
60− except AttributeError:
61− self.touch._device.finger_move(int(x2), int(y2))
62−
63−
64def create_ephemeral_notification(
40def create_ephemeral_notification(
65 summary='',
41 summary='',
66 body='',
42 body='',
tests/autopilot/unity8/shell/emulators/__init__.py−6
@@ -17,12 +17,6 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19
19
20−import ubuntuuitoolkit
21−
22−
23−class UnityEmulatorBase(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
24− """A base class for all unity emulators."""
25−
26
20
27class UnityEmulatorException(Exception):
21class UnityEmulatorException(Exception):
28 """Exception raised when there is an error with the Unity emulators."""
22 """Exception raised when there is an error with the Unity emulators."""
tests/autopilot/unity8/shell/emulators/dash.py+6−6
@@ -18,13 +18,13 @@
18#
18#
19
19
20import logging
20import logging
21−import ubuntuuitoolkit
22−
23−from unity8.shell import emulators
24
21
22+import ubuntuuitoolkit
25from autopilot import logging as autopilot_logging
23from autopilot import logging as autopilot_logging
26from autopilot.introspection import dbus
24from autopilot.introspection import dbus
27
25
26+from unity8.shell import emulators
27+
28
28
29logger = logging.getLogger(__name__)
29logger = logging.getLogger(__name__)
30
30
@@ -40,7 +40,7 @@ class DashApp():
40 self.dash = self.main_view.select_single(Dash)
40 self.dash = self.main_view.select_single(Dash)
41
41
42
42
43−class Dash(emulators.UnityEmulatorBase):
43+class Dash(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
44 """An emulator that understands the Dash."""
44 """An emulator that understands the Dash."""
45
45
46 def __init__(self, *args):
46 def __init__(self, *args):
@@ -188,7 +188,7 @@ class ListViewWithPageHeader(ubuntuuitoolkit.QQuickFlickable):
188 pass
188 pass
189
189
190
190
191−class GenericScopeView(emulators.UnityEmulatorBase):
191+class GenericScopeView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
192 """Autopilot emulator for generic scopes."""
192 """Autopilot emulator for generic scopes."""
193
193
194 @autopilot_logging.log_action(logger.info)
194 @autopilot_logging.log_action(logger.info)
@@ -255,5 +255,5 @@ class GenericScopeView(emulators.UnityEmulatorBase):
255 return result
255 return result
256
256
257
257
258−class Preview(emulators.UnityEmulatorBase):
258+class Preview(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
259 """Autopilot custom proxy object for generic previews."""
259 """Autopilot custom proxy object for generic previews."""
tests/autopilot/unity8/shell/emulators/greeter.py+2−4
@@ -1,7 +1,7 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
2#
3# Unity Autopilot Test Suite
3# Unity Autopilot Test Suite
4−# Copyright (C) 2012, 2013, 2014 Canonical
4+# Copyright (C) 2012, 2013, 2014, 2015 Canonical
5#
5#
6# This program is free software: you can redistribute it and/or modify
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
7# it under the terms of the GNU General Public License as published by
@@ -18,12 +18,10 @@
18#
18#
19
19
20import ubuntuuitoolkit
20import ubuntuuitoolkit
21−
22from autopilot.utilities import sleep
21from autopilot.utilities import sleep
23−from unity8.shell.emulators import UnityEmulatorBase
24
22
25
23
26−class Greeter(UnityEmulatorBase):
24+class Greeter(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
27 """An emulator that understands the greeter screen."""
25 """An emulator that understands the greeter screen."""
28
26
29 def wait_swiped_away(self):
27 def wait_swiped_away(self):
tests/autopilot/unity8/shell/emulators/launcher.py+3−2
@@ -1,7 +1,7 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
2#
3# Unity Autopilot Test Suite
3# Unity Autopilot Test Suite
4−# Copyright (C) 2012, 2013, 2014 Canonical
4+# Copyright (C) 2012, 2013, 2014, 2015 Canonical
5#
5#
6# This program is free software: you can redistribute it and/or modify
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
7# it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
20import logging
20import logging
21
21
22import autopilot.logging
22import autopilot.logging
23+import ubuntuuitoolkit
23
24
24from unity8.shell import emulators
25from unity8.shell import emulators
25
26
@@ -27,7 +28,7 @@ from unity8.shell import emulators
27logger = logging.getLogger(__name__)
28logger = logging.getLogger(__name__)
28
29
29
30
30−class Launcher(emulators.UnityEmulatorBase):
31+class Launcher(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
31
32
32 """An emulator that understands the Launcher."""
33 """An emulator that understands the Launcher."""
33
34
tests/autopilot/unity8/shell/emulators/main_window.py+2−2
@@ -19,17 +19,17 @@
19
19
20import logging
20import logging
21
21
22+import ubuntuuitoolkit
22from autopilot import logging as autopilot_logging
23from autopilot import logging as autopilot_logging
23from autopilot import input
24from autopilot import input
24
25
25−from unity8.shell import emulators
26from unity8.shell.emulators.greeter import Greeter
26from unity8.shell.emulators.greeter import Greeter
27from unity8.shell.emulators.launcher import Launcher
27from unity8.shell.emulators.launcher import Launcher
28
28
29logger = logging.getLogger(__name__)
29logger = logging.getLogger(__name__)
30
30
31
31
32−class QQuickView(emulators.UnityEmulatorBase):
32+class QQuickView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
33 """An emulator class that makes it easy to interact with the shell"""
33 """An emulator class that makes it easy to interact with the shell"""
34
34
35 def get_greeter(self):
35 def get_greeter(self):
tests/autopilot/unity8/shell/tests/__init__.py+32−111
@@ -24,17 +24,17 @@ try:
24except ImportError:
24except ImportError:
25 Gio = None
25 Gio = None
26
26
27+import logging
28+import os
29+
27from autopilot import introspection
30from autopilot import introspection
28from autopilot.platform import model
31from autopilot.platform import model
29from autopilot.testcase import AutopilotTestCase
32from autopilot.testcase import AutopilotTestCase
30from autopilot.matchers import Eventually
33from autopilot.matchers import Eventually
31−from autopilot.input import Touch
32from autopilot.display import Display
34from autopilot.display import Display
33−import logging
34−import os.path
35−import subprocess
36−import sys
37from testtools.matchers import Equals
35from testtools.matchers import Equals
36+
37+import ubuntuuitoolkit
38from ubuntuuitoolkit import (
38from ubuntuuitoolkit import (
39 fixture_setup as toolkit_fixtures,
39 fixture_setup as toolkit_fixtures,
40 ubuntu_scenarios
40 ubuntu_scenarios
@@ -51,7 +51,6 @@ from unity8 import (
51 fixture_setup,
51 fixture_setup,
52 process_helpers
52 process_helpers
53)
53)
54−from unity8.shell import emulators
55from unity8.shell.emulators import (
54from unity8.shell.emulators import (
56 dash as dash_helpers,
55 dash as dash_helpers,
57 main_window as main_window_emulator,
56 main_window as main_window_emulator,
@@ -93,36 +92,25 @@ class UnityTestCase(AutopilotTestCase):
93 @classmethod
92 @classmethod
94 def setUpClass(cls):
93 def setUpClass(cls):
95 try:
94 try:
96− output = subprocess.check_output(
95+ is_unity_running = process_helpers.is_job_running('unity8')
97− ["/sbin/initctl", "status", "unity8"],
96+ except process_helpers.JobError as e:
98− stderr=subprocess.STDOUT,
97+ xdg_config_home = os.getenv(
99− universal_newlines=True,
98+ 'XDG_CONFIG_HOME', os.path.join(os.getenv('HOME'), '.config'))
100− )
99+ upstart_config_path = os.path.join(xdg_config_home, 'upstart')
101− except subprocess.CalledProcessError as e:
100+ logger.error(
102− sys.stderr.write(
103− "Error: `initctl status unity8` failed, most probably the "
101+ '`initctl status unity8` failed, most probably the '
104− "unity8 session could not be found:\n\n"
102+ 'unity8 session could not be found:\n\n'
105− "{0}\n"
103+ '{0}\n'
106− "Please install unity8 or copy data/unity8.conf to "
104+ 'Please install unity8 or copy data/unity8.conf to '
107− "{1}\n".format(
105+ '{1}\n'.format(e.output, upstart_config_path)
108− e.output,
109− os.path.join(os.getenv("XDG_CONFIG_HOME",
110− os.path.join(os.getenv("HOME"),
111− ".config")
112− ),
113− "upstart")
114− )
115− )
116− sys.exit(1)
117−
118− if "start/" in output:
119− sys.stderr.write(
120− "Error: Unity is currently running, these tests require it to "
121− "be 'stopped'.\n"
122− "Please run this command before running these tests: \n"
123− "initctl stop unity8\n"
124 )
106 )
125− sys.exit(2)
107+ raise e
108+ else:
109+ assert not is_unity_running, (
110+ 'Unity is currently running, these tests require it to be '
111+ 'stopped.\n'
112+ 'Please run this command before running these tests: \n'
113+ 'initctl stop unity8\n')
126
114
127 def setUp(self):
115 def setUp(self):
128 super().setUp()
116 super().setUp()
@@ -134,13 +122,6 @@ class UnityTestCase(AutopilotTestCase):
134 self._data_dirs_mock_enabled = True
122 self._data_dirs_mock_enabled = True
135 self._environment = {}
123 self._environment = {}
136
124
137− # FIXME: This is a work around re: lp:1238417
138− if model() != "Desktop":
139− from autopilot.input import _uinput
140− _uinput._touch_device = _uinput.create_touch_device()
141− self.addCleanup(_uinput._touch_device.close)
142−
143− self.touch = Touch.create()
144 self._setup_display_details()
125 self._setup_display_details()
145
126
146 def _setup_display_details(self):
127 def _setup_display_details(self):
@@ -196,40 +177,6 @@ class UnityTestCase(AutopilotTestCase):
196 divisor = divisor * 2
177 divisor = divisor * 2
197 return divisor
178 return divisor
198
179
199− def _patch_environment(self, key, value):
200− """Wrapper for patching env for upstart environment."""
201− try:
202− current_value = subprocess.check_output(
203− ["/sbin/initctl", "get-env", "--global", key],
204− stderr=subprocess.STDOUT,
205− universal_newlines=True,
206− ).rstrip()
207− except subprocess.CalledProcessError:
208− current_value = None
209−
210− subprocess.call([
211− "/sbin/initctl",
212− "set-env",
213− "--global",
214− "%s=%s" % (key, value)
215− ], stderr=subprocess.STDOUT)
216− self.addCleanup(self._upstart_reset_env, key, current_value)
217−
218− def _upstart_reset_env(self, key, value):
219− logger.info("Resetting upstart env %s to %s", key, value)
220− if value is None:
221− subprocess.call(
222− ["/sbin/initctl", "unset-env", key],
223− stderr=subprocess.STDOUT,
224− )
225− else:
226− subprocess.call([
227− "/sbin/initctl",
228− "set-env",
229− "--global",
230− "%s=%s" % (key, value)
231− ], stderr=subprocess.STDOUT)
232−
233 def launch_unity(self, mode="full-greeter", *args):
180 def launch_unity(self, mode="full-greeter", *args):
234 """
181 """
235 Launch the unity shell, return a proxy object for it.
182 Launch the unity shell, return a proxy object for it.
@@ -257,21 +204,6 @@ class UnityTestCase(AutopilotTestCase):
257 if self._data_dirs_mock_enabled:
204 if self._data_dirs_mock_enabled:
258 self._patch_data_dirs()
205 self._patch_data_dirs()
259
206
260− # FIXME: we shouldn't be doing this
261− # $MIR_SOCKET, fallback to $XDG_RUNTIME_DIR/mir_socket and
262− # /tmp/mir_socket as last resort
263− try:
264− os.unlink(
265− os.getenv('MIR_SOCKET',
266− os.path.join(os.getenv('XDG_RUNTIME_DIR', "/tmp"),
267− "mir_socket")))
268− except OSError:
269− pass
270− try:
271− os.unlink("/tmp/mir_socket")
272− except OSError:
273− pass
274−
275 unity8_cli_args_list = ["--mode={}".format(mode)]
207 unity8_cli_args_list = ["--mode={}".format(mode)]
276 if len(args) != 0:
208 if len(args) != 0:
277 unity8_cli_args_list += args
209 unity8_cli_args_list += args
@@ -297,26 +229,15 @@ class UnityTestCase(AutopilotTestCase):
297
229
298 def _launch_unity_with_upstart(self, binary_path, args):
230 def _launch_unity_with_upstart(self, binary_path, args):
299 logger.info("Starting unity")
231 logger.info("Starting unity")
232+ self.useFixture(toolkit_fixtures.InitctlEnvironmentVariable(
300− self._patch_environment("QT_LOAD_TESTABILITY", 1)
233+ global_=True, QT_LOAD_TESTABILITY=1))
301−
302− binary_arg = "BINARY=%s" % binary_path
303− extra_args = "ARGS=%s" % " ".join(args)
304− env_args = ["%s=%s" % (k, v) for k, v in self._environment.items()]
305− all_args = [binary_arg, extra_args] + env_args
306
234
307− self.addCleanup(self._cleanup_launching_upstart_unity)
235+ variables = self._environment
308−
236+ variables['ARGS'] = " ".join(args)
309− return process_helpers.restart_unity_with_testability(*all_args)
237+ launch_unity_fixture = fixture_setup.RestartUnityWithTestability(
310−
238+ binary_path, variables)
311− def _cleanup_launching_upstart_unity(self):
239+ self.useFixture(launch_unity_fixture)
312− logger.info("Stopping unity")
240+ return launch_unity_fixture.unity_proxy
313− try:
314− subprocess.check_output(
315− ["/sbin/initctl", "stop", "unity8"],
316− stderr=subprocess.STDOUT
317− )
318− except subprocess.CalledProcessError:
319− logger.warning("Appears unity was already stopped!")
320
241
321 def _patch_data_dirs(self):
242 def _patch_data_dirs(self):
322 data_dirs = get_data_dirs(self._data_dirs_mock_enabled)
243 data_dirs = get_data_dirs(self._data_dirs_mock_enabled)
@@ -369,7 +290,7 @@ class UnityTestCase(AutopilotTestCase):
369 pid = process_helpers.get_job_pid('unity8-dash')
290 pid = process_helpers.get_job_pid('unity8-dash')
370 dash_proxy = introspection.get_proxy_object_for_existing_process(
291 dash_proxy = introspection.get_proxy_object_for_existing_process(
371 pid=pid,
292 pid=pid,
372− emulator_base=emulators.UnityEmulatorBase,
293+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
373 )
294 )
374 dash_app = dash_helpers.DashApp(dash_proxy)
295 dash_app = dash_helpers.DashApp(dash_proxy)
375 return dash_app.dash
296 return dash_app.dash
tests/autopilot/unity8/shell/tests/test_upstart.py+5−4
@@ -1,7 +1,7 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
2#
3# Unity Autopilot Test Suite
3# Unity Autopilot Test Suite
4−# Copyright (C) 2013, 2014 Canonical
4+# Copyright (C) 2013, 2014, 2015 Canonical
5#
5#
6# This program is free software: you can redistribute it and/or modify
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
7# it under the terms of the GNU General Public License as published by
@@ -26,13 +26,13 @@ import subprocess
26import time
26import time
27
27
28import fixtures
28import fixtures
29−from testtools.matchers import Equals, MismatchError
29+import ubuntuuitoolkit
30from autopilot.matchers import Eventually
30from autopilot.matchers import Eventually
31from autopilot.introspection import get_proxy_object_for_existing_process
31from autopilot.introspection import get_proxy_object_for_existing_process
32+from testtools.matchers import Equals, MismatchError
32from ubuntuuitoolkit import ubuntu_scenarios
33from ubuntuuitoolkit import ubuntu_scenarios
33
34
34from unity8 import get_binary_path
35from unity8 import get_binary_path
35−from unity8.shell.emulators import UnityEmulatorBase
36from unity8.shell.tests import UnityTestCase
36from unity8.shell.tests import UnityTestCase
37
37
38import logging
38import logging
@@ -90,10 +90,11 @@ class UpstartIntegrationTests(UnityTestCase):
90 self.addCleanup(ensure_stopped)
90 self.addCleanup(ensure_stopped)
91
91
92 def _set_proxy(self):
92 def _set_proxy(self):
93+ proxy_base = ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
93 super()._set_proxy(
94 super()._set_proxy(
94 get_proxy_object_for_existing_process(
95 get_proxy_object_for_existing_process(
95 pid=self.process.pid,
96 pid=self.process.pid,
96− emulator_base=UnityEmulatorBase,))
97+ emulator_base=proxy_base))
97
98
98 def test_no_sigstop(self):
99 def test_no_sigstop(self):
99 self.useFixture(
100 self.useFixture(
tests/plugins/Dash/listviewwithpageheadertest.cpp+8−2
@@ -973,9 +973,15 @@ private Q_SLOTS:
973 QCOMPARE(lvwph->contentY(), 1258.);
973 QCOMPARE(lvwph->contentY(), 1258.);
974 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
974 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
975
975
976− changeContentY(-1700);
976+ changeContentY(-800);
977−
977+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
978+ changeContentY(-400);
979+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
980+ changeContentY(-200);
981+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 10);
982+ changeContentY(-300);
978 QTRY_COMPARE(lvwph->m_visibleItems.count(), 12);
983 QTRY_COMPARE(lvwph->m_visibleItems.count(), 12);
984+
979 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
985 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
980 verifyItem(0, -308., 75., true);
986 verifyItem(0, -308., 75., true);
981 verifyItem(1, -233., 75., true);
987 verifyItem(1, -233., 75., true);
tests/qmltests/Components/CMakeLists.txt+17−3
@@ -1,3 +1,7 @@
1+add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
2+add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
3+add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
4+
1########## tst_DragHandle
5########## tst_DragHandle
2
6
3include_directories(
7include_directories(
@@ -15,6 +19,16 @@ target_link_libraries(DragHandleTestExec UbuntuGesturesQml UbuntuGestures)
15add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
19add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
16add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/utils/modules)
20add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/utils/modules)
17
21
18−add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
22+########## tst_EdgeDragEvaluator
19−add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
23+
20−add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
24+include_directories(
25+ ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
26+ ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
27+ ${CMAKE_CURRENT_BINARY_DIR}
28+ )
29+
30+add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
31+qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
32+target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml UbuntuGestures)
33+
34+add_binary_qml_test(EdgeDragEvaluator ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
tests/qmltests/Components/tst_EdgeDragEvaluator.cppnew file+165
@@ -0,0 +1,165 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <functional>
18+#include <QtTest>
19+#include <QObject>
20+#include <QQuickView>
21+#include <QQmlEngine>
22+#include <QQuickItem>
23+
24+// Ubuntu.Gestures plugin
25+#include <AxisVelocityCalculator.h>
26+#include <Direction.h>
27+#include <Timer.h>
28+
29+using namespace UbuntuGestures;
30+
31+class tst_EdgeDragEvaluator: public QObject
32+{
33+ Q_OBJECT
34+public:
35+ tst_EdgeDragEvaluator() {}
36+private Q_SLOTS:
37+ void initTestCase(); // will be called before the first test function is executed
38+ void cleanupTestCase(); // will be called after the last test function was executed.
39+
40+ void init(); // called right before each and every test function is executed
41+ void cleanup(); // called right after each and every test function is executed
42+
43+ void horizontalDirection();
44+ void horizontalDirection_data();
45+
46+private:
47+ void drag(qreal &pos, qreal distance, qreal speed);
48+
49+ QQuickView *createView();
50+ QQuickView *m_view;
51+ FakeTimer *m_fakeTimer;
52+ QSharedPointer<FakeTimeSource> m_fakeTimeSource;
53+ AxisVelocityCalculator *m_dragEvaluator;
54+};
55+
56+
57+void tst_EdgeDragEvaluator::initTestCase()
58+{
59+ m_view = 0;
60+}
61+
62+void tst_EdgeDragEvaluator::cleanupTestCase()
63+{
64+}
65+
66+void tst_EdgeDragEvaluator::init()
67+{
68+
69+ m_view = createView();
70+ m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_EdgeDragEvaluator.qml"));
71+ m_view->show();
72+ QVERIFY(QTest::qWaitForWindowExposed(m_view));
73+ QVERIFY(m_view->rootObject() != 0);
74+ qApp->processEvents();
75+
76+ m_fakeTimeSource.reset(new FakeTimeSource);
77+ m_fakeTimer = new FakeTimer(m_fakeTimeSource);
78+
79+ m_dragEvaluator =
80+ m_view->rootObject()->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
81+ QVERIFY(m_dragEvaluator);
82+ m_dragEvaluator->setTimeSource(m_fakeTimeSource);
83+}
84+
85+void tst_EdgeDragEvaluator::cleanup()
86+{
87+ m_dragEvaluator = nullptr;
88+
89+ delete m_view;
90+ m_view = 0;
91+
92+ delete m_fakeTimer;
93+ m_fakeTimer = 0;
94+
95+ m_fakeTimeSource.reset();
96+}
97+
98+QQuickView *tst_EdgeDragEvaluator::createView()
99+{
100+ QQuickView *window = new QQuickView(0);
101+ window->setResizeMode(QQuickView::SizeRootObjectToView);
102+ window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
103+ window->engine()->addImportPath(QLatin1String(TEST_DIR));
104+
105+ return window;
106+}
107+
108+void tst_EdgeDragEvaluator::drag(qreal &pos, qreal distance, qreal speed)
109+{
110+ int numSteps = 10;
111+ qreal distanceStep = distance / ((qreal)numSteps);
112+ int timeStep = qAbs(distanceStep / speed);
113+
114+ for (int i = 0; i < numSteps; ++i) {
115+ m_fakeTimeSource->m_msecsSinceReference += timeStep;
116+ pos += distanceStep;
117+ m_dragEvaluator->setTrackedPosition(pos);
118+ }
119+}
120+
121+void tst_EdgeDragEvaluator::horizontalDirection()
122+{
123+ qreal maxDragDistance = 100.;
124+ qreal speedThreshold = 100.;
125+ qreal speedThresholdMs = speedThreshold / 1000.;
126+ QFETCH(qreal, dragDirection);
127+
128+ m_dragEvaluator->setProperty("maxDragDistance", QVariant::fromValue(maxDragDistance));
129+ m_dragEvaluator->setProperty("dragThreshold", QVariant::fromValue(maxDragDistance * 0.5));
130+ m_dragEvaluator->setProperty("speedThreshold", QVariant::fromValue(speedThreshold));
131+
132+ // If direction is "Horizontal" it means it can drag leftwards or rightwards
133+ m_dragEvaluator->setProperty("direction", QVariant::fromValue((int)Direction::Horizontal));
134+
135+ qreal pos = 0.;
136+ m_dragEvaluator->setTrackedPosition(pos);
137+
138+ // Go far beyond dragThreshold
139+ drag(pos, maxDragDistance * 0.75 * dragDirection /*distance*/, speedThresholdMs * 0.5 /*speed*/);
140+
141+ // Then come back a bit, getting close to dragThreshold
142+ drag(pos, -maxDragDistance * 0.20 * dragDirection /*distance*/, speedThresholdMs * 0.5 /*speed*/);
143+
144+ QVariant shouldAutoComplete;
145+ bool ok = QMetaObject::invokeMethod(m_dragEvaluator, "shouldAutoComplete", Qt::DirectConnection,
146+ Q_RETURN_ARG(QVariant, shouldAutoComplete));
147+ QVERIFY(ok);
148+
149+ // It should not autocomplete because the current negative velocity (speedThresholdMs * 0.5)
150+ // is bigger (in absolute terms) than the minimum negative velocity at this position needed to
151+ // cancel autocompletion (speedThreshold * 0.1)
152+ QCOMPARE(shouldAutoComplete.toBool(), false);
153+}
154+
155+void tst_EdgeDragEvaluator::horizontalDirection_data()
156+{
157+ QTest::addColumn<qreal>("dragDirection");
158+
159+ QTest::newRow("right") << 1.;
160+ QTest::newRow("left") << -1.;
161+}
162+
163+QTEST_MAIN(tst_EdgeDragEvaluator)
164+
165+#include "tst_EdgeDragEvaluator.moc"
tests/qmltests/Components/tst_EdgeDragEvaluator.qmlnew file+27
@@ -0,0 +1,27 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../../qml/Components"
19+
20+Item {
21+ width: units.gu(70)
22+ height: units.gu(70)
23+
24+ EdgeDragEvaluator {
25+ objectName: "edgeDragEvaluator"
26+ }
27+}
tests/qmltests/tst_Shell.qml+14−10
@@ -461,11 +461,11 @@ Rectangle {
461 function test_phoneLeftEdgeDrag_data() {
461 function test_phoneLeftEdgeDrag_data() {
462 return [
462 return [
463 {tag: "without launcher",
463 {tag: "without launcher",
464− revealLauncher: false, swipeLength: units.gu(27), appHides: true, focusedApp: "dialer-app",
464+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
465 launcherHides: true, greeterShown: false},
465 launcherHides: true, greeterShown: false},
466
466
467 {tag: "with launcher",
467 {tag: "with launcher",
468− revealLauncher: true, swipeLength: units.gu(27), appHides: true, focusedApp: "dialer-app",
468+ revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
469 launcherHides: true, greeterShown: false},
469 launcherHides: true, greeterShown: false},
470
470
471 {tag: "small swipe",
471 {tag: "small swipe",
@@ -473,7 +473,7 @@ Rectangle {
473 launcherHides: false, greeterShown: false},
473 launcherHides: false, greeterShown: false},
474
474
475 {tag: "long swipe",
475 {tag: "long swipe",
476− revealLauncher: false, swipeLength: units.gu(27), appHides: true, focusedApp: "dialer-app",
476+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
477 launcherHides: true, greeterShown: false},
477 launcherHides: true, greeterShown: false},
478
478
479 {tag: "small swipe with greeter",
479 {tag: "small swipe with greeter",
@@ -481,11 +481,11 @@ Rectangle {
481 launcherHides: false, greeterShown: true},
481 launcherHides: false, greeterShown: true},
482
482
483 {tag: "long swipe with greeter",
483 {tag: "long swipe with greeter",
484− revealLauncher: false, swipeLength: units.gu(27), appHides: true, focusedApp: "dialer-app",
484+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
485 launcherHides: true, greeterShown: true},
485 launcherHides: true, greeterShown: true},
486
486
487 {tag: "swipe over dash",
487 {tag: "swipe over dash",
488− revealLauncher: false, swipeLength: units.gu(27), appHides: true, focusedApp: "unity8-dash",
488+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
489 launcherHides: false, greeterShown: false},
489 launcherHides: false, greeterShown: false},
490 ];
490 ];
491 }
491 }
@@ -690,7 +690,7 @@ Rectangle {
690
690
691 dashCommunicatorSpy.clear();
691 dashCommunicatorSpy.clear();
692 // Minimize the application we just launched
692 // Minimize the application we just launched
693− swipeFromLeftEdge(units.gu(27));
693+ swipeFromLeftEdge(shell.width * 0.75);
694
694
695 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
695 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
696
696
@@ -847,7 +847,8 @@ Rectangle {
847 }
847 }
848
848
849 function dragLauncherIntoView() {
849 function dragLauncherIntoView() {
850− var launcherPanel = findChild(shell, "launcherPanel");
850+ var launcher = findChild(shell, "launcher");
851+ var launcherPanel = findChild(launcher, "launcherPanel");
851 verify(launcherPanel.x = - launcherPanel.width);
852 verify(launcherPanel.x = - launcherPanel.width);
852
853
853 var touchStartX = 2;
854 var touchStartX = 2;
@@ -855,6 +856,7 @@ Rectangle {
855 touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
856 touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
856
857
857 tryCompare(launcherPanel, "x", 0);
858 tryCompare(launcherPanel, "x", 0);
859+ tryCompare(launcher, "state", "visible");
858 }
860 }
859
861
860 function tapOnAppIconInLauncher() {
862 function tapOnAppIconInLauncher() {
@@ -891,7 +893,9 @@ Rectangle {
891 function swipeFromLeftEdge(swipeLength) {
893 function swipeFromLeftEdge(swipeLength) {
892 var touchStartX = 2;
894 var touchStartX = 2;
893 var touchStartY = shell.height / 2;
895 var touchStartY = shell.height / 2;
896+ touchFlick(shell,
894− touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY);
897+ touchStartX , touchStartY,
898+ touchStartX + swipeLength, touchStartY);
895 }
899 }
896
900
897 function itemIsOnScreen(item) {
901 function itemIsOnScreen(item) {
@@ -958,7 +962,7 @@ Rectangle {
958 tryCompareFunction(function() { return app.session !== null && app.session.surface !== null }, true);
962 tryCompareFunction(function() { return app.session !== null && app.session.surface !== null }, true);
959
963
960 // Minimize the application we just launched
964 // Minimize the application we just launched
961− swipeFromLeftEdge(units.gu(26) + 1);
965+ swipeFromLeftEdge(shell.width * 0.75);
962
966
963 waitUntilDashIsFocused();
967 waitUntilDashIsFocused();
964
968
@@ -1040,7 +1044,7 @@ Rectangle {
1040
1044
1041 compare(panel.fullscreenMode, true);
1045 compare(panel.fullscreenMode, true);
1042
1046
1043− touchFlick(shell, units.gu(2), touchStartY, units.gu(10), touchStartY, false, false);
1047+ touchFlick(shell, units.gu(2), touchStartY, shell.width * 0.5, touchStartY, false, false);
1044
1048
1045 tryCompare(panel, "fullscreenMode", false);
1049 tryCompare(panel, "fullscreenMode", false);
1046
1050
tests/qmltests/tst_ShellWithPin.qml+2−2
@@ -612,14 +612,14 @@ Item {
612 tryCompare(coverPage, "showProgress", 1);
612 tryCompare(coverPage, "showProgress", 1);
613
613
614 // Swipe cover page away
614 // Swipe cover page away
615− touchFlick(shell, 2, shell.height / 2, units.gu(27), shell.height / 2);
615+ touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
616 tryCompare(launcher, "x", -launcher.width);
616 tryCompare(launcher, "x", -launcher.width);
617 tryCompare(coverPage, "showProgress", 0);
617 tryCompare(coverPage, "showProgress", 0);
618 compare(lockscreen.shown, true);
618 compare(lockscreen.shown, true);
619 compare(ApplicationManager.focusedApplicationId, "gallery-app");
619 compare(ApplicationManager.focusedApplicationId, "gallery-app");
620
620
621 // Now attempt a swipe on lockscreen
621 // Now attempt a swipe on lockscreen
622− touchFlick(shell, 2, shell.height / 2, units.gu(27), shell.height / 2);
622+ touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
623 tryCompare(launcher, "x", 0);
623 tryCompare(launcher, "x", 0);
624 compare(lockscreen.shown, true);
624 compare(lockscreen.shown, true);
625 compare(ApplicationManager.focusedApplicationId, "gallery-app");
625 compare(ApplicationManager.focusedApplicationId, "gallery-app");
tests/utils/modules/Unity/Test/UnityTestCase.qml+3−4
@@ -269,7 +269,7 @@ TestCase {
269 speed = (speed !== undefined) ? speed : units.gu(10)
269 speed = (speed !== undefined) ? speed : units.gu(10)
270
270
271 // Set a default iterations if not specified
271 // Set a default iterations if not specified
272− var iterations = (iterations !== undefined) ? iterations : 5
272+ var iterations = (iterations !== undefined) ? iterations : 10
273
273
274 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
274 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
275 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
275 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
@@ -403,9 +403,8 @@ TestCase {
403 function removeTimeConstraintsFromDirectionalDragAreas(item) {
403 function removeTimeConstraintsFromDirectionalDragAreas(item) {
404
404
405 // use duck-typing to identify a DirectionalDragArea
405 // use duck-typing to identify a DirectionalDragArea
406− if (item.maxTime != undefined && item.compositionTime != undefined) {
406+ if (item.removeTimeConstraints != undefined) {
407− item.maxTime = 60 * 60 * 1000;
407+ item.removeTimeConstraints();
408− item.compositionTime = 0;
409 } else {
408 } else {
410 for (var i in item.children) {
409 for (var i in item.children) {
411 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
410 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);