Passed
Push — zero-is-false ( 14c39e...85b8a2 )
by Sam
06:15
created

testMustBeLoggedInToChangePassword()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 0
dl 0
loc 19
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\Tests;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Dev\SapphireTest;
7
use SilverStripe\Forms\ConfirmedPasswordField;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\Form;
10
use SilverStripe\Forms\ReadonlyField;
11
use SilverStripe\Forms\RequiredFields;
12
use SilverStripe\Security\Member;
13
14
class ConfirmedPasswordFieldTest extends SapphireTest
15
{
16
    public function testSetValue()
17
    {
18
        $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA');
19
        $this->assertEquals('valueA', $field->Value());
20
        $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_Password]')->Value());
21
        $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value());
22
        $field->setValue('valueB');
23
        $this->assertEquals('valueB', $field->Value());
24
        $this->assertEquals('valueB', $field->children->fieldByName($field->getName() . '[_Password]')->Value());
25
        $this->assertEquals('valueB', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value());
26
    }
27
28
    /**
29
     * @useDatabase true
30
     */
31
    public function testHashHidden()
32
    {
33
        $field = new ConfirmedPasswordField('Password', 'Password', 'valueA');
34
        $field->setCanBeEmpty(true);
35
36
        $this->assertEquals('valueA', $field->Value());
37
        $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_Password]')->Value());
38
        $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value());
39
40
        $member = new Member();
41
        $member->Password = "valueB";
42
        $member->write();
43
44
        /** @skipUpgrade */
45
        $form = new Form(Controller::curr(), 'Form', new FieldList($field), new FieldList());
46
        $form->loadDataFrom($member);
47
48
        $this->assertEquals('', $field->Value());
49
        $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_Password]')->Value());
50
        $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value());
51
    }
52
53
    public function testSetShowOnClick()
54
    {
55
        //hide by default and display show/hide toggle button
56
        $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA', null, true);
57
        $fieldHTML = $field->Field();
58
        $this->assertContains(
59
            "showOnClickContainer",
60
            $fieldHTML,
61
            "Test class for hiding/showing the form contents is set"
62
        );
63
        $this->assertContains(
64
            "showOnClick",
65
            $fieldHTML,
66
            "Test class for hiding/showing the form contents is set"
67
        );
68
69
        //show all by default
70
        $field = new ConfirmedPasswordField('Test', 'Testing', 'valueA', null, false);
71
        $fieldHTML = $field->Field();
72
        $this->assertNotContains(
73
            "showOnClickContainer",
74
            $fieldHTML,
75
            "Test class for hiding/showing the form contents is set"
76
        );
77
        $this->assertNotContains(
78
            "showOnClick",
79
            $fieldHTML,
80
            "Test class for hiding/showing the form contents is set"
81
        );
82
    }
83
84
    public function testValidation()
85
    {
86
        $field = new ConfirmedPasswordField(
87
            'Test',
88
            'Testing',
89
            [
90
                '_Password' => 'abc123',
91
                '_ConfirmPassword' => 'abc123',
92
            ]
93
        );
94
        $validator = new RequiredFields();
95
        $this->assertTrue(
96
            $field->validate($validator),
97
            'Validates when both passwords are the same'
98
        );
99
        $field->setName('TestNew'); //try changing name of field
100
        $this->assertTrue(
101
            $field->validate($validator),
102
            'Validates when field name is changed'
103
        );
104
        //non-matching password should make the field invalid
105
        $field->setValue([
106
            '_Password' => 'abc123',
107
            '_ConfirmPassword' => '123abc',
108
        ]);
109
        $this->assertFalse(
110
            $field->validate($validator),
111
            'Does not validate when passwords differ'
112
        );
113
114
        // Empty passwords should make the field invalid
115
        $field->setCanBeEmpty(false);
116
        $field->setValue([
117
            '_Password' => '',
118
            '_ConfirmPassword' => '',
119
        ]);
120
        $this->assertFalse(
121
            $field->validate($validator),
122
            'Empty passwords should not be allowed when canBeEmpty is false'
123
        );
124
    }
125
126
    public function testFormValidation()
127
    {
128
        /** @skipUpgrade */
129
        $form = new Form(
130
            Controller::curr(),
131
            'Form',
132
            new FieldList($field = new ConfirmedPasswordField('Password')),
133
            new FieldList()
134
        );
135
136
        $form->loadDataFrom([
137
            'Password' => [
138
                '_Password' => '123',
139
                '_ConfirmPassword' => '999',
140
            ],
141
        ]);
142
143
        $this->assertEquals('123', $field->children->first()->Value());
144
        $this->assertEquals('999', $field->children->last()->Value());
145
        $this->assertNotEquals($field->children->first()->Value(), $field->children->last()->Value());
146
    }
147
148
    /**
149
     * @param int|null $minLength
150
     * @param int|null $maxLength
151
     * @param bool $expectValid
152
     * @param string $expectedMessage
153
     * @dataProvider lengthValidationProvider
154
     */
155
    public function testLengthValidation($minLength, $maxLength, $expectValid, $expectedMessage = '')
156
    {
157
        $field = new ConfirmedPasswordField('Test', 'Testing', [
158
            '_Password' => 'abc123',
159
            '_ConfirmPassword' => 'abc123',
160
        ]);
161
        $field->setMinLength($minLength)->setMaxLength($maxLength);
162
163
        $validator = new RequiredFields();
164
        $result = $field->validate($validator);
165
166
        $this->assertSame($expectValid, $result, 'Validate method should return its result');
167
        $this->assertSame($expectValid, $validator->getResult()->isValid());
168
        if ($expectedMessage) {
169
            $this->assertContains($expectedMessage, $validator->getResult()->serialize());
170
        }
171
    }
172
173
    /**
174
     * @return array[]
175
     */
176
    public function lengthValidationProvider()
177
    {
178
        return [
179
            'valid: within min and max' => [3, 8, true],
180
            'invalid: lower than min with max' => [8, 12, false, 'Passwords must be 8 to 12 characters long'],
181
            'valid: greater than min' => [3, null, true],
182
            'invalid: lower than min' => [8, null, false, 'Passwords must be at least 8 characters long'],
183
            'valid: less than max' => [null, 8, true],
184
            'invalid: greater than max' => [null, 4, false, 'Passwords must be at most 4 characters long'],
185
186
        ];
187
    }
188
189
    public function testStrengthValidation()
190
    {
191
        $field = new ConfirmedPasswordField('Test', 'Testing', [
192
            '_Password' => 'abc',
193
            '_ConfirmPassword' => 'abc',
194
        ]);
195
        $field->setRequireStrongPassword(true);
196
197
        $validator = new RequiredFields();
198
        $result = $field->validate($validator);
199
200
        $this->assertFalse($result, 'Validate method should return its result');
201
        $this->assertFalse($validator->getResult()->isValid());
202
        $this->assertContains(
203
            'Passwords must have at least one digit and one alphanumeric character',
204
            $validator->getResult()->serialize()
205
        );
206
    }
207
208
    public function testCurrentPasswordValidation()
209
    {
210
        $field = new ConfirmedPasswordField('Test', 'Testing', [
211
            '_Password' => 'abc',
212
            '_ConfirmPassword' => 'abc',
213
        ]);
214
        $field->setRequireExistingPassword(true);
215
216
        $validator = new RequiredFields();
217
        $result = $field->validate($validator);
218
219
        $this->assertFalse($result, 'Validate method should return its result');
220
        $this->assertFalse($validator->getResult()->isValid());
221
        $this->assertContains(
222
            'You must enter your current password',
223
            $validator->getResult()->serialize()
224
        );
225
    }
226
227
    public function testMustBeLoggedInToChangePassword()
228
    {
229
        $field = new ConfirmedPasswordField('Test', 'Testing');
230
        $field->setRequireExistingPassword(true);
231
        $field->setValue([
232
            '_CurrentPassword' => 'foo',
233
            '_Password' => 'abc',
234
            '_ConfirmPassword' => 'abc',
235
        ]);
236
237
        $validator = new RequiredFields();
238
        $this->logOut();
239
        $result = $field->validate($validator);
240
241
        $this->assertFalse($result, 'Validate method should return its result');
242
        $this->assertFalse($validator->getResult()->isValid());
243
        $this->assertContains(
244
            'You must be logged in to change your password',
245
            $validator->getResult()->serialize()
246
        );
247
    }
248
249
    /**
250
     * @useDatabase true
251
     */
252
    public function testValidateCorrectPassword()
253
    {
254
        $this->logInWithPermission('ADMIN');
255
256
        $field = new ConfirmedPasswordField('Test', 'Testing');
257
        $field->setRequireExistingPassword(true);
258
        $field->setValue([
259
            '_CurrentPassword' => 'foo-not-going-to-be-the-correct-password',
260
            '_Password' => 'abc',
261
            '_ConfirmPassword' => 'abc',
262
        ]);
263
264
        $validator = new RequiredFields();
265
        $result = $field->validate($validator);
266
267
        $this->assertFalse($result, 'Validate method should return its result');
268
        $this->assertFalse($validator->getResult()->isValid());
269
        $this->assertContains(
270
            'The current password you have entered is not correct',
271
            $validator->getResult()->serialize()
272
        );
273
    }
274
275
    public function testTitle()
276
    {
277
        $this->assertNull(ConfirmedPasswordField::create('Test')->Title(), 'Should not have it\'s own title');
278
    }
279
280
    public function testSetTitlePropagatesToPasswordField()
281
    {
282
        /** @var ConfirmedPasswordField $field */
283
        $field = ConfirmedPasswordField::create('Test')
284
            ->setTitle('My password');
285
286
        $this->assertSame('My password', $field->getPasswordField()->Title());
287
    }
288
289
    public function testSetRightTitlePropagatesToChildren()
290
    {
291
        $field = new ConfirmedPasswordField('Test');
292
293
        $this->assertCount(2, $field->getChildren());
294
        foreach ($field->getChildren() as $child) {
295
            $this->assertEmpty($child->RightTitle());
296
        }
297
298
        $field->setRightTitle('Please confirm');
299
        foreach ($field->getChildren() as $child) {
300
            $this->assertSame('Please confirm', $child->RightTitle());
301
        }
302
    }
303
304
    public function testSetChildrenTitles()
305
    {
306
        $field = new ConfirmedPasswordField('Test');
307
        $field->setRequireExistingPassword(true);
308
        $field->setChildrenTitles([
309
            'Current Password',
310
            'Password',
311
            'Confirm Password',
312
        ]);
313
314
        $this->assertSame('Current Password', $field->getChildren()->shift()->Title());
315
        $this->assertSame('Password', $field->getChildren()->shift()->Title());
316
        $this->assertSame('Confirm Password', $field->getChildren()->shift()->Title());
317
    }
318
319
    public function testPerformReadonlyTransformation()
320
    {
321
        $field = new ConfirmedPasswordField('Test', 'Change it');
322
        $result = $field->performReadonlyTransformation();
323
324
        $this->assertInstanceOf(ReadonlyField::class, $result);
325
        $this->assertSame('Change it', $result->Title());
326
        $this->assertContains('***', $result->Value());
327
    }
328
329
    public function testPerformDisabledTransformation()
330
    {
331
        $field = new ConfirmedPasswordField('Test', 'Change it');
332
        $result = $field->performDisabledTransformation();
333
334
        $this->assertInstanceOf(ReadonlyField::class, $result);
335
    }
336
337
    public function testSetRequireExistingPasswordOnlyRunsOnce()
338
    {
339
        $field = new ConfirmedPasswordField('Test', 'Change it');
340
341
        $this->assertCount(2, $field->getChildren());
342
343
        $field->setRequireExistingPassword(true);
344
        $this->assertCount(3, $field->getChildren(), 'Current password field was not pushed');
345
346
        $field->setRequireExistingPassword(true);
347
        $this->assertCount(3, $field->getChildren(), 'Current password field should not be pushed again');
348
349
        $field->setRequireExistingPassword(false);
350
        $this->assertCount(2, $field->getChildren(), 'Current password field should not be removed');
351
    }
352
}
353