@@ -23,25 +23,33 @@ import LightDM 0.1 as LightDM
2323import Unity.Test 0.1 as UT
2424
2525Rectangle {
26− width: units.gu(60)
26+ id: root
27+ width: units.gu(80)
2728 height: units.gu(80)
2829 color: "orange"
2930
3031 Lockscreen {
3132 id: lockscreen
3233 anchors.fill: parent
33− anchors.rightMargin: units.gu(18)
34+ anchors.rightMargin: units.gu(30)
3435 placeholderText: "Please enter your PIN"
36+ wrongPlaceholderText: "Incorrect PIN"
37+ retryText: retryCountTextField.text
3538 alphaNumeric: pinPadCheckBox.checked
36− pinLength: pinLengthTextField.text
39+ minPinLength: minPinLengthTextField.text
40+ maxPinLength: maxPinLengthTextField.text
3741 username: "Lola"
42+ infoText: infoTextTextField.text
3843 }
3944
4045 Connections {
4146 target: lockscreen
4247
4348 onEmergencyCall: emergencyCheckBox.checked = true
44− onEntered: enteredLabel.text = passphrase
49+ onEntered: {
50+ enteredLabel.text = passphrase
51+ lockscreen.clear(true)
52+ }
4553 }
4654
4755 Connections {
@@ -49,9 +57,9 @@ Rectangle {
4957
5058 onShowPrompt: {
5159 if (text.indexOf("PIN") >= 0) {
52− lockscreen.alphaNumeric = false
60+ pinPadCheckBox.checked = false
5361 } else {
54− lockscreen.alphaNumeric = true
62+ pinPadCheckBox.checked = true
5563 }
5664 lockscreen.placeholderText = text;
5765 }
@@ -65,6 +73,7 @@ Rectangle {
6573 Column {
6674 anchors.fill: parent
6775 anchors.margins: units.gu(1)
76+ spacing: units.gu(1)
6877
6978 Row {
7079 CheckBox {
@@ -86,12 +95,32 @@ Rectangle {
8695 }
8796 Row {
8897 TextField {
89− id: pinLengthTextField
98+ id: minPinLengthTextField
9099 width: units.gu(7)
91100 text: "4"
92101 }
93102 Label {
94− text: "PIN length"
103+ text: "Min PIN length"
104+ }
105+ }
106+ Row {
107+ TextField {
108+ id: maxPinLengthTextField
109+ width: units.gu(7)
110+ text: "4"
111+ }
112+ Label {
113+ text: "Max PIN length"
114+ }
115+ }
116+ Row {
117+ TextField {
118+ id: retryCountTextField
119+ width: units.gu(7)
120+ text: "3 retries left"
121+ }
122+ Label {
123+ text: "Retries left"
95124 }
96125 }
97126 Label {
@@ -108,12 +137,40 @@ Rectangle {
108137 }
109138 Button {
110139 text: "start auth (1234)"
140+ width: parent.width
111141 onClicked: LightDM.Greeter.authenticate("has-pin")
112142 }
113143 Button {
114144 text: "start auth (password)"
145+ width: parent.width
115146 onClicked: LightDM.Greeter.authenticate("has-password")
116147 }
148+
149+ TextField {
150+ id: infoTextTextField
151+ width: parent.width
152+ placeholderText: "Infotext"
153+ text: "+49 179 3253553"
154+ }
155+
156+ TextField {
157+ id: infoPopupTitleTextField
158+ width: parent.width
159+ placeholderText: "Popup title"
160+ text: "This will be the last attempt"
161+ }
162+
163+ TextArea {
164+ id: infoPopupTextArea
165+ width: parent.width
166+ text: "If the SIM PIN is entered incorrectly, your SIM will be blocked and would require the PUK code to unlock."
167+ }
168+
169+ Button {
170+ text: "open info popup"
171+ width: parent.width
172+ onClicked: lockscreen.showInfoPopup(infoPopupTitleTextField.text, infoPopupTextArea.text)
173+ }
117174 }
118175 }
119176
@@ -121,6 +178,16 @@ Rectangle {
121178 name: "Lockscreen"
122179 when: windowShown
123180
181+ function cleanup() {
182+ lockscreen.clear(false);
183+ }
184+
185+ function waitForLockscreenReady() {
186+ var pinPadLoader = findChild(lockscreen, "pinPadLoader");
187+ tryCompare(pinPadLoader, "status", Loader.Ready)
188+ waitForRendering(lockscreen)
189+ }
190+
124191 function test_loading_data() {
125192 return [
126193 {tag: "numeric", alphanumeric: false, pinPadAvailable: true },
@@ -129,8 +196,8 @@ Rectangle {
129196 }
130197
131198 function test_loading(data) {
132− lockscreen.alphaNumeric = data.alphanumeric
133− waitForRendering(lockscreen)
199+ pinPadCheckBox.checked = data.alphanumeric
200+ waitForLockscreenReady();
134201 if (data.pinPadAvailable) {
135202 compare(findChild(lockscreen, "pinPadButton8").text, "8", "Could not find number 8 on PinPad")
136203 } else {
@@ -147,8 +214,8 @@ Rectangle {
147214
148215 function test_emergency_call(data) {
149216 emergencyCheckBox.checked = false
150− lockscreen.alphaNumeric = data.alphanumeric
151− waitForRendering(lockscreen)
217+ pinPadCheckBox.checked = data.alphanumeric
218+ waitForLockscreenReady();
152219 var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
153220 mouseClick(emergencyButton, units.gu(1), units.gu(1))
154221 tryCompare(emergencyCheckBox, "checked", true)
@@ -163,9 +230,9 @@ Rectangle {
163230 }
164231
165232 function test_labels(data) {
166− lockscreen.alphaNumeric = data.alphanumeric
233+ pinPadCheckBox.checked = data.alphanumeric
167234 lockscreen.placeholderText = data.placeholderText
168− waitForRendering(lockscreen)
235+ waitForLockscreenReady();
169236 compare(findChild(lockscreen, "pinentryField").placeholderText, data.placeholderText, "Placeholdertext is not what it should be")
170237 if (data.alphanumeric) {
171238 compare(findChild(lockscreen, "greeterLabel").text, "Hello " + data.username, "Greeter is not set correctly")
@@ -175,23 +242,25 @@ Rectangle {
175242
176243 function test_unlock_data() {
177244 return [
178− {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", pinLength: 4},
179− {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", pinLength: -1},
180− {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", pinLength: 4},
181− {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", pinLength: -1},
182− {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", pinLength: -1},
245+ {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: 4, maxPinLength: 4},
246+ {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", minPinLength: -1, maxPinLength: -1},
247+ {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", minPinLength: 4, maxPinLength: 4},
248+ {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", minPinLength: -1, maxPinLength: -1},
249+ {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: -1, maxPinLength: -1},
183250 ]
184251 }
185252
186253 function test_unlock(data) {
187254 enteredLabel.text = ""
188− pinLengthTextField.text = data.pinLength
255+ minPinLengthTextField.text = data.minPinLength
256+ maxPinLengthTextField.text = data.maxPinLength
189257 LightDM.Greeter.authenticate(data.username)
190− waitForRendering(lockscreen)
258+ waitForLockscreenReady();
191259
192260 var inputField = findChild(lockscreen, "pinentryField")
193261 if (data.alphanumeric) {
194262 mouseClick(inputField, units.gu(1), units.gu(1))
263+ tryCompare(inputField, "focus", true);
195264 typeString(data.password)
196265 keyClick(Qt.Key_Enter)
197266 } else {
@@ -200,7 +269,7 @@ Rectangle {
200269 var button = findChild(lockscreen, "pinPadButton" + character)
201270 mouseClick(button, units.gu(1), units.gu(1))
202271 }
203− if (data.pinLength == -1) {
272+ if (data.minPinLength !== data.maxPinLength || data.minPinLength == -1) {
204273 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
205274 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
206275 }
@@ -219,11 +288,12 @@ Rectangle {
219288
220289 function test_clear(data) {
221290 pinPadCheckBox.checked = data.alphanumeric
222− waitForRendering(lockscreen)
291+ waitForLockscreenReady();
223292
224293 var inputField = findChild(lockscreen, "pinentryField")
225294 if (data.alphanumeric) {
226295 mouseClick(inputField, units.gu(1), units.gu(1))
296+ tryCompare(inputField, "activeFocus", true);
227297 typeString("1")
228298 } else {
229299 var button = findChild(lockscreen, "pinPadButton1")
@@ -239,6 +309,16 @@ Rectangle {
239309
240310 wait(0) // Trigger event loop to make sure the animation would start running
241311 compare(animation.running, data.animation)
312+ if (data.animation) {
313+ if (data.alphanumeric) {
314+ tryCompare(inputField, "placeholderText", lockscreen.wrongPlaceholderText)
315+ tryCompare(inputField, "placeholderText", lockscreen.placeholderText)
316+ } else {
317+ var label = findChild(lockscreen, "pinentryFieldPlaceHolder");
318+ tryCompare(label, "text", lockscreen.wrongPlaceholderText)
319+ tryCompare(label, "text", lockscreen.placeholderText)
320+ }
321+ }
242322
243323 // wait for animation to finish to not disturb other tests
244324 tryCompare(animation, "running", false)
@@ -246,33 +326,130 @@ Rectangle {
246326
247327 function test_backspace_data() {
248328 return [
249− {tag: "fixed length", pinLength: 4},
250− {tag: "variable length", pinLength: -1}
329+ {tag: "fixed length", minPinLength: 4, maxPinLength: 4},
330+ {tag: "variable undefined length", minPinLength: -1, maxPinLength: -1},
331+ {tag: "variable restricted length", minPinLength: 4, maxPinLength: 8}
251332 ];
252333 }
253334
254335 function test_backspace(data) {
255336 pinPadCheckBox.checked = false
256− pinLengthTextField.text = data.pinLength
257− waitForRendering(lockscreen);
337+ minPinLengthTextField.text = data.minPinLength
338+ maxPinLengthTextField.text = data.maxPinLength
339+ waitForLockscreenReady();
258340
259341 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
260342 var backspaceIcon = findChild(lockscreen, "backspaceIcon");
261343 var pinEntryField = findChild(lockscreen, "pinentryField");
262344
263− compare(pinPadButtonErase.iconName, data.pinLength == -1 ? "" : "erase");
264− compare(backspaceIcon.visible, data.pinLength == -1);
345+ var autoConfirmEnabled = data.minPinLength === data.maxPinLength && data.minPinLength !== -1;
346+ compare(pinPadButtonErase.iconName, autoConfirmEnabled ? "erase" : "");
347+ compare(backspaceIcon.visible, !autoConfirmEnabled);
265348
266349 var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
267350 mouseClick(pinPadButton5, units.gu(1), units.gu(1));
268351 compare(pinEntryField.text, "5");
269352
270− if (data.pinLength == -1) {
353+ if (data.minPinLength !== data.maxPinLength) {
271354 mouseClick(backspaceIcon, units.gu(1), units.gu(1));
272355 } else {
273356 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
274357 }
275358 compare(pinEntryField.text, "");
276359 }
360+
361+ function test_minMaxLength_data() {
362+ return [
363+ {tag: "undefined", minPinLength: -1, maxPinLength: -1},
364+ {tag: "fixed", minPinLength: 4, maxPinLength: 4},
365+ {tag: "variable, limited", minPinLength: 4, maxPinLength: 8},
366+ ];
367+ }
368+
369+ function test_minMaxLength(data) {
370+ pinPadCheckBox.checked = false
371+ minPinLengthTextField.text = data.minPinLength
372+ maxPinLengthTextField.text = data.maxPinLength
373+ waitForLockscreenReady();
374+
375+ var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
376+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
377+ var inputField = findChild(lockscreen, "pinentryField")
378+
379+ for (var i = 0; i < 10; i++) {
380+ mouseClick(pinPadButton5, units.gu(1), units.gu(1));
381+
382+ if (data.minPinLength == data.maxPinLength && data.minPinLength != -1) {
383+ // auto confirm mode...
384+ compare(inputField.text.length, (i+1) % data.minPinLength);
385+ } else {
386+ // manual confirm mode
387+ tryCompare(pinPadButtonErase, "enabled", (i+1) >= data.minPinLength)
388+ if (data.maxPinLength == -1) {
389+ compare(inputField.text.length, i+1);
390+ } else {
391+ compare(inputField.text.length, Math.min(data.maxPinLength, i+1));
392+ }
393+
394+ }
395+ }
396+ }
397+
398+ function test_retryDisplay_data() {
399+ return [
400+ {tag: "empty", retryText: "", shown: false},
401+ {tag: "3 retries left", retryText: "3 retries left", shown: true},
402+ ]
403+ }
404+
405+ function test_retryDisplay(data) {
406+ pinPadCheckBox.checked = false
407+ waitForLockscreenReady();
408+
409+ retryCountTextField.text = data.retryText;
410+ var label = findChild(lockscreen, "retryCountLabel")
411+ compare(label.visible, data.shown);
412+ }
413+
414+ function test_infoPopup() {
415+ verify(findChild(root, "infoPopup") === null);
416+ lockscreen.showInfoPopup("foo", "bar");
417+ tryCompareFunction(function() { return findChild(root, "infoPopup") !== null}, true);
418+
419+ var infoPopup = findChild(root, "infoPopup");
420+ compare(infoPopup.title, "foo");
421+ compare(infoPopup.text, "bar");
422+
423+ signalSpy.signalName = "infoPopupConfirmed"
424+ signalSpy.clear();
425+
426+ var okButton = findChild(root, "infoPopupOkButton");
427+ mouseClick(okButton, okButton.width / 2, okButton.height / 2);
428+
429+ tryCompareFunction(function() { return findChild(root, "infoPopup") === null}, true);
430+
431+ tryCompare(signalSpy, "count", 1);
432+ }
433+
434+ function test_infoTextDisplay_data() {
435+ return [
436+ {tag: "empty string", text: "", shown: false},
437+ {tag: "hello world", text: "hello world", shown: true},
438+ ]
439+ }
440+
441+ function test_infoTextDisplay(data) {
442+ pinPadCheckBox.checked = false
443+ waitForLockscreenReady();
444+
445+ infoTextTextField.text = data.text;
446+ var label = findChild(lockscreen, "infoTextLabel")
447+ compare(label.visible, data.shown);
448+ }
449+ }
450+
451+ SignalSpy {
452+ id: signalSpy
453+ target: lockscreen
277454 }
278455}