Projet

Général

Profil

Paste
Télécharger (96,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / user / user.test @ f7a2490e

1
<?php
2

    
3
/**
4
 * @file
5
 * Tests for user.module.
6
 */
7

    
8
class UserRegistrationTestCase extends DrupalWebTestCase {
9
  public static function getInfo() {
10
    return array(
11
      'name' => 'User registration',
12
      'description' => 'Test registration of user under different configurations.',
13
      'group' => 'User'
14
    );
15
  }
16

    
17
  function setUp() {
18
    parent::setUp('field_test');
19
  }
20

    
21
  function testRegistrationWithEmailVerification() {
22
    // Require e-mail verification.
23
    variable_set('user_email_verification', TRUE);
24

    
25
    // Set registration to administrator only.
26
    variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY);
27
    $this->drupalGet('user/register');
28
    $this->assertResponse(403, 'Registration page is inaccessible when only administrators can create accounts.');
29

    
30
    // Allow registration by site visitors without administrator approval.
31
    variable_set('user_register', USER_REGISTER_VISITORS);
32
    $edit = array();
33
    $edit['name'] = $name = $this->randomName();
34
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
35
    $this->drupalPost('user/register', $edit, t('Create new account'));
36
    $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), 'User registered successfully.');
37
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
38
    $new_user = reset($accounts);
39
    $this->assertTrue($new_user->status, 'New account is active after registration.');
40

    
41
    // Allow registration by site visitors, but require administrator approval.
42
    variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
43
    $edit = array();
44
    $edit['name'] = $name = $this->randomName();
45
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
46
    $this->drupalPost('user/register', $edit, t('Create new account'));
47
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
48
    $new_user = reset($accounts);
49
    $this->assertFalse($new_user->status, 'New account is blocked until approved by an administrator.');
50
  }
51

    
52
  function testRegistrationWithoutEmailVerification() {
53
    // Don't require e-mail verification.
54
    variable_set('user_email_verification', FALSE);
55

    
56
    // Allow registration by site visitors without administrator approval.
57
    variable_set('user_register', USER_REGISTER_VISITORS);
58
    $edit = array();
59
    $edit['name'] = $name = $this->randomName();
60
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
61

    
62
    // Try entering a mismatching password.
63
    $edit['pass[pass1]'] = '99999.0';
64
    $edit['pass[pass2]'] = '99999';
65
    $this->drupalPost('user/register', $edit, t('Create new account'));
66
    $this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.');
67

    
68
    // Enter a correct password.
69
    $edit['pass[pass1]'] = $new_pass = $this->randomName();
70
    $edit['pass[pass2]'] = $new_pass;
71
    $this->drupalPost('user/register', $edit, t('Create new account'));
72
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
73
    $new_user = reset($accounts);
74
    $this->assertText(t('Registration successful. You are now logged in.'), 'Users are logged in after registering.');
75
    $this->drupalLogout();
76

    
77
    // Allow registration by site visitors, but require administrator approval.
78
    variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
79
    $edit = array();
80
    $edit['name'] = $name = $this->randomName();
81
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
82
    $edit['pass[pass1]'] = $pass = $this->randomName();
83
    $edit['pass[pass2]'] = $pass;
84
    $this->drupalPost('user/register', $edit, t('Create new account'));
85
    $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval');
86

    
87
    // Try to login before administrator approval.
88
    $auth = array(
89
      'name' => $name,
90
      'pass' => $pass,
91
    );
92
    $this->drupalPost('user/login', $auth, t('Log in'));
93
    $this->assertText(t('The username @name has not been activated or is blocked.', array('@name' => $name)), 'User cannot login yet.');
94

    
95
    // Activate the new account.
96
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
97
    $new_user = reset($accounts);
98
    $admin_user = $this->drupalCreateUser(array('administer users'));
99
    $this->drupalLogin($admin_user);
100
    $edit = array(
101
      'status' => 1,
102
    );
103
    $this->drupalPost('user/' . $new_user->uid . '/edit', $edit, t('Save'));
104
    $this->drupalLogout();
105

    
106
    // Login after administrator approval.
107
    $this->drupalPost('user/login', $auth, t('Log in'));
108
    $this->assertText(t('Member for'), 'User can log in after administrator approval.');
109
  }
110

    
111
  function testRegistrationEmailDuplicates() {
112
    // Don't require e-mail verification.
113
    variable_set('user_email_verification', FALSE);
114

    
115
    // Allow registration by site visitors without administrator approval.
116
    variable_set('user_register', USER_REGISTER_VISITORS);
117

    
118
    // Set up a user to check for duplicates.
119
    $duplicate_user = $this->drupalCreateUser();
120

    
121
    $edit = array();
122
    $edit['name'] = $this->randomName();
123
    $edit['mail'] = $duplicate_user->mail;
124

    
125
    // Attempt to create a new account using an existing e-mail address.
126
    $this->drupalPost('user/register', $edit, t('Create new account'));
127
    $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying an exact duplicate email address displays an error message');
128

    
129
    // Attempt to bypass duplicate email registration validation by adding spaces.
130
    $edit['mail'] = '   ' . $duplicate_user->mail . '   ';
131

    
132
    $this->drupalPost('user/register', $edit, t('Create new account'));
133
    $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying a duplicate email address with added whitespace displays an error message');
134
  }
135

    
136
  function testRegistrationDefaultValues() {
137
    // Allow registration by site visitors without administrator approval.
138
    variable_set('user_register', USER_REGISTER_VISITORS);
139

    
140
    // Don't require e-mail verification.
141
    variable_set('user_email_verification', FALSE);
142

    
143
    // Set the default timezone to Brussels.
144
    variable_set('configurable_timezones', 1);
145
    variable_set('date_default_timezone', 'Europe/Brussels');
146

    
147
    // Check that the account information fieldset's options are not displayed
148
    // is a fieldset if there is not more than one fieldset in the form.
149
    $this->drupalGet('user/register');
150
    $this->assertNoRaw('<fieldset id="edit-account"><legend>Account information</legend>', 'Account settings fieldset was hidden.');
151

    
152
    $edit = array();
153
    $edit['name'] = $name = $this->randomName();
154
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
155
    $edit['pass[pass1]'] = $new_pass = $this->randomName();
156
    $edit['pass[pass2]'] = $new_pass;
157
    $this->drupalPost(NULL, $edit, t('Create new account'));
158

    
159
    // Check user fields.
160
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
161
    $new_user = reset($accounts);
162
    $this->assertEqual($new_user->name, $name, 'Username matches.');
163
    $this->assertEqual($new_user->mail, $mail, 'E-mail address matches.');
164
    $this->assertEqual($new_user->theme, '', 'Correct theme field.');
165
    $this->assertEqual($new_user->signature, '', 'Correct signature field.');
166
    $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), 'Correct creation time.');
167
    $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
168
    $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), 'Correct time zone field.');
169
    $this->assertEqual($new_user->language, '', 'Correct language field.');
170
    $this->assertEqual($new_user->picture, '', 'Correct picture field.');
171
    $this->assertEqual($new_user->init, $mail, 'Correct init field.');
172
  }
173

    
174
  /**
175
   * Tests Field API fields on user registration forms.
176
   */
177
  function testRegistrationWithUserFields() {
178
    // Create a field, and an instance on 'user' entity type.
179
    $field = array(
180
      'type' => 'test_field',
181
      'field_name' => 'test_user_field',
182
      'cardinality' => 1,
183
    );
184
    field_create_field($field);
185
    $instance = array(
186
      'field_name' => 'test_user_field',
187
      'entity_type' => 'user',
188
      'label' => 'Some user field',
189
      'bundle' => 'user',
190
      'required' => TRUE,
191
      'settings' => array('user_register_form' => FALSE),
192
    );
193
    field_create_instance($instance);
194

    
195
    // Check that the field does not appear on the registration form.
196
    $this->drupalGet('user/register');
197
    $this->assertNoText($instance['label'], 'The field does not appear on user registration form');
198

    
199
    // Have the field appear on the registration form.
200
    $instance['settings']['user_register_form'] = TRUE;
201
    field_update_instance($instance);
202
    $this->drupalGet('user/register');
203
    $this->assertText($instance['label'], 'The field appears on user registration form');
204

    
205
    // Check that validation errors are correctly reported.
206
    $edit = array();
207
    $edit['name'] = $name = $this->randomName();
208
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
209
    // Missing input in required field.
210
    $edit['test_user_field[und][0][value]'] = '';
211
    $this->drupalPost(NULL, $edit, t('Create new account'));
212
    $this->assertRaw(t('@name field is required.', array('@name' => $instance['label'])), 'Field validation error was correctly reported.');
213
    // Invalid input.
214
    $edit['test_user_field[und][0][value]'] = '-1';
215
    $this->drupalPost(NULL, $edit, t('Create new account'));
216
    $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $instance['label'])), 'Field validation error was correctly reported.');
217

    
218
    // Submit with valid data.
219
    $value = rand(1, 255);
220
    $edit['test_user_field[und][0][value]'] = $value;
221
    $this->drupalPost(NULL, $edit, t('Create new account'));
222
    // Check user fields.
223
    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
224
    $new_user = reset($accounts);
225
    $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, 'The field value was correctly saved.');
226

    
227
    // Check that the 'add more' button works.
228
    $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
229
    field_update_field($field);
230
    foreach (array('js', 'nojs') as $js) {
231
      $this->drupalGet('user/register');
232
      // Add two inputs.
233
      $value = rand(1, 255);
234
      $edit = array();
235
      $edit['test_user_field[und][0][value]'] = $value;
236
      if ($js == 'js') {
237
        $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
238
        $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
239
      }
240
      else {
241
        $this->drupalPost(NULL, $edit, t('Add another item'));
242
        $this->drupalPost(NULL, $edit, t('Add another item'));
243
      }
244
      // Submit with three values.
245
      $edit['test_user_field[und][1][value]'] = $value + 1;
246
      $edit['test_user_field[und][2][value]'] = $value + 2;
247
      $edit['name'] = $name = $this->randomName();
248
      $edit['mail'] = $mail = $edit['name'] . '@example.com';
249
      $this->drupalPost(NULL, $edit, t('Create new account'));
250
      // Check user fields.
251
      $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
252
      $new_user = reset($accounts);
253
      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
254
      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
255
      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
256
    }
257
  }
258
}
259

    
260
class UserValidationTestCase extends DrupalWebTestCase {
261
  public static function getInfo() {
262
    return array(
263
      'name' => 'Username/e-mail validation',
264
      'description' => 'Verify that username/email validity checks behave as designed.',
265
      'group' => 'User'
266
    );
267
  }
268

    
269
  // Username validation.
270
  function testUsernames() {
271
    $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'),
272
      'foo'                    => array('Valid username', 'assertNull'),
273
      'FOO'                    => array('Valid username', 'assertNull'),
274
      'Foo O\'Bar'             => array('Valid username', 'assertNull'),
275
      'foo@bar'                => array('Valid username', 'assertNull'),
276
      'foo@example.com'        => array('Valid username', 'assertNull'),
277
      'foo@-example.com'       => array('Valid username', 'assertNull'), // invalid domains are allowed in usernames
278
      'þòøÇߪř€'               => array('Valid username', 'assertNull'),
279
      'ᚠᛇᚻ᛫ᛒᛦᚦ'                => array('Valid UTF8 username', 'assertNull'), // runes
280
      ' foo'                   => array('Invalid username that starts with a space', 'assertNotNull'),
281
      'foo '                   => array('Invalid username that ends with a space', 'assertNotNull'),
282
      'foo  bar'               => array('Invalid username that contains 2 spaces \'&nbsp;&nbsp;\'', 'assertNotNull'),
283
      ''                       => array('Invalid empty username', 'assertNotNull'),
284
      'foo/'                   => array('Invalid username containing invalid chars', 'assertNotNull'),
285
      'foo' . chr(0) . 'bar'   => array('Invalid username containing chr(0)', 'assertNotNull'), // NULL
286
      'foo' . chr(13) . 'bar'  => array('Invalid username containing chr(13)', 'assertNotNull'), // CR
287
      str_repeat('x', USERNAME_MAX_LENGTH + 1) => array('Invalid excessively long username', 'assertNotNull'),
288
    );
289
    foreach ($test_cases as $name => $test_case) {
290
      list($description, $test) = $test_case;
291
      $result = user_validate_name($name);
292
      $this->$test($result, $description . ' (' . $name . ')');
293
    }
294
  }
295

    
296
  // Mail validation. More extensive tests can be found at common.test
297
  function testMailAddresses() {
298
    $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'),
299
      ''                => array('Empty mail address', 'assertNotNull'),
300
      'foo'             => array('Invalid mail address', 'assertNotNull'),
301
      'foo@example.com' => array('Valid mail address', 'assertNull'),
302
    );
303
    foreach ($test_cases as $name => $test_case) {
304
      list($description, $test) = $test_case;
305
      $result = user_validate_mail($name);
306
      $this->$test($result, $description . ' (' . $name . ')');
307
    }
308
  }
309
}
310

    
311
/**
312
 * Functional tests for user logins, including rate limiting of login attempts.
313
 */
314
class UserLoginTestCase extends DrupalWebTestCase {
315
  public static function getInfo() {
316
    return array(
317
      'name' => 'User login',
318
      'description' => 'Ensure that login works as expected.',
319
      'group' => 'User',
320
    );
321
  }
322

    
323
  /**
324
   * Test the global login flood control.
325
   */
326
  function testGlobalLoginFloodControl() {
327
    // Set the global login limit.
328
    variable_set('user_failed_login_ip_limit', 10);
329
    // Set a high per-user limit out so that it is not relevant in the test.
330
    variable_set('user_failed_login_user_limit', 4000);
331

    
332
    $user1 = $this->drupalCreateUser(array());
333
    $incorrect_user1 = clone $user1;
334
    $incorrect_user1->pass_raw .= 'incorrect';
335

    
336
    // Try 2 failed logins.
337
    for ($i = 0; $i < 2; $i++) {
338
      $this->assertFailedLogin($incorrect_user1);
339
    }
340

    
341
    // A successful login will not reset the IP-based flood control count.
342
    $this->drupalLogin($user1);
343
    $this->drupalLogout();
344

    
345
    // Try 8 more failed logins, they should not trigger the flood control
346
    // mechanism.
347
    for ($i = 0; $i < 8; $i++) {
348
      $this->assertFailedLogin($incorrect_user1);
349
    }
350

    
351
    // The next login trial should result in an IP-based flood error message.
352
    $this->assertFailedLogin($incorrect_user1, 'ip');
353

    
354
    // A login with the correct password should also result in a flood error
355
    // message.
356
    $this->assertFailedLogin($user1, 'ip');
357
  }
358

    
359
  /**
360
   * Test the per-user login flood control.
361
   */
362
  function testPerUserLoginFloodControl() {
363
    // Set a high global limit out so that it is not relevant in the test.
364
    variable_set('user_failed_login_ip_limit', 4000);
365
    // Set the per-user login limit.
366
    variable_set('user_failed_login_user_limit', 3);
367

    
368
    $user1 = $this->drupalCreateUser(array());
369
    $incorrect_user1 = clone $user1;
370
    $incorrect_user1->pass_raw .= 'incorrect';
371

    
372
    $user2 = $this->drupalCreateUser(array());
373

    
374
    // Try 2 failed logins.
375
    for ($i = 0; $i < 2; $i++) {
376
      $this->assertFailedLogin($incorrect_user1);
377
    }
378

    
379
    // A successful login will reset the per-user flood control count.
380
    $this->drupalLogin($user1);
381
    $this->drupalLogout();
382

    
383
    // Try 3 failed logins for user 1, they will not trigger flood control.
384
    for ($i = 0; $i < 3; $i++) {
385
      $this->assertFailedLogin($incorrect_user1);
386
    }
387

    
388
    // Try one successful attempt for user 2, it should not trigger any
389
    // flood control.
390
    $this->drupalLogin($user2);
391
    $this->drupalLogout();
392

    
393
    // Try one more attempt for user 1, it should be rejected, even if the
394
    // correct password has been used.
395
    $this->assertFailedLogin($user1, 'user');
396
  }
397

    
398
  /**
399
   * Test that user password is re-hashed upon login after changing $count_log2.
400
   */
401
  function testPasswordRehashOnLogin() {
402
    // Load password hashing API.
403
    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
404
    // Set initial $count_log2 to the default, DRUPAL_HASH_COUNT.
405
    variable_set('password_count_log2', DRUPAL_HASH_COUNT);
406
    // Create a new user and authenticate.
407
    $account = $this->drupalCreateUser(array());
408
    $password = $account->pass_raw;
409
    $this->drupalLogin($account);
410
    $this->drupalLogout();
411
    // Load the stored user. The password hash should reflect $count_log2.
412
    $account = user_load($account->uid);
413
    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT);
414
    // Change $count_log2 and log in again.
415
    variable_set('password_count_log2', DRUPAL_HASH_COUNT + 1);
416
    $account->pass_raw = $password;
417
    $this->drupalLogin($account);
418
    // Load the stored user, which should have a different password hash now.
419
    $account = user_load($account->uid, TRUE);
420
    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT + 1);
421
  }
422

    
423
  /**
424
   * Make an unsuccessful login attempt.
425
   *
426
   * @param $account
427
   *   A user object with name and pass_raw attributes for the login attempt.
428
   * @param $flood_trigger
429
   *   Whether or not to expect that the flood control mechanism will be
430
   *   triggered.
431
   */
432
  function assertFailedLogin($account, $flood_trigger = NULL) {
433
    $edit = array(
434
      'name' => $account->name,
435
      'pass' => $account->pass_raw,
436
    );
437
    $this->drupalPost('user', $edit, t('Log in'));
438
    $this->assertNoFieldByXPath("//input[@name='pass' and @value!='']", NULL, 'Password value attribute is blank.');
439
    if (isset($flood_trigger)) {
440
      if ($flood_trigger == 'user') {
441
        $this->assertRaw(format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
442
      }
443
      else {
444
        // No uid, so the limit is IP-based.
445
        $this->assertRaw(t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
446
      }
447
    }
448
    else {
449
      $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'));
450
    }
451
  }
452
}
453

    
454
/**
455
 * Tests resetting a user password.
456
 */
457
class UserPasswordResetTestCase extends DrupalWebTestCase {
458
  protected $profile = 'standard';
459

    
460
  public static function getInfo() {
461
    return array(
462
      'name' => 'Reset password',
463
      'description' => 'Ensure that password reset methods work as expected.',
464
      'group' => 'User',
465
    );
466
  }
467

    
468
  /**
469
   * Tests password reset functionality.
470
   */
471
  function testUserPasswordReset() {
472
    // Create a user.
473
    $account = $this->drupalCreateUser();
474
    $this->drupalLogin($account);
475
    $this->drupalLogout();
476
    // Attempt to reset password.
477
    $edit = array('name' => $account->name);
478
    $this->drupalPost('user/password', $edit, t('E-mail new password'));
479
    // Confirm the password reset.
480
    $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.');
481
  }
482

    
483
  /**
484
   * Attempts login using an expired password reset link.
485
   */
486
  function testUserPasswordResetExpired() {
487
    // Set password reset timeout variable to 43200 seconds = 12 hours.
488
    $timeout = 43200;
489
    variable_set('user_password_reset_timeout', $timeout);
490

    
491
    // Create a user.
492
    $account = $this->drupalCreateUser();
493
    $this->drupalLogin($account);
494
    // Load real user object.
495
    $account = user_load($account->uid, TRUE);
496
    $this->drupalLogout();
497

    
498
    // To attempt an expired password reset, create a password reset link as if
499
    // its request time was 60 seconds older than the allowed limit of timeout.
500
    $bogus_timestamp = REQUEST_TIME - variable_get('user_password_reset_timeout', 86400) - 60;
501
    $this->drupalGet("user/reset/$account->uid/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
502
    $this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.');
503
  }
504

    
505
  /**
506
   * Prefill the text box on incorrect login via link to password reset page.
507
   */
508
  function testUserPasswordTextboxFilled() {
509
    $this->drupalGet('user/login');
510
    $edit = array(
511
      'name' => $this->randomName(),
512
      'pass' => $this->randomName(),
513
    );
514
    $this->drupalPost('user', $edit, t('Log in'));
515
    $this->assertRaw(t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>',
516
      array('@password' => url('user/password', array('query' => array('name' => $edit['name']))))));
517
    unset($edit['pass']);
518
    $this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
519
    $this->assertFieldByName('name', $edit['name'], 'User name found.');
520
  }
521

    
522
}
523

    
524
/**
525
 * Test cancelling a user.
526
 */
527
class UserCancelTestCase extends DrupalWebTestCase {
528
  public static function getInfo() {
529
    return array(
530
      'name' => 'Cancel account',
531
      'description' => 'Ensure that account cancellation methods work as expected.',
532
      'group' => 'User',
533
    );
534
  }
535

    
536
  function setUp() {
537
    parent::setUp('comment');
538
  }
539

    
540
  /**
541
   * Attempt to cancel account without permission.
542
   */
543
  function testUserCancelWithoutPermission() {
544
    variable_set('user_cancel_method', 'user_cancel_reassign');
545

    
546
    // Create a user.
547
    $account = $this->drupalCreateUser(array());
548
    $this->drupalLogin($account);
549
    // Load real user object.
550
    $account = user_load($account->uid, TRUE);
551

    
552
    // Create a node.
553
    $node = $this->drupalCreateNode(array('uid' => $account->uid));
554

    
555
    // Attempt to cancel account.
556
    $this->drupalGet('user/' . $account->uid . '/edit');
557
    $this->assertNoRaw(t('Cancel account'), 'No cancel account button displayed.');
558

    
559
    // Attempt bogus account cancellation request confirmation.
560
    $timestamp = $account->login;
561
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
562
    $this->assertResponse(403, 'Bogus cancelling request rejected.');
563
    $account = user_load($account->uid);
564
    $this->assertTrue($account->status == 1, 'User account was not canceled.');
565

    
566
    // Confirm user's content has not been altered.
567
    $test_node = node_load($node->nid, NULL, TRUE);
568
    $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
569
  }
570

    
571
  /**
572
   * Tests that user account for uid 1 cannot be cancelled.
573
   *
574
   * This should never be possible, or the site owner would become unable to
575
   * administer the site.
576
   */
577
  function testUserCancelUid1() {
578
    // Update uid 1's name and password to we know it.
579
    $password = user_password();
580
    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
581
    $account = array(
582
      'name' => 'user1',
583
      'pass' => user_hash_password(trim($password)),
584
    );
585
    // We cannot use user_save() here or the password would be hashed again.
586
    db_update('users')
587
      ->fields($account)
588
      ->condition('uid', 1)
589
      ->execute();
590

    
591
    // Reload and log in uid 1.
592
    $user1 = user_load(1, TRUE);
593
    $user1->pass_raw = $password;
594

    
595
    // Try to cancel uid 1's account with a different user.
596
    $this->admin_user = $this->drupalCreateUser(array('administer users'));
597
    $this->drupalLogin($this->admin_user);
598
    $edit = array(
599
      'operation' => 'cancel',
600
      'accounts[1]' => TRUE,
601
    );
602
    $this->drupalPost('admin/people', $edit, t('Update'));
603

    
604
    // Verify that uid 1's account was not cancelled.
605
    $user1 = user_load(1, TRUE);
606
    $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
607
  }
608

    
609
  /**
610
   * Attempt invalid account cancellations.
611
   */
612
  function testUserCancelInvalid() {
613
    variable_set('user_cancel_method', 'user_cancel_reassign');
614

    
615
    // Create a user.
616
    $account = $this->drupalCreateUser(array('cancel account'));
617
    $this->drupalLogin($account);
618
    // Load real user object.
619
    $account = user_load($account->uid, TRUE);
620

    
621
    // Create a node.
622
    $node = $this->drupalCreateNode(array('uid' => $account->uid));
623

    
624
    // Attempt to cancel account.
625
    $this->drupalPost('user/' . $account->uid . '/edit', NULL, t('Cancel account'));
626

    
627
    // Confirm account cancellation.
628
    $timestamp = time();
629
    $this->drupalPost(NULL, NULL, t('Cancel account'));
630
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
631

    
632
    // Attempt bogus account cancellation request confirmation.
633
    $bogus_timestamp = $timestamp + 60;
634
    $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
635
    $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Bogus cancelling request rejected.');
636
    $account = user_load($account->uid);
637
    $this->assertTrue($account->status == 1, 'User account was not canceled.');
638

    
639
    // Attempt expired account cancellation request confirmation.
640
    $bogus_timestamp = $timestamp - 86400 - 60;
641
    $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
642
    $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Expired cancel account request rejected.');
643
    $accounts = user_load_multiple(array($account->uid), array('status' => 1));
644
    $this->assertTrue(reset($accounts), 'User account was not canceled.');
645

    
646
    // Confirm user's content has not been altered.
647
    $test_node = node_load($node->nid, NULL, TRUE);
648
    $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
649
  }
650

    
651
  /**
652
   * Disable account and keep all content.
653
   */
654
  function testUserBlock() {
655
    variable_set('user_cancel_method', 'user_cancel_block');
656

    
657
    // Create a user.
658
    $web_user = $this->drupalCreateUser(array('cancel account'));
659
    $this->drupalLogin($web_user);
660

    
661
    // Load real user object.
662
    $account = user_load($web_user->uid, TRUE);
663

    
664
    // Attempt to cancel account.
665
    $this->drupalGet('user/' . $account->uid . '/edit');
666
    $this->drupalPost(NULL, NULL, t('Cancel account'));
667
    $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
668
    $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'), 'Informs that all content will be remain as is.');
669
    $this->assertNoText(t('Select the method to cancel the account above.'), 'Does not allow user to select account cancellation method.');
670

    
671
    // Confirm account cancellation.
672
    $timestamp = time();
673

    
674
    $this->drupalPost(NULL, NULL, t('Cancel account'));
675
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
676

    
677
    // Confirm account cancellation request.
678
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
679
    $account = user_load($account->uid, TRUE);
680
    $this->assertTrue($account->status == 0, 'User has been blocked.');
681

    
682
    // Confirm that the confirmation message made it through to the end user.
683
    $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
684
  }
685

    
686
  /**
687
   * Disable account and unpublish all content.
688
   */
689
  function testUserBlockUnpublish() {
690
    variable_set('user_cancel_method', 'user_cancel_block_unpublish');
691

    
692
    // Create a user.
693
    $account = $this->drupalCreateUser(array('cancel account'));
694
    $this->drupalLogin($account);
695
    // Load real user object.
696
    $account = user_load($account->uid, TRUE);
697

    
698
    // Create a node with two revisions.
699
    $node = $this->drupalCreateNode(array('uid' => $account->uid));
700
    $settings = get_object_vars($node);
701
    $settings['revision'] = 1;
702
    $node = $this->drupalCreateNode($settings);
703

    
704
    // Attempt to cancel account.
705
    $this->drupalGet('user/' . $account->uid . '/edit');
706
    $this->drupalPost(NULL, NULL, t('Cancel account'));
707
    $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
708
    $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'), 'Informs that all content will be unpublished.');
709

    
710
    // Confirm account cancellation.
711
    $timestamp = time();
712
    $this->drupalPost(NULL, NULL, t('Cancel account'));
713
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
714

    
715
    // Confirm account cancellation request.
716
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
717
    $account = user_load($account->uid, TRUE);
718
    $this->assertTrue($account->status == 0, 'User has been blocked.');
719

    
720
    // Confirm user's content has been unpublished.
721
    $test_node = node_load($node->nid, NULL, TRUE);
722
    $this->assertTrue($test_node->status == 0, 'Node of the user has been unpublished.');
723
    $test_node = node_load($node->nid, $node->vid, TRUE);
724
    $this->assertTrue($test_node->status == 0, 'Node revision of the user has been unpublished.');
725

    
726
    // Confirm that the confirmation message made it through to the end user.
727
    $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
728
  }
729

    
730
  /**
731
   * Delete account and anonymize all content.
732
   */
733
  function testUserAnonymize() {
734
    variable_set('user_cancel_method', 'user_cancel_reassign');
735

    
736
    // Create a user.
737
    $account = $this->drupalCreateUser(array('cancel account'));
738
    $this->drupalLogin($account);
739
    // Load real user object.
740
    $account = user_load($account->uid, TRUE);
741

    
742
    // Create a simple node.
743
    $node = $this->drupalCreateNode(array('uid' => $account->uid));
744

    
745
    // Create a node with two revisions, the initial one belonging to the
746
    // cancelling user.
747
    $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
748
    $revision = $revision_node->vid;
749
    $settings = get_object_vars($revision_node);
750
    $settings['revision'] = 1;
751
    $settings['uid'] = 1; // Set new/current revision to someone else.
752
    $revision_node = $this->drupalCreateNode($settings);
753

    
754
    // Attempt to cancel account.
755
    $this->drupalGet('user/' . $account->uid . '/edit');
756
    $this->drupalPost(NULL, NULL, t('Cancel account'));
757
    $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
758
    $this->assertRaw(t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))), 'Informs that all content will be attributed to anonymous account.');
759

    
760
    // Confirm account cancellation.
761
    $timestamp = time();
762
    $this->drupalPost(NULL, NULL, t('Cancel account'));
763
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
764

    
765
    // Confirm account cancellation request.
766
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
767
    $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
768

    
769
    // Confirm that user's content has been attributed to anonymous user.
770
    $test_node = node_load($node->nid, NULL, TRUE);
771
    $this->assertTrue(($test_node->uid == 0 && $test_node->status == 1), 'Node of the user has been attributed to anonymous user.');
772
    $test_node = node_load($revision_node->nid, $revision, TRUE);
773
    $this->assertTrue(($test_node->revision_uid == 0 && $test_node->status == 1), 'Node revision of the user has been attributed to anonymous user.');
774
    $test_node = node_load($revision_node->nid, NULL, TRUE);
775
    $this->assertTrue(($test_node->uid != 0 && $test_node->status == 1), "Current revision of the user's node was not attributed to anonymous user.");
776

    
777
    // Confirm that the confirmation message made it through to the end user.
778
    $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
779
  }
780

    
781
  /**
782
   * Delete account and remove all content.
783
   */
784
  function testUserDelete() {
785
    variable_set('user_cancel_method', 'user_cancel_delete');
786

    
787
    // Create a user.
788
    $account = $this->drupalCreateUser(array('cancel account', 'post comments', 'skip comment approval'));
789
    $this->drupalLogin($account);
790
    // Load real user object.
791
    $account = user_load($account->uid, TRUE);
792

    
793
    // Create a simple node.
794
    $node = $this->drupalCreateNode(array('uid' => $account->uid));
795

    
796
    // Create comment.
797
    $langcode = LANGUAGE_NONE;
798
    $edit = array();
799
    $edit['subject'] = $this->randomName(8);
800
    $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
801

    
802
    $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
803
    $this->drupalPost(NULL, array(), t('Save'));
804
    $this->assertText(t('Your comment has been posted.'));
805
    $comments = comment_load_multiple(array(), array('subject' => $edit['subject']));
806
    $comment = reset($comments);
807
    $this->assertTrue($comment->cid, 'Comment found.');
808

    
809
    // Create a node with two revisions, the initial one belonging to the
810
    // cancelling user.
811
    $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
812
    $revision = $revision_node->vid;
813
    $settings = get_object_vars($revision_node);
814
    $settings['revision'] = 1;
815
    $settings['uid'] = 1; // Set new/current revision to someone else.
816
    $revision_node = $this->drupalCreateNode($settings);
817

    
818
    // Attempt to cancel account.
819
    $this->drupalGet('user/' . $account->uid . '/edit');
820
    $this->drupalPost(NULL, NULL, t('Cancel account'));
821
    $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
822
    $this->assertText(t('Your account will be removed and all account information deleted. All of your content will also be deleted.'), 'Informs that all content will be deleted.');
823

    
824
    // Confirm account cancellation.
825
    $timestamp = time();
826
    $this->drupalPost(NULL, NULL, t('Cancel account'));
827
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
828

    
829
    // Confirm account cancellation request.
830
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
831
    $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
832

    
833
    // Confirm that user's content has been deleted.
834
    $this->assertFalse(node_load($node->nid, NULL, TRUE), 'Node of the user has been deleted.');
835
    $this->assertFalse(node_load($node->nid, $revision, TRUE), 'Node revision of the user has been deleted.');
836
    $this->assertTrue(node_load($revision_node->nid, NULL, TRUE), "Current revision of the user's node was not deleted.");
837
    $this->assertFalse(comment_load($comment->cid), 'Comment of the user has been deleted.');
838

    
839
    // Confirm that the confirmation message made it through to the end user.
840
    $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
841
  }
842

    
843
  /**
844
   * Create an administrative user and delete another user.
845
   */
846
  function testUserCancelByAdmin() {
847
    variable_set('user_cancel_method', 'user_cancel_reassign');
848

    
849
    // Create a regular user.
850
    $account = $this->drupalCreateUser(array());
851

    
852
    // Create administrative user.
853
    $admin_user = $this->drupalCreateUser(array('administer users'));
854
    $this->drupalLogin($admin_user);
855

    
856
    // Delete regular user.
857
    $this->drupalGet('user/' . $account->uid . '/edit');
858
    $this->drupalPost(NULL, NULL, t('Cancel account'));
859
    $this->assertRaw(t('Are you sure you want to cancel the account %name?', array('%name' => $account->name)), 'Confirmation form to cancel account displayed.');
860
    $this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.');
861

    
862
    // Confirm deletion.
863
    $this->drupalPost(NULL, NULL, t('Cancel account'));
864
    $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), 'User deleted.');
865
    $this->assertFalse(user_load($account->uid), 'User is not found in the database.');
866
  }
867

    
868
  /**
869
   * Create an administrative user and mass-delete other users.
870
   */
871
  function testMassUserCancelByAdmin() {
872
    variable_set('user_cancel_method', 'user_cancel_reassign');
873
    // Enable account cancellation notification.
874
    variable_set('user_mail_status_canceled_notify', TRUE);
875

    
876
    // Create administrative user.
877
    $admin_user = $this->drupalCreateUser(array('administer users'));
878
    $this->drupalLogin($admin_user);
879

    
880
    // Create some users.
881
    $users = array();
882
    for ($i = 0; $i < 3; $i++) {
883
      $account = $this->drupalCreateUser(array());
884
      $users[$account->uid] = $account;
885
    }
886

    
887
    // Cancel user accounts, including own one.
888
    $edit = array();
889
    $edit['operation'] = 'cancel';
890
    foreach ($users as $uid => $account) {
891
      $edit['accounts[' . $uid . ']'] = TRUE;
892
    }
893
    $edit['accounts[' . $admin_user->uid . ']'] = TRUE;
894
    // Also try to cancel uid 1.
895
    $edit['accounts[1]'] = TRUE;
896
    $this->drupalPost('admin/people', $edit, t('Update'));
897
    $this->assertText(t('Are you sure you want to cancel these user accounts?'), 'Confirmation form to cancel accounts displayed.');
898
    $this->assertText(t('When cancelling these accounts'), 'Allows to select account cancellation method.');
899
    $this->assertText(t('Require e-mail confirmation to cancel account.'), 'Allows to send confirmation mail.');
900
    $this->assertText(t('Notify user when account is canceled.'), 'Allows to send notification mail.');
901

    
902
    // Confirm deletion.
903
    $this->drupalPost(NULL, NULL, t('Cancel accounts'));
904
    $status = TRUE;
905
    foreach ($users as $account) {
906
      $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->name))) !== FALSE);
907
      $status = $status && !user_load($account->uid, TRUE);
908
    }
909
    $this->assertTrue($status, 'Users deleted and not found in the database.');
910

    
911
    // Ensure that admin account was not cancelled.
912
    $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
913
    $admin_user = user_load($admin_user->uid);
914
    $this->assertTrue($admin_user->status == 1, 'Administrative user is found in the database and enabled.');
915

    
916
    // Verify that uid 1's account was not cancelled.
917
    $user1 = user_load(1, TRUE);
918
    $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
919
  }
920
}
921

    
922
class UserPictureTestCase extends DrupalWebTestCase {
923
  protected $user;
924
  protected $_directory_test;
925

    
926
  public static function getInfo() {
927
    return array(
928
      'name' => 'Upload user picture',
929
      'description' => 'Assure that dimension check, extension check and image scaling work as designed.',
930
      'group' => 'User'
931
    );
932
  }
933

    
934
  function setUp() {
935
    parent::setUp();
936
    // Enable user pictures.
937
    variable_set('user_pictures', 1);
938

    
939
    $this->user = $this->drupalCreateUser();
940

    
941
    // Test if directories specified in settings exist in filesystem.
942
    $file_dir = 'public://';
943
    $file_check = file_prepare_directory($file_dir, FILE_CREATE_DIRECTORY);
944
    // TODO: Test public and private methods?
945

    
946
    $picture_dir = variable_get('user_picture_path', 'pictures');
947
    $picture_path = $file_dir . $picture_dir;
948

    
949
    $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY);
950
    $this->_directory_test = is_writable($picture_path);
951
    $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
952
  }
953

    
954
  function testNoPicture() {
955
    $this->drupalLogin($this->user);
956

    
957
    // Try to upload a file that is not an image for the user picture.
958
    $not_an_image = current($this->drupalGetTestFiles('html'));
959
    $this->saveUserPicture($not_an_image);
960
    $this->assertRaw(t('Only JPEG, PNG and GIF images are allowed.'), 'Non-image files are not accepted.');
961
  }
962

    
963
  /**
964
   * Do the test:
965
   *  GD Toolkit is installed
966
   *  Picture has invalid dimension
967
   *
968
   * results: The image should be uploaded because ImageGDToolkit resizes the picture
969
   */
970
  function testWithGDinvalidDimension() {
971
    if ($this->_directory_test && image_get_toolkit()) {
972
      $this->drupalLogin($this->user);
973

    
974
      $image = current($this->drupalGetTestFiles('image'));
975
      $info = image_get_info($image->uri);
976

    
977
      // Set new variables: invalid dimensions, valid filesize (0 = no limit).
978
      $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
979
      variable_set('user_picture_dimensions', $test_dim);
980
      variable_set('user_picture_file_size', 0);
981

    
982
      $pic_path = $this->saveUserPicture($image);
983
      // Check that the image was resized and is being displayed on the
984
      // user's profile page.
985
      $text = t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $test_dim));
986
      $this->assertRaw($text, 'Image was resized.');
987
      $alt = t("@user's picture", array('@user' => format_username($this->user)));
988
      $style = variable_get('user_picture_style', '');
989
      $this->assertRaw(check_plain(image_style_url($style, $pic_path)), "Image is displayed in user's edit page");
990

    
991
      // Check if file is located in proper directory.
992
      $this->assertTrue(is_file($pic_path), "File is located in proper directory");
993
    }
994
  }
995

    
996
  /**
997
   * Do the test:
998
   *  GD Toolkit is installed
999
   *  Picture has invalid size
1000
   *
1001
   * results: The image should be uploaded because ImageGDToolkit resizes the picture
1002
   */
1003
  function testWithGDinvalidSize() {
1004
    if ($this->_directory_test && image_get_toolkit()) {
1005
      $this->drupalLogin($this->user);
1006

    
1007
      // Images are sorted first by size then by name. We need an image
1008
      // bigger than 1 KB so we'll grab the last one.
1009
      $files = $this->drupalGetTestFiles('image');
1010
      $image = end($files);
1011
      $info = image_get_info($image->uri);
1012

    
1013
      // Set new variables: valid dimensions, invalid filesize.
1014
      $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
1015
      $test_size = 1;
1016
      variable_set('user_picture_dimensions', $test_dim);
1017
      variable_set('user_picture_file_size', $test_size);
1018

    
1019
      $pic_path = $this->saveUserPicture($image);
1020

    
1021
      // Test that the upload failed and that the correct reason was cited.
1022
      $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
1023
      $this->assertRaw($text, 'Upload failed.');
1024
      $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024)));
1025
      $this->assertRaw($text, 'File size cited as reason for failure.');
1026

    
1027
      // Check if file is not uploaded.
1028
      $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
1029
    }
1030
  }
1031

    
1032
  /**
1033
   * Do the test:
1034
   *  GD Toolkit is not installed
1035
   *  Picture has invalid size
1036
   *
1037
   * results: The image shouldn't be uploaded
1038
   */
1039
  function testWithoutGDinvalidDimension() {
1040
    if ($this->_directory_test && !image_get_toolkit()) {
1041
      $this->drupalLogin($this->user);
1042

    
1043
      $image = current($this->drupalGetTestFiles('image'));
1044
      $info = image_get_info($image->uri);
1045

    
1046
      // Set new variables: invalid dimensions, valid filesize (0 = no limit).
1047
      $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
1048
      variable_set('user_picture_dimensions', $test_dim);
1049
      variable_set('user_picture_file_size', 0);
1050

    
1051
      $pic_path = $this->saveUserPicture($image);
1052

    
1053
      // Test that the upload failed and that the correct reason was cited.
1054
      $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
1055
      $this->assertRaw($text, 'Upload failed.');
1056
      $text = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $test_dim));
1057
      $this->assertRaw($text, 'Checking response on invalid image (dimensions).');
1058

    
1059
      // Check if file is not uploaded.
1060
      $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
1061
    }
1062
  }
1063

    
1064
  /**
1065
   * Do the test:
1066
   *  GD Toolkit is not installed
1067
   *  Picture has invalid size
1068
   *
1069
   * results: The image shouldn't be uploaded
1070
   */
1071
  function testWithoutGDinvalidSize() {
1072
    if ($this->_directory_test && !image_get_toolkit()) {
1073
      $this->drupalLogin($this->user);
1074

    
1075
      $image = current($this->drupalGetTestFiles('image'));
1076
      $info = image_get_info($image->uri);
1077

    
1078
      // Set new variables: valid dimensions, invalid filesize.
1079
      $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
1080
      $test_size = 1;
1081
      variable_set('user_picture_dimensions', $test_dim);
1082
      variable_set('user_picture_file_size', $test_size);
1083

    
1084
      $pic_path = $this->saveUserPicture($image);
1085

    
1086
      // Test that the upload failed and that the correct reason was cited.
1087
      $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
1088
      $this->assertRaw($text, 'Upload failed.');
1089
      $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024)));
1090
      $this->assertRaw($text, 'File size cited as reason for failure.');
1091

    
1092
      // Check if file is not uploaded.
1093
      $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
1094
    }
1095
  }
1096

    
1097
  /**
1098
   * Do the test:
1099
   *  Picture is valid (proper size and dimension)
1100
   *
1101
   * results: The image should be uploaded
1102
   */
1103
  function testPictureIsValid() {
1104
    if ($this->_directory_test) {
1105
      $this->drupalLogin($this->user);
1106

    
1107
      $image = current($this->drupalGetTestFiles('image'));
1108
      $info = image_get_info($image->uri);
1109

    
1110
      // Set new variables: valid dimensions, valid filesize (0 = no limit).
1111
      $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
1112
      variable_set('user_picture_dimensions', $test_dim);
1113
      variable_set('user_picture_file_size', 0);
1114

    
1115
      $pic_path = $this->saveUserPicture($image);
1116

    
1117
      // Check if image is displayed in user's profile page.
1118
      $this->drupalGet('user');
1119
      $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
1120

    
1121
      // Check if file is located in proper directory.
1122
      $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
1123

    
1124
      // Set new picture dimensions.
1125
      $test_dim = ($info['width'] + 5) . 'x' . ($info['height'] + 5);
1126
      variable_set('user_picture_dimensions', $test_dim);
1127

    
1128
      $pic_path2 = $this->saveUserPicture($image);
1129
      $this->assertNotEqual($pic_path, $pic_path2, 'Filename of second picture is different.');
1130
    }
1131
  }
1132

    
1133
  /**
1134
   * Test HTTP schema working with user pictures.
1135
   */
1136
  function testExternalPicture() {
1137
    $this->drupalLogin($this->user);
1138
    // Set the default picture to an URI with a HTTP schema.
1139
    $images = $this->drupalGetTestFiles('image');
1140
    $image = $images[0];
1141
    $pic_path = file_create_url($image->uri);
1142
    variable_set('user_picture_default', $pic_path);
1143

    
1144
    // Check if image is displayed in user's profile page.
1145
    $this->drupalGet('user');
1146

    
1147
    // Get the user picture image via xpath.
1148
    $elements = $this->xpath('//div[@class="user-picture"]/img');
1149
    $this->assertEqual(count($elements), 1, "There is exactly one user picture on the user's profile page");
1150
    $this->assertEqual($pic_path, (string) $elements[0]['src'], "User picture source is correct.");
1151
  }
1152

    
1153
  /**
1154
   * Tests deletion of user pictures.
1155
   */
1156
  function testDeletePicture() {
1157
    $this->drupalLogin($this->user);
1158

    
1159
    $image = current($this->drupalGetTestFiles('image'));
1160
    $info = image_get_info($image->uri);
1161

    
1162
    // Set new variables: valid dimensions, valid filesize (0 = no limit).
1163
    $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
1164
    variable_set('user_picture_dimensions', $test_dim);
1165
    variable_set('user_picture_file_size', 0);
1166

    
1167
    // Save a new picture.
1168
    $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
1169
    $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
1170

    
1171
    // Load actual user data from database.
1172
    $account = user_load($this->user->uid, TRUE);
1173
    $pic_path = isset($account->picture) ? $account->picture->uri : NULL;
1174

    
1175
    // Check if image is displayed in user's profile page.
1176
    $this->drupalGet('user');
1177
    $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
1178

    
1179
    // Check if file is located in proper directory.
1180
    $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
1181

    
1182
    $edit = array('picture_delete' => 1);
1183
    $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
1184

    
1185
    // Load actual user data from database.
1186
    $account1 = user_load($this->user->uid, TRUE);
1187
    $this->assertNull($account1->picture, 'User object has no picture');
1188

    
1189
    $file = file_load($account->picture->fid);
1190
    $this->assertFalse($file, 'File is removed from database');
1191

    
1192
    // Clear out PHP's file stat cache so we see the current value.
1193
    clearstatcache();
1194
    $this->assertFalse(is_file($pic_path), 'File is removed from file system');
1195
  }
1196

    
1197
  function saveUserPicture($image) {
1198
    $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
1199
    $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
1200

    
1201
    // Load actual user data from database.
1202
    $account = user_load($this->user->uid, TRUE);
1203
    return isset($account->picture) ? $account->picture->uri : NULL;
1204
  }
1205

    
1206
  /**
1207
   * Tests the admin form validates user picture settings.
1208
   */
1209
  function testUserPictureAdminFormValidation() {
1210
    $this->drupalLogin($this->drupalCreateUser(array('administer users')));
1211

    
1212
    // The default values are valid.
1213
    $this->drupalPost('admin/config/people/accounts', array(), t('Save configuration'));
1214
    $this->assertText(t('The configuration options have been saved.'), 'The default values are valid.');
1215

    
1216
    // The form does not save with an invalid file size.
1217
    $edit = array(
1218
      'user_picture_file_size' => $this->randomName(),
1219
    );
1220
    $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
1221
    $this->assertNoText(t('The configuration options have been saved.'), 'The form does not save with an invalid file size.');
1222
  }
1223
}
1224

    
1225

    
1226
class UserPermissionsTestCase extends DrupalWebTestCase {
1227
  protected $admin_user;
1228
  protected $rid;
1229

    
1230
  public static function getInfo() {
1231
    return array(
1232
      'name' => 'Role permissions',
1233
      'description' => 'Verify that role permissions can be added and removed via the permissions page.',
1234
      'group' => 'User'
1235
    );
1236
  }
1237

    
1238
  function setUp() {
1239
    parent::setUp();
1240

    
1241
    $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users'));
1242

    
1243
    // Find the new role ID - it must be the maximum.
1244
    $all_rids = array_keys($this->admin_user->roles);
1245
    sort($all_rids);
1246
    $this->rid = array_pop($all_rids);
1247
  }
1248

    
1249
  /**
1250
   * Change user permissions and check user_access().
1251
   */
1252
  function testUserPermissionChanges() {
1253
    $this->drupalLogin($this->admin_user);
1254
    $rid = $this->rid;
1255
    $account = $this->admin_user;
1256

    
1257
    // Add a permission.
1258
    $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
1259
    $edit = array();
1260
    $edit[$rid . '[administer nodes]'] = TRUE;
1261
    $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
1262
    $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
1263
    drupal_static_reset('user_access');
1264
    drupal_static_reset('user_role_permissions');
1265
    $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
1266

    
1267
    // Remove a permission.
1268
    $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
1269
    $edit = array();
1270
    $edit[$rid . '[access user profiles]'] = FALSE;
1271
    $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
1272
    $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
1273
    drupal_static_reset('user_access');
1274
    drupal_static_reset('user_role_permissions');
1275
    $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
1276
  }
1277

    
1278
  /**
1279
   * Test assigning of permissions for the administrator role.
1280
   */
1281
  function testAdministratorRole() {
1282
    $this->drupalLogin($this->admin_user);
1283
    $this->drupalGet('admin/config/people/accounts');
1284

    
1285
    // Set the user's role to be the administrator role.
1286
    $edit = array();
1287
    $edit['user_admin_role'] = $this->rid;
1288
    $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
1289

    
1290
    // Enable aggregator module and ensure the 'administer news feeds'
1291
    // permission is assigned by default.
1292
    $edit = array();
1293
    $edit['modules[Core][aggregator][enable]'] = TRUE;
1294
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
1295
    $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role');
1296
  }
1297

    
1298
  /**
1299
   * Verify proper permission changes by user_role_change_permissions().
1300
   */
1301
  function testUserRoleChangePermissions() {
1302
    $rid = $this->rid;
1303
    $account = $this->admin_user;
1304

    
1305
    // Verify current permissions.
1306
    $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
1307
    $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
1308
    $this->assertTrue(user_access('administer site configuration', $account), 'User has "administer site configuration" permission.');
1309

    
1310
    // Change permissions.
1311
    $permissions = array(
1312
      'administer nodes' => 1,
1313
      'access user profiles' => 0,
1314
    );
1315
    user_role_change_permissions($rid, $permissions);
1316

    
1317
    // Verify proper permission changes.
1318
    $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
1319
    $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
1320
    $this->assertTrue(user_access('administer site configuration', $account), 'User still has "administer site configuration" permission.');
1321
  }
1322
}
1323

    
1324
class UserAdminTestCase extends DrupalWebTestCase {
1325
  public static function getInfo() {
1326
    return array(
1327
      'name' => 'User administration',
1328
      'description' => 'Test user administration page functionality.',
1329
      'group' => 'User'
1330
    );
1331
  }
1332

    
1333
  /**
1334
   * Registers a user and deletes it.
1335
   */
1336
  function testUserAdmin() {
1337

    
1338
    $user_a = $this->drupalCreateUser(array());
1339
    $user_b = $this->drupalCreateUser(array('administer taxonomy'));
1340
    $user_c = $this->drupalCreateUser(array('administer taxonomy'));
1341

    
1342
    // Create admin user to delete registered user.
1343
    $admin_user = $this->drupalCreateUser(array('administer users'));
1344
    $this->drupalLogin($admin_user);
1345
    $this->drupalGet('admin/people');
1346
    $this->assertText($user_a->name, 'Found user A on admin users page');
1347
    $this->assertText($user_b->name, 'Found user B on admin users page');
1348
    $this->assertText($user_c->name, 'Found user C on admin users page');
1349
    $this->assertText($admin_user->name, 'Found Admin user on admin users page');
1350

    
1351
    // Test for existence of edit link in table.
1352
    $link = l(t('edit'), "user/$user_a->uid/edit", array('query' => array('destination' => 'admin/people')));
1353
    $this->assertRaw($link, 'Found user A edit link on admin users page');
1354

    
1355
    // Filter the users by permission 'administer taxonomy'.
1356
    $edit = array();
1357
    $edit['permission'] = 'administer taxonomy';
1358
    $this->drupalPost('admin/people', $edit, t('Filter'));
1359

    
1360
    // Check if the correct users show up.
1361
    $this->assertNoText($user_a->name, 'User A not on filtered by perm admin users page');
1362
    $this->assertText($user_b->name, 'Found user B on filtered by perm admin users page');
1363
    $this->assertText($user_c->name, 'Found user C on filtered by perm admin users page');
1364

    
1365
    // Filter the users by role. Grab the system-generated role name for User C.
1366
    $edit['role'] = max(array_flip($user_c->roles));
1367
    $this->drupalPost('admin/people', $edit, t('Refine'));
1368

    
1369
    // Check if the correct users show up when filtered by role.
1370
    $this->assertNoText($user_a->name, 'User A not on filtered by role on admin users page');
1371
    $this->assertNoText($user_b->name, 'User B not on filtered by role on admin users page');
1372
    $this->assertText($user_c->name, 'User C on filtered by role on admin users page');
1373

    
1374
    // Test blocking of a user.
1375
    $account = user_load($user_c->uid);
1376
    $this->assertEqual($account->status, 1, 'User C not blocked');
1377
    $edit = array();
1378
    $edit['operation'] = 'block';
1379
    $edit['accounts[' . $account->uid . ']'] = TRUE;
1380
    $this->drupalPost('admin/people', $edit, t('Update'));
1381
    $account = user_load($user_c->uid, TRUE);
1382
    $this->assertEqual($account->status, 0, 'User C blocked');
1383

    
1384
    // Test unblocking of a user from /admin/people page and sending of activation mail
1385
    $editunblock = array();
1386
    $editunblock['operation'] = 'unblock';
1387
    $editunblock['accounts[' . $account->uid . ']'] = TRUE;
1388
    $this->drupalPost('admin/people', $editunblock, t('Update'));
1389
    $account = user_load($user_c->uid, TRUE);
1390
    $this->assertEqual($account->status, 1, 'User C unblocked');
1391
    $this->assertMail("to", $account->mail, "Activation mail sent to user C");
1392

    
1393
    // Test blocking and unblocking another user from /user/[uid]/edit form and sending of activation mail
1394
    $user_d = $this->drupalCreateUser(array());
1395
    $account1 = user_load($user_d->uid, TRUE);
1396
    $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => 0), t('Save'));
1397
    $account1 = user_load($user_d->uid, TRUE);
1398
    $this->assertEqual($account1->status, 0, 'User D blocked');
1399
    $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => TRUE), t('Save'));
1400
    $account1 = user_load($user_d->uid, TRUE);
1401
    $this->assertEqual($account1->status, 1, 'User D unblocked');
1402
    $this->assertMail("to", $account1->mail, "Activation mail sent to user D");
1403
  }
1404
}
1405

    
1406
/**
1407
 * Tests for user-configurable time zones.
1408
 */
1409
class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
1410
  public static function getInfo() {
1411
    return array(
1412
      'name' => 'User time zones',
1413
      'description' => 'Set a user time zone and verify that dates are displayed in local time.',
1414
      'group' => 'User',
1415
    );
1416
  }
1417

    
1418
  /**
1419
   * Tests the display of dates and time when user-configurable time zones are set.
1420
   */
1421
  function testUserTimeZone() {
1422
    // Setup date/time settings for Los Angeles time.
1423
    variable_set('date_default_timezone', 'America/Los_Angeles');
1424
    variable_set('configurable_timezones', 1);
1425
    variable_set('date_format_medium', 'Y-m-d H:i T');
1426

    
1427
    // Create a user account and login.
1428
    $web_user = $this->drupalCreateUser();
1429
    $this->drupalLogin($web_user);
1430

    
1431
    // Create some nodes with different authored-on dates.
1432
    // Two dates in PST (winter time):
1433
    $date1 = '2007-03-09 21:00:00 -0800';
1434
    $date2 = '2007-03-11 01:00:00 -0800';
1435
    // One date in PDT (summer time):
1436
    $date3 = '2007-03-20 21:00:00 -0700';
1437
    $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article'));
1438
    $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article'));
1439
    $node3 = $this->drupalCreateNode(array('created' => strtotime($date3), 'type' => 'article'));
1440

    
1441
    // Confirm date format and time zone.
1442
    $this->drupalGet("node/$node1->nid");
1443
    $this->assertText('2007-03-09 21:00 PST', 'Date should be PST.');
1444
    $this->drupalGet("node/$node2->nid");
1445
    $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.');
1446
    $this->drupalGet("node/$node3->nid");
1447
    $this->assertText('2007-03-20 21:00 PDT', 'Date should be PDT.');
1448

    
1449
    // Change user time zone to Santiago time.
1450
    $edit = array();
1451
    $edit['mail'] = $web_user->mail;
1452
    $edit['timezone'] = 'America/Santiago';
1453
    $this->drupalPost("user/$web_user->uid/edit", $edit, t('Save'));
1454
    $this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.');
1455

    
1456
    // Confirm date format and time zone.
1457
    $this->drupalGet("node/$node1->nid");
1458
    $this->assertText('2007-03-10 02:00 CLST', 'Date should be Chile summer time; five hours ahead of PST.');
1459
    $this->drupalGet("node/$node2->nid");
1460
    $this->assertText('2007-03-11 05:00 CLT', 'Date should be Chile time; four hours ahead of PST');
1461
    $this->drupalGet("node/$node3->nid");
1462
    $this->assertText('2007-03-21 00:00 CLT', 'Date should be Chile time; three hours ahead of PDT.');
1463
  }
1464
}
1465

    
1466
/**
1467
 * Test user autocompletion.
1468
 */
1469
class UserAutocompleteTestCase extends DrupalWebTestCase {
1470
  public static function getInfo() {
1471
    return array(
1472
      'name' => 'User autocompletion',
1473
      'description' => 'Test user autocompletion functionality.',
1474
      'group' => 'User'
1475
    );
1476
  }
1477

    
1478
  function setUp() {
1479
    parent::setUp();
1480

    
1481
    // Set up two users with different permissions to test access.
1482
    $this->unprivileged_user = $this->drupalCreateUser();
1483
    $this->privileged_user = $this->drupalCreateUser(array('access user profiles'));
1484
  }
1485

    
1486
  /**
1487
   * Tests access to user autocompletion and verify the correct results.
1488
   */
1489
  function testUserAutocomplete() {
1490
    // Check access from unprivileged user, should be denied.
1491
    $this->drupalLogin($this->unprivileged_user);
1492
    $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
1493
    $this->assertResponse(403, 'Autocompletion access denied to user without permission.');
1494

    
1495
    // Check access from privileged user.
1496
    $this->drupalLogout();
1497
    $this->drupalLogin($this->privileged_user);
1498
    $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
1499
    $this->assertResponse(200, 'Autocompletion access allowed.');
1500

    
1501
    // Using first letter of the user's name, make sure the user's full name is in the results.
1502
    $this->assertRaw($this->unprivileged_user->name, 'User name found in autocompletion results.');
1503
  }
1504
}
1505

    
1506

    
1507
/**
1508
 * Tests user links in the secondary menu.
1509
 */
1510
class UserAccountLinksUnitTests extends DrupalWebTestCase {
1511
  public static function getInfo() {
1512
    return array(
1513
      'name' => 'User account links',
1514
      'description' => 'Test user-account links.',
1515
      'group' => 'User'
1516
    );
1517
  }
1518

    
1519
  function setUp() {
1520
    parent::setUp('menu');
1521
  }
1522

    
1523
  /**
1524
   * Tests the secondary menu.
1525
   */
1526
  function testSecondaryMenu() {
1527
    // Create a regular user.
1528
    $user = $this->drupalCreateUser(array());
1529

    
1530
    // Log in and get the homepage.
1531
    $this->drupalLogin($user);
1532
    $this->drupalGet('<front>');
1533

    
1534
    // For a logged-in user, expect the secondary menu to have links for "My
1535
    // account" and "Log out".
1536
    $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
1537
      ':menu_id' => 'secondary-menu-links',
1538
      ':href' => 'user',
1539
      ':text' => 'My account',
1540
    ));
1541
    $this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
1542

    
1543
    $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
1544
      ':menu_id' => 'secondary-menu-links',
1545
      ':href' => 'user/logout',
1546
      ':text' => 'Log out',
1547
    ));
1548
    $this->assertEqual(count($link), 1, 'Log out link is in secondary menu.');
1549

    
1550
    // Log out and get the homepage.
1551
    $this->drupalLogout();
1552
    $this->drupalGet('<front>');
1553

    
1554
    // For a logged-out user, expect no secondary links.
1555
    $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links'));
1556
    $this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.');
1557
  }
1558

    
1559
  /**
1560
   * Tests disabling the 'My account' link.
1561
   */
1562
  function testDisabledAccountLink() {
1563
    // Create an admin user and log in.
1564
    $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu')));
1565

    
1566
    // Verify that the 'My account' link is enabled.
1567
    $this->drupalGet('admin/structure/menu/manage/user-menu');
1568
    $label = $this->xpath('//label[contains(.,:text)]/@for', array(':text' => 'Enable My account menu link'));
1569
    $this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
1570

    
1571
    // Disable the 'My account' link.
1572
    $input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0]));
1573
    $edit = array(
1574
      (string) $input[0] => FALSE,
1575
    );
1576
    $this->drupalPost('admin/structure/menu/manage/user-menu', $edit, t('Save configuration'));
1577

    
1578
    // Get the homepage.
1579
    $this->drupalGet('<front>');
1580

    
1581
    // Verify that the 'My account' link does not appear when disabled.
1582
    $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
1583
      ':menu_id' => 'secondary-menu-links',
1584
      ':href' => 'user',
1585
      ':text' => 'My account',
1586
    ));
1587
    $this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.');
1588
  }
1589

    
1590
}
1591

    
1592
/**
1593
 * Test user blocks.
1594
 */
1595
class UserBlocksUnitTests extends DrupalWebTestCase {
1596
  public static function getInfo() {
1597
    return array(
1598
      'name' => 'User blocks',
1599
      'description' => 'Test user blocks.',
1600
      'group' => 'User'
1601
    );
1602
  }
1603

    
1604
  /**
1605
   * Test the user login block.
1606
   */
1607
  function testUserLoginBlock() {
1608
    // Create a user with some permission that anonymous users lack.
1609
    $user = $this->drupalCreateUser(array('administer permissions'));
1610

    
1611
    // Log in using the block.
1612
    $edit = array();
1613
    $edit['name'] = $user->name;
1614
    $edit['pass'] = $user->pass_raw;
1615
    $this->drupalPost('admin/people/permissions', $edit, t('Log in'));
1616
    $this->assertNoText(t('User login'), 'Logged in.');
1617

    
1618
    // Check that we are still on the same page.
1619
    $this->assertEqual(url('admin/people/permissions', array('absolute' => TRUE)), $this->getUrl(), 'Still on the same page after login for access denied page');
1620

    
1621
    // Now, log out and repeat with a non-403 page.
1622
    $this->drupalLogout();
1623
    $this->drupalPost('filter/tips', $edit, t('Log in'));
1624
    $this->assertNoText(t('User login'), 'Logged in.');
1625
    $this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
1626

    
1627
    // Check that the user login block is not vulnerable to information
1628
    // disclosure to third party sites.
1629
    $this->drupalLogout();
1630
    $this->drupalPost('http://example.com/', $edit, t('Log in'), array('external' => FALSE));
1631
    // Check that we remain on the site after login.
1632
    $this->assertEqual(url('user/' . $user->uid, array('absolute' => TRUE)), $this->getUrl(), 'Redirected to user profile page after login from the frontpage');
1633
  }
1634

    
1635
  /**
1636
   * Test the Who's Online block.
1637
   */
1638
  function testWhosOnlineBlock() {
1639
    // Generate users and make sure there are no current user sessions.
1640
    $user1 = $this->drupalCreateUser(array());
1641
    $user2 = $this->drupalCreateUser(array());
1642
    $user3 = $this->drupalCreateUser(array());
1643
    $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions}")->fetchField(), 0, 'Sessions table is empty.');
1644

    
1645
    // Insert a user with two sessions.
1646
    $this->insertSession(array('uid' => $user1->uid));
1647
    $this->insertSession(array('uid' => $user1->uid));
1648
    $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid", array(':uid' => $user1->uid))->fetchField(), 2, 'Duplicate user session has been inserted.');
1649

    
1650
    // Insert a user with only one session.
1651
    $this->insertSession(array('uid' => $user2->uid, 'timestamp' => REQUEST_TIME + 1));
1652

    
1653
    // Insert an inactive logged-in user who should not be seen in the block.
1654
    $this->insertSession(array('uid' => $user3->uid, 'timestamp' => (REQUEST_TIME - variable_get('user_block_seconds_online', 900) - 1)));
1655

    
1656
    // Insert two anonymous user sessions.
1657
    $this->insertSession();
1658
    $this->insertSession();
1659

    
1660
    // Test block output.
1661
    $block = user_block_view('online');
1662
    $this->drupalSetContent($block['content']);
1663
    $this->assertRaw(t('2 users'), 'Correct number of online users (2 users).');
1664
    $this->assertText($user1->name, 'Active user 1 found in online list.');
1665
    $this->assertText($user2->name, 'Active user 2 found in online list.');
1666
    $this->assertNoText($user3->name, "Inactive user not found in online list.");
1667
    $this->assertTrue(strpos($this->drupalGetContent(), $user1->name) > strpos($this->drupalGetContent(), $user2->name), 'Online users are ordered correctly.');
1668
  }
1669

    
1670
  /**
1671
   * Insert a user session into the {sessions} table. This function is used
1672
   * since we cannot log in more than one user at the same time in tests.
1673
   */
1674
  private function insertSession(array $fields = array()) {
1675
    $fields += array(
1676
      'uid' => 0,
1677
      'sid' => drupal_hash_base64(uniqid(mt_rand(), TRUE)),
1678
      'timestamp' => REQUEST_TIME,
1679
    );
1680
    db_insert('sessions')
1681
      ->fields($fields)
1682
      ->execute();
1683
    $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid AND sid = :sid AND timestamp = :timestamp", array(':uid' => $fields['uid'], ':sid' => $fields['sid'], ':timestamp' => $fields['timestamp']))->fetchField(), 1, 'Session record inserted.');
1684
  }
1685
}
1686

    
1687
/**
1688
 * Tests saving a user account.
1689
 */
1690
class UserSaveTestCase extends DrupalWebTestCase {
1691

    
1692
  public static function getInfo() {
1693
    return array(
1694
      'name' => 'User save test',
1695
      'description' => 'Test user_save() for arbitrary new uid.',
1696
      'group' => 'User',
1697
    );
1698
  }
1699

    
1700
  /**
1701
   * Test creating a user with arbitrary uid.
1702
   */
1703
  function testUserImport() {
1704
    // User ID must be a number that is not in the database.
1705
    $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField();
1706
    $test_uid = $max_uid + mt_rand(1000, 1000000);
1707
    $test_name = $this->randomName();
1708

    
1709
    // Create the base user, based on drupalCreateUser().
1710
    $user = array(
1711
      'name' => $test_name,
1712
      'uid' => $test_uid,
1713
      'mail' => $test_name . '@example.com',
1714
      'is_new' => TRUE,
1715
      'pass' => user_password(),
1716
      'status' => 1,
1717
    );
1718
    $user_by_return = user_save(drupal_anonymous_user(), $user);
1719
    $this->assertTrue($user_by_return, 'Loading user by return of user_save().');
1720

    
1721
    // Test if created user exists.
1722
    $user_by_uid = user_load($test_uid);
1723
    $this->assertTrue($user_by_uid, 'Loading user by uid.');
1724

    
1725
    $user_by_name = user_load_by_name($test_name);
1726
    $this->assertTrue($user_by_name, 'Loading user by name.');
1727
  }
1728
}
1729

    
1730
/**
1731
 * Test the create user administration page.
1732
 */
1733
class UserCreateTestCase extends DrupalWebTestCase {
1734

    
1735
  public static function getInfo() {
1736
    return array(
1737
      'name' => 'User create',
1738
      'description' => 'Test the create user administration page.',
1739
      'group' => 'User',
1740
    );
1741
  }
1742

    
1743
  /**
1744
   * Create a user through the administration interface and ensure that it
1745
   * displays in the user list.
1746
   */
1747
  protected function testUserAdd() {
1748
    $user = $this->drupalCreateUser(array('administer users'));
1749
    $this->drupalLogin($user);
1750

    
1751
    foreach (array(FALSE, TRUE) as $notify) {
1752
      $edit = array(
1753
        'name' => $this->randomName(),
1754
        'mail' => $this->randomName() . '@example.com',
1755
        'pass[pass1]' => $pass = $this->randomString(),
1756
        'pass[pass2]' => $pass,
1757
        'notify' => $notify,
1758
      );
1759
      $this->drupalPost('admin/people/create', $edit, t('Create new account'));
1760

    
1761
      if ($notify) {
1762
        $this->assertText(t('A welcome message with further instructions has been e-mailed to the new user @name.', array('@name' => $edit['name'])), 'User created');
1763
        $this->assertEqual(count($this->drupalGetMails()), 1, 'Notification e-mail sent');
1764
      }
1765
      else {
1766
        $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created');
1767
        $this->assertEqual(count($this->drupalGetMails()), 0, 'Notification e-mail not sent');
1768
      }
1769

    
1770
      $this->drupalGet('admin/people');
1771
      $this->assertText($edit['name'], 'User found in list of users');
1772
    }
1773
  }
1774
}
1775

    
1776
/**
1777
 * Tests editing a user account.
1778
 */
1779
class UserEditTestCase extends DrupalWebTestCase {
1780

    
1781
  public static function getInfo() {
1782
    return array(
1783
      'name' => 'User edit',
1784
      'description' => 'Test user edit page.',
1785
      'group' => 'User',
1786
    );
1787
  }
1788

    
1789
  /**
1790
   * Test user edit page.
1791
   */
1792
  function testUserEdit() {
1793
    // Test user edit functionality with user pictures disabled.
1794
    variable_set('user_pictures', 0);
1795
    $user1 = $this->drupalCreateUser(array('change own username'));
1796
    $user2 = $this->drupalCreateUser(array());
1797
    $this->drupalLogin($user1);
1798

    
1799
    // Test that error message appears when attempting to use a non-unique user name.
1800
    $edit['name'] = $user2->name;
1801
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1802
    $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
1803

    
1804
    // Repeat the test with user pictures enabled, which modifies the form.
1805
    variable_set('user_pictures', 1);
1806
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1807
    $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
1808

    
1809
    // Check that filling out a single password field does not validate.
1810
    $edit = array();
1811
    $edit['pass[pass1]'] = '';
1812
    $edit['pass[pass2]'] = $this->randomName();
1813
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1814
    $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
1815

    
1816
    $edit['pass[pass1]'] = $this->randomName();
1817
    $edit['pass[pass2]'] = '';
1818
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1819
    $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
1820

    
1821
    // Test that the error message appears when attempting to change the mail or
1822
    // pass without the current password.
1823
    $edit = array();
1824
    $edit['mail'] = $this->randomName() . '@new.example.com';
1825
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1826
    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('E-mail address'))));
1827

    
1828
    $edit['current_pass'] = $user1->pass_raw;
1829
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1830
    $this->assertRaw(t("The changes have been saved."));
1831

    
1832
    // Test that the user must enter current password before changing passwords.
1833
    $edit = array();
1834
    $edit['pass[pass1]'] = $new_pass = $this->randomName();
1835
    $edit['pass[pass2]'] = $new_pass;
1836
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1837
    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password'))));
1838

    
1839
    // Try again with the current password.
1840
    $edit['current_pass'] = $user1->pass_raw;
1841
    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
1842
    $this->assertRaw(t("The changes have been saved."));
1843

    
1844
    // Make sure the user can log in with their new password.
1845
    $this->drupalLogout();
1846
    $user1->pass_raw = $new_pass;
1847
    $this->drupalLogin($user1);
1848
    $this->drupalLogout();
1849
  }
1850
}
1851

    
1852
/**
1853
 * Test case for user signatures.
1854
 */
1855
class UserSignatureTestCase extends DrupalWebTestCase {
1856
  public static function getInfo() {
1857
    return array(
1858
      'name' => 'User signatures',
1859
      'description' => 'Test user signatures.',
1860
      'group' => 'User',
1861
    );
1862
  }
1863

    
1864
  function setUp() {
1865
    parent::setUp('comment');
1866

    
1867
    // Enable user signatures.
1868
    variable_set('user_signatures', 1);
1869

    
1870
    // Prefetch text formats.
1871
    $this->full_html_format = filter_format_load('full_html');
1872
    $this->plain_text_format = filter_format_load('plain_text');
1873

    
1874
    // Create regular and administrative users.
1875
    $this->web_user = $this->drupalCreateUser(array());
1876
    $admin_permissions = array('administer comments');
1877
    foreach (filter_formats() as $format) {
1878
      if ($permission = filter_permission_name($format)) {
1879
        $admin_permissions[] = $permission;
1880
      }
1881
    }
1882
    $this->admin_user = $this->drupalCreateUser($admin_permissions);
1883
  }
1884

    
1885
  /**
1886
   * Test that a user can change their signature format and that it is respected
1887
   * upon display.
1888
   */
1889
  function testUserSignature() {
1890
    // Create a new node with comments on.
1891
    $node = $this->drupalCreateNode(array('comment' => COMMENT_NODE_OPEN));
1892

    
1893
    // Verify that user signature field is not displayed on registration form.
1894
    $this->drupalGet('user/register');
1895
    $this->assertNoText(t('Signature'));
1896

    
1897
    // Log in as a regular user and create a signature.
1898
    $this->drupalLogin($this->web_user);
1899
    $signature_text = "<h1>" . $this->randomName() . "</h1>";
1900
    $edit = array(
1901
      'signature[value]' => $signature_text,
1902
      'signature[format]' => $this->plain_text_format->format,
1903
    );
1904
    $this->drupalPost('user/' . $this->web_user->uid . '/edit', $edit, t('Save'));
1905

    
1906
    // Verify that values were stored.
1907
    $this->assertFieldByName('signature[value]', $edit['signature[value]'], 'Submitted signature text found.');
1908
    $this->assertFieldByName('signature[format]', $edit['signature[format]'], 'Submitted signature format found.');
1909

    
1910
    // Create a comment.
1911
    $langcode = LANGUAGE_NONE;
1912
    $edit = array();
1913
    $edit['subject'] = $this->randomName(8);
1914
    $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
1915
    $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
1916
    $this->drupalPost(NULL, array(), t('Save'));
1917

    
1918
    // Get the comment ID. (This technique is the same one used in the Comment
1919
    // module's CommentHelperCase test case.)
1920
    preg_match('/#comment-([0-9]+)/', $this->getURL(), $match);
1921
    $comment_id = $match[1];
1922

    
1923
    // Log in as an administrator and edit the comment to use Full HTML, so
1924
    // that the comment text itself is not filtered at all.
1925
    $this->drupalLogin($this->admin_user);
1926
    $edit['comment_body[' . $langcode . '][0][format]'] = $this->full_html_format->format;
1927
    $this->drupalPost('comment/' . $comment_id . '/edit', $edit, t('Save'));
1928

    
1929
    // Assert that the signature did not make it through unfiltered.
1930
    $this->drupalGet('node/' . $node->nid);
1931
    $this->assertNoRaw($signature_text, 'Unfiltered signature text not found.');
1932
    $this->assertRaw(check_markup($signature_text, $this->plain_text_format->format), 'Filtered signature text found.');
1933
  }
1934
}
1935

    
1936
/*
1937
 * Test that a user, having editing their own account, can still log in.
1938
 */
1939
class UserEditedOwnAccountTestCase extends DrupalWebTestCase {
1940

    
1941
  public static function getInfo() {
1942
    return array(
1943
      'name' => 'User edited own account',
1944
      'description' => 'Test user edited own account can still log in.',
1945
      'group' => 'User',
1946
    );
1947
  }
1948

    
1949
  function testUserEditedOwnAccount() {
1950
    // Change account setting 'Who can register accounts?' to Administrators
1951
    // only.
1952
    variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY);
1953

    
1954
    // Create a new user account and log in.
1955
    $account = $this->drupalCreateUser(array('change own username'));
1956
    $this->drupalLogin($account);
1957

    
1958
    // Change own username.
1959
    $edit = array();
1960
    $edit['name'] = $this->randomName();
1961
    $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save'));
1962

    
1963
    // Log out.
1964
    $this->drupalLogout();
1965

    
1966
    // Set the new name on the user account and attempt to log back in.
1967
    $account->name = $edit['name'];
1968
    $this->drupalLogin($account);
1969
  }
1970
}
1971

    
1972
/**
1973
 * Test case to test adding, editing and deleting roles.
1974
 */
1975
class UserRoleAdminTestCase extends DrupalWebTestCase {
1976

    
1977
  public static function getInfo() {
1978
    return array(
1979
      'name' => 'User role administration',
1980
      'description' => 'Test adding, editing and deleting user roles and changing role weights.',
1981
      'group' => 'User',
1982
    );
1983
  }
1984

    
1985
  function setUp() {
1986
    parent::setUp();
1987
    $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
1988
  }
1989

    
1990
  /**
1991
   * Test adding, renaming and deleting roles.
1992
   */
1993
  function testRoleAdministration() {
1994
    $this->drupalLogin($this->admin_user);
1995

    
1996
    // Test adding a role. (In doing so, we use a role name that happens to
1997
    // correspond to an integer, to test that the role administration pages
1998
    // correctly distinguish between role names and IDs.)
1999
    $role_name = '123';
2000
    $edit = array('name' => $role_name);
2001
    $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
2002
    $this->assertText(t('The role has been added.'), 'The role has been added.');
2003
    $role = user_role_load_by_name($role_name);
2004
    $this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
2005

    
2006
    // Try adding a duplicate role.
2007
    $this->drupalPost(NULL, $edit, t('Add role'));
2008
    $this->assertRaw(t('The role name %name already exists. Choose another role name.', array('%name' => $role_name)), 'Duplicate role warning displayed.');
2009

    
2010
    // Test renaming a role.
2011
    $old_name = $role_name;
2012
    $role_name = '456';
2013
    $edit = array('name' => $role_name);
2014
    $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", $edit, t('Save role'));
2015
    $this->assertText(t('The role has been renamed.'), 'The role has been renamed.');
2016
    $this->assertFalse(user_role_load_by_name($old_name), 'The role can no longer be retrieved from the database using its old name.');
2017
    $this->assertTrue(is_object(user_role_load_by_name($role_name)), 'The role can be retrieved from the database using its new name.');
2018

    
2019
    // Test deleting a role.
2020
    $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", NULL, t('Delete role'));
2021
    $this->drupalPost(NULL, NULL, t('Delete'));
2022
    $this->assertText(t('The role has been deleted.'), 'The role has been deleted');
2023
    $this->assertNoLinkByHref("admin/people/permissions/roles/edit/{$role->rid}", 'Role edit link removed.');
2024
    $this->assertFalse(user_role_load_by_name($role_name), 'A deleted role can no longer be loaded.');
2025

    
2026
    // Make sure that the system-defined roles cannot be edited via the user
2027
    // interface.
2028
    $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_ANONYMOUS_RID);
2029
    $this->assertResponse(403, 'Access denied when trying to edit the built-in anonymous role.');
2030
    $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_AUTHENTICATED_RID);
2031
    $this->assertResponse(403, 'Access denied when trying to edit the built-in authenticated role.');
2032
  }
2033

    
2034
  /**
2035
   * Test user role weight change operation.
2036
   */
2037
  function testRoleWeightChange() {
2038
    $this->drupalLogin($this->admin_user);
2039

    
2040
    // Pick up a random role and get its weight.
2041
    $rid = array_rand(user_roles());
2042
    $role = user_role_load($rid);
2043
    $old_weight = $role->weight;
2044

    
2045
    // Change the role weight and submit the form.
2046
    $edit = array('roles['. $rid .'][weight]' => $old_weight + 1);
2047
    $this->drupalPost('admin/people/permissions/roles', $edit, t('Save order'));
2048
    $this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
2049

    
2050
    // Retrieve the saved role and compare its weight.
2051
    $role = user_role_load($rid);
2052
    $new_weight = $role->weight;
2053
    $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.');
2054
  }
2055
}
2056

    
2057
/**
2058
 * Test user token replacement in strings.
2059
 */
2060
class UserTokenReplaceTestCase extends DrupalWebTestCase {
2061
  public static function getInfo() {
2062
    return array(
2063
      'name' => 'User token replacement',
2064
      'description' => 'Generates text using placeholders for dummy content to check user token replacement.',
2065
      'group' => 'User',
2066
    );
2067
  }
2068

    
2069
  /**
2070
   * Creates a user, then tests the tokens generated from it.
2071
   */
2072
  function testUserTokenReplacement() {
2073
    global $language;
2074
    $url_options = array(
2075
      'absolute' => TRUE,
2076
      'language' => $language,
2077
    );
2078

    
2079
    // Create two users and log them in one after another.
2080
    $user1 = $this->drupalCreateUser(array());
2081
    $user2 = $this->drupalCreateUser(array());
2082
    $this->drupalLogin($user1);
2083
    $this->drupalLogout();
2084
    $this->drupalLogin($user2);
2085

    
2086
    $account = user_load($user1->uid);
2087
    $global_account = user_load($GLOBALS['user']->uid);
2088

    
2089
    // Generate and test sanitized tokens.
2090
    $tests = array();
2091
    $tests['[user:uid]'] = $account->uid;
2092
    $tests['[user:name]'] = check_plain(format_username($account));
2093
    $tests['[user:mail]'] = check_plain($account->mail);
2094
    $tests['[user:url]'] = url("user/$account->uid", $url_options);
2095
    $tests['[user:edit-url]'] = url("user/$account->uid/edit", $url_options);
2096
    $tests['[user:last-login]'] = format_date($account->login, 'medium', '', NULL, $language->language);
2097
    $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language);
2098
    $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language);
2099
    $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language);
2100
    $tests['[current-user:name]'] = check_plain(format_username($global_account));
2101

    
2102
    // Test to make sure that we generated something for each token.
2103
    $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
2104

    
2105
    foreach ($tests as $input => $expected) {
2106
      $output = token_replace($input, array('user' => $account), array('language' => $language));
2107
      $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input)));
2108
    }
2109

    
2110
    // Generate and test unsanitized tokens.
2111
    $tests['[user:name]'] = format_username($account);
2112
    $tests['[user:mail]'] = $account->mail;
2113
    $tests['[current-user:name]'] = format_username($global_account);
2114

    
2115
    foreach ($tests as $input => $expected) {
2116
      $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
2117
      $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input)));
2118
    }
2119
  }
2120
}
2121

    
2122
/**
2123
 * Test user search.
2124
 */
2125
class UserUserSearchTestCase extends DrupalWebTestCase {
2126
  public static function getInfo() {
2127
    return array(
2128
      'name' => 'User search',
2129
      'description' => 'Tests the user search page and verifies that sensitive information is hidden from unauthorized users.',
2130
      'group' => 'User',
2131
    );
2132
  }
2133

    
2134
  function testUserSearch() {
2135
    $user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search'));
2136
    $this->drupalLogin($user1);
2137
    $keys = $user1->mail;
2138
    $edit = array('keys' => $keys);
2139
    $this->drupalPost('search/user/', $edit, t('Search'));
2140
    $this->assertNoText($keys);
2141
    $this->drupalLogout();
2142

    
2143
    $user2 = $this->drupalCreateUser(array('administer users', 'access user profiles', 'search content', 'use advanced search'));
2144
    $this->drupalLogin($user2);
2145
    $keys = $user2->mail;
2146
    $edit = array('keys' => $keys);
2147
    $this->drupalPost('search/user/', $edit, t('Search'));
2148
    $this->assertText($keys);
2149

    
2150
    // Create a blocked user.
2151
    $blocked_user = $this->drupalCreateUser();
2152
    $edit = array('status' => 0);
2153
    $blocked_user = user_save($blocked_user, $edit);
2154

    
2155
    // Verify that users with "administer users" permissions can see blocked
2156
    // accounts in search results.
2157
    $edit = array('keys' => $blocked_user->name);
2158
    $this->drupalPost('search/user/', $edit, t('Search'));
2159
    $this->assertText($blocked_user->name, 'Blocked users are listed on the user search results for users with the "administer users" permission.');
2160

    
2161
    // Verify that users without "administer users" permissions do not see
2162
    // blocked accounts in search results.
2163
    $this->drupalLogin($user1);
2164
    $edit = array('keys' => $blocked_user->name);
2165
    $this->drupalPost('search/user/', $edit, t('Search'));
2166
    $this->assertNoText($blocked_user->name, 'Blocked users are hidden from the user search results.');
2167

    
2168
    $this->drupalLogout();
2169
  }
2170
}
2171

    
2172
/**
2173
 * Test role assignment.
2174
 */
2175
class UserRolesAssignmentTestCase extends DrupalWebTestCase {
2176
  protected $admin_user;
2177

    
2178
  public static function getInfo() {
2179
    return array(
2180
      'name' => 'Role assignment',
2181
      'description' => 'Tests that users can be assigned and unassigned roles.',
2182
      'group' => 'User'
2183
    );
2184
  }
2185

    
2186
  function setUp() {
2187
    parent::setUp();
2188
    $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
2189
    $this->drupalLogin($this->admin_user);
2190
  }
2191

    
2192
  /**
2193
   * Tests that a user can be assigned a role and that the role can be removed
2194
   * again.
2195
   */
2196
  function testAssignAndRemoveRole()  {
2197
    $rid = $this->drupalCreateRole(array('administer content types'));
2198
    $account = $this->drupalCreateUser();
2199

    
2200
    // Assign the role to the user.
2201
    $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => $rid), t('Save'));
2202
    $this->assertText(t('The changes have been saved.'));
2203
    $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
2204
    $this->userLoadAndCheckRoleAssigned($account, $rid);
2205

    
2206
    // Remove the role from the user.
2207
    $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
2208
    $this->assertText(t('The changes have been saved.'));
2209
    $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
2210
    $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
2211
  }
2212

    
2213
  /**
2214
   * Tests that when creating a user the role can be assigned. And that it can
2215
   * be removed again.
2216
   */
2217
  function testCreateUserWithRole() {
2218
    $rid = $this->drupalCreateRole(array('administer content types'));
2219
    // Create a new user and add the role at the same time.
2220
    $edit = array(
2221
      'name' => $this->randomName(),
2222
      'mail' => $this->randomName() . '@example.com',
2223
      'pass[pass1]' => $pass = $this->randomString(),
2224
      'pass[pass2]' => $pass,
2225
      "roles[$rid]" => $rid,
2226
    );
2227
    $this->drupalPost('admin/people/create', $edit, t('Create new account'));
2228
    $this->assertText(t('Created a new user account for !name.', array('!name' => $edit['name'])));
2229
    // Get the newly added user.
2230
    $account = user_load_by_name($edit['name']);
2231

    
2232
    $this->drupalGet('user/' . $account->uid . '/edit');
2233
    $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
2234
    $this->userLoadAndCheckRoleAssigned($account, $rid);
2235

    
2236
    // Remove the role again.
2237
    $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
2238
    $this->assertText(t('The changes have been saved.'));
2239
    $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
2240
    $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
2241
  }
2242

    
2243
  /**
2244
   * Check role on user object.
2245
   *
2246
   * @param object $account
2247
   *   The user account to check.
2248
   * @param string $rid
2249
   *   The role ID to search for.
2250
   * @param bool $is_assigned
2251
   *   (optional) Whether to assert that $rid exists (TRUE) or not (FALSE).
2252
   *   Defaults to TRUE.
2253
   */
2254
  private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) {
2255
    $account = user_load($account->uid, TRUE);
2256
    if ($is_assigned) {
2257
      $this->assertTrue(array_key_exists($rid, $account->roles), 'The role is present in the user object.');
2258
    }
2259
    else {
2260
      $this->assertFalse(array_key_exists($rid, $account->roles), 'The role is not present in the user object.');
2261
    }
2262
  }
2263
}
2264

    
2265

    
2266
/**
2267
 * Unit test for authmap assignment.
2268
 */
2269
class UserAuthmapAssignmentTestCase extends DrupalWebTestCase {
2270
  public static function getInfo() {
2271
    return array(
2272
      'name' => 'Authmap assignment',
2273
      'description' => 'Tests that users can be assigned and unassigned authmaps.',
2274
      'group' => 'User'
2275
    );
2276
  }
2277

    
2278
  /**
2279
   * Test authmap assignment and retrieval.
2280
   */
2281
  function testAuthmapAssignment()  {
2282
    $account = $this->drupalCreateUser();
2283

    
2284
    // Assign authmaps to the user.
2285
    $authmaps = array(
2286
      'authname_poll' => 'external username one',
2287
      'authname_book' => 'external username two',
2288
    );
2289
    user_set_authmaps($account, $authmaps);
2290

    
2291
    // Test for expected authmaps.
2292
    $expected_authmaps = array(
2293
      'external username one' => array(
2294
        'poll' => 'external username one',
2295
      ),
2296
      'external username two' => array(
2297
        'book' => 'external username two',
2298
      ),
2299
    );
2300
    foreach ($expected_authmaps as $authname => $expected_output) {
2301
      $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
2302
    }
2303

    
2304
    // Remove authmap for module poll, add authmap for module blog.
2305
    $authmaps = array(
2306
      'authname_poll' => NULL,
2307
      'authname_blog' => 'external username three',
2308
    );
2309
    user_set_authmaps($account, $authmaps);
2310

    
2311
    // Assert that external username one does not have authmaps.
2312
    $remove_username = 'external username one';
2313
    unset($expected_authmaps[$remove_username]);
2314
    $this->assertFalse(user_get_authmaps($remove_username), format_string('Authmap for %authname was removed.', array('%authname' => $remove_username)));
2315

    
2316
    // Assert that a new authmap was created for external username three, and
2317
    // existing authmaps for external username two were unchanged.
2318
    $expected_authmaps['external username three'] = array('blog' => 'external username three');
2319
    foreach ($expected_authmaps as $authname => $expected_output) {
2320
      $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
2321
    }
2322
  }
2323
}
2324

    
2325
/**
2326
 * Tests user_validate_current_pass on a custom form.
2327
 */
2328
class UserValidateCurrentPassCustomForm extends DrupalWebTestCase {
2329

    
2330
  public static function getInfo() {
2331
    return array(
2332
      'name' => 'User validate current pass custom form',
2333
      'description' => 'Test that user_validate_current_pass is usable on a custom form.',
2334
      'group' => 'User',
2335
    );
2336
  }
2337

    
2338
  /**
2339
   * User with permission to view content.
2340
   */
2341
  protected $accessUser;
2342

    
2343
  /**
2344
   * User permission to administer users.
2345
   */
2346
  protected $adminUser;
2347

    
2348
  function setUp() {
2349
    parent::setUp('user_form_test');
2350
    // Create two users
2351
    $this->accessUser = $this->drupalCreateUser(array('access content'));
2352
    $this->adminUser = $this->drupalCreateUser(array('administer users'));
2353
  }
2354

    
2355
  /**
2356
   * Tests that user_validate_current_pass can be reused on a custom form.
2357
   */
2358
  function testUserValidateCurrentPassCustomForm() {
2359
    $this->drupalLogin($this->adminUser);
2360

    
2361
    // Submit the custom form with the admin user using the access user's password.
2362
    $edit = array();
2363
    $edit['user_form_test_field'] = $this->accessUser->name;
2364
    $edit['current_pass'] = $this->accessUser->pass_raw;
2365
    $this->drupalPost('user_form_test_current_password/' . $this->accessUser->uid, $edit, t('Test'));
2366
    $this->assertText(t('The password has been validated and the form submitted successfully.'));
2367
  }
2368
}