@@ -0,0 +1,285 @@
1+/*
2+ * Copyright (C) 2013,2014 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 QtTest 1.0
19+import GSettings 1.0
20+import LightDM 0.1 as LightDM
21+import Ubuntu.Components 1.1
22+import Ubuntu.Telephony 0.1 as Telephony
23+import Unity.Application 0.1
24+import Unity.Connectivity 0.1
25+import Unity.Test 0.1 as UT
26+import Powerd 0.1
27+
28+import "../../qml"
29+
30+Row {
31+ id: root
32+ spacing: 0
33+
34+ QtObject {
35+ id: applicationArguments
36+
37+ function hasGeometry() {
38+ return false
39+ }
40+
41+ function width() {
42+ return 0
43+ }
44+
45+ function height() {
46+ return 0
47+ }
48+ }
49+
50+ Loader {
51+ id: shellLoader
52+
53+ width: units.gu(100)
54+ height: units.gu(80)
55+
56+ property bool itemDestroyed: false
57+ sourceComponent: Component {
58+ Shell {
59+ Component.onDestruction: {
60+ shellLoader.itemDestroyed = true
61+ }
62+ }
63+ }
64+ }
65+
66+ Rectangle {
67+ color: "white"
68+ width: units.gu(20)
69+ height: shellLoader.height
70+
71+ Column {
72+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
73+ spacing: units.gu(1)
74+ Row {
75+ anchors { left: parent.left; right: parent.right }
76+ Button {
77+ text: "Show Greeter"
78+ onClicked: {
79+ if (shellLoader.status !== Loader.Ready)
80+ return
81+
82+ var greeter = testCase.findChild(shellLoader.item, "greeter")
83+ if (!greeter.shown) {
84+ greeter.show()
85+ }
86+ }
87+ }
88+ }
89+ }
90+ }
91+
92+ SignalSpy {
93+ id: sessionSpy
94+ signalName: "sessionStarted"
95+ }
96+
97+ SignalSpy {
98+ id: dashCommunicatorSpy
99+ signalName: "setCurrentScopeCalled"
100+ }
101+
102+ SignalSpy {
103+ id: unlockAllModemsSpy
104+ target: Connectivity
105+ signalName: "unlockingAllModems"
106+ }
107+
108+ Telephony.CallEntry {
109+ id: phoneCall
110+ phoneNumber: "+447812221111"
111+ }
112+
113+ UT.UnityTestCase {
114+ id: testCase
115+ name: "Shell"
116+ when: windowShown
117+
118+ property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
119+
120+ function init() {
121+ sessionSpy.clear()
122+ sessionSpy.target = findChild(shell, "greeter")
123+ dashCommunicatorSpy.target = findInvisibleChild(shell, "dashCommunicator")
124+ }
125+
126+ function cleanup() {
127+ shellLoader.itemDestroyed = false
128+
129+ shellLoader.active = false
130+
131+ tryCompare(shellLoader, "status", Loader.Null)
132+ tryCompare(shellLoader, "item", null)
133+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
134+ // item might still be alive. So if we set Loader.active back to true
135+ // again right now we will get the very same Shell instance back. So no reload
136+ // actually took place. Likely because Loader waits until the next event loop
137+ // iteration to do its work. So to ensure the reload, we will wait until the
138+ // Shell instance gets destroyed.
139+ tryCompare(shellLoader, "itemDestroyed", true)
140+
141+ // kill all (fake) running apps
142+ killApps(ApplicationManager)
143+
144+ unlockAllModemsSpy.clear()
145+
146+ // reload our test subject to get it in a fresh state once again
147+ shellLoader.active = true
148+
149+ tryCompare(shellLoader, "status", Loader.Ready)
150+ removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item)
151+ }
152+
153+ function killApps() {
154+ while (ApplicationManager.count > 1) {
155+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
156+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId)
157+ }
158+ compare(ApplicationManager.count, 1)
159+ }
160+
161+ function selectIndex(i) {
162+ // We could be anywhere in list; find target index to know which direction
163+ var greeter = findChild(shell, "greeter")
164+ var userlist = findChild(greeter, "userList")
165+ if (userlist.currentIndex == i)
166+ keyClick(Qt.Key_Escape) // Reset state if we're not moving
167+ while (userlist.currentIndex != i) {
168+ var next = userlist.currentIndex + 1
169+ if (userlist.currentIndex > i) {
170+ next = userlist.currentIndex - 1
171+ }
172+ var account = findChild(greeter, "username"+next)
173+ mouseClick(account, 1, 1)
174+ tryCompare(userlist, "currentIndex", next)
175+ tryCompare(userlist, "movingInternally", false)
176+ }
177+ }
178+
179+ function selectUser(name) {
180+ // Find index of user with the right name
181+ var greeter = findChild(shell, "greeter")
182+ for (var i = 0; i < greeter.model.count; i++) {
183+ if (greeter.model.data(i, LightDM.UserRoles.NameRole) == name) {
184+ break
185+ }
186+ }
187+ if (i == greeter.model.count) {
188+ fail("Didn't find name")
189+ return -1
190+ }
191+ selectIndex(i)
192+ return i
193+ }
194+
195+ function clickPasswordInput() {
196+ var greeter = findChild(shell, "greeter")
197+ tryCompare(greeter, "showProgress", 1)
198+
199+ var passwordInput = findChild(shell, "passwordInput")
200+ mouseClick(passwordInput, passwordInput.width / 2, passwordInput.height / 2)
201+ }
202+
203+ function confirmLoggedIn(loggedIn) {
204+ var greeter = findChild(shell, "greeter")
205+ tryCompare(greeter, "showProgress", loggedIn ? 0 : 1)
206+ tryCompare(sessionSpy, "count", loggedIn ? 1 : 0)
207+ }
208+
209+ function swipeFromLeftEdge(swipeLength) {
210+ var touchStartX = 2
211+ var touchStartY = shell.height / 2
212+ touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY)
213+ }
214+
215+ function test_noLockscreen() {
216+ selectUser("has-password")
217+ var lockscreen = findChild(shell, "lockscreen")
218+ tryCompare(lockscreen, "shown", false)
219+ }
220+
221+ function test_showAndHideGreeterDBusCalls() {
222+ var greeter = findChild(shell, "greeter")
223+ LightDM.Greeter.hideGreeter()
224+ tryCompare(greeter, "showProgress", 0)
225+ LightDM.Greeter.showGreeter()
226+ tryCompare(greeter, "showProgress", 1)
227+ }
228+
229+ function test_login_data() {
230+ return [
231+ //{tag: "auth error", user: "auth-error", loggedIn: false, password: ""},
232+ //{tag: "without password", user: "no-password", loggedIn: true, password: ""},
233+ {tag: "with password", user: "has-password", loggedIn: true, password: "password"},
234+ ]
235+ }
236+
237+ function test_login(data) {
238+ selectUser(data.user)
239+
240+ clickPasswordInput()
241+
242+ if (data.password !== "") {
243+ typeString(data.password)
244+ keyClick(Qt.Key_Enter)
245+ }
246+
247+ confirmLoggedIn(data.loggedIn)
248+ }
249+
250+ function test_appLaunchDuringGreeter_data() {
251+ return [
252+ {tag: "auth error", user: "auth-error", loggedIn: false, passwordFocus: false},
253+ {tag: "without password", user: "no-password", loggedIn: true, passwordFocus: false},
254+ {tag: "with password", user: "has-password", loggedIn: false, passwordFocus: true},
255+ ]
256+ }
257+
258+ function test_appLaunchDuringGreeter(data) {
259+ selectUser(data.user)
260+
261+ var greeter = findChild(shell, "greeter")
262+ var app = ApplicationManager.startApplication("dialer-app")
263+
264+ confirmLoggedIn(data.loggedIn)
265+
266+ if (data.passwordFocus) {
267+ var passwordInput = findChild(greeter, "passwordInput")
268+ tryCompare(passwordInput, "focus", true)
269+ }
270+ }
271+
272+ function test_leftEdgeDrag_data() {
273+ return [
274+ {tag: "without password", user: "no-password", loggedIn: true},
275+ {tag: "with password", user: "has-password", loggedIn: false},
276+ ]
277+ }
278+
279+ function test_leftEdgeDrag(data) {
280+ selectUser(data.user)
281+ swipeFromLeftEdge(shell.width * 0.75)
282+ confirmLoggedIn(data.loggedIn)
283+ }
284+ }
285+}