user.test 55.2 KB
Newer Older
1 2 3 4
<?php
// $Id$

class UserRegistrationTestCase extends DrupalWebTestCase {
5
  public static function getInfo() {
6
    return array(
7
      'name' => 'User registration',
8
      'description' => 'Test registration of user under different configurations.',
9
      'group' => 'User'
10 11
    );
  }
12 13 14 15 16 17 18 19 20 21 22
  
  function testRegistrationWithEmailVerification() {
    // Require e-mail verification.
    variable_set('user_email_verification', TRUE);
    
    // Set registration to administrator only.
    variable_set('user_register', 0);
    $this->drupalGet('user/register');
    $this->assertResponse(403, t('Registration page is inaccessible when only administrators can create accounts.'));
    
    // Allow registration by site visitors without administrator approval.
23 24 25
    variable_set('user_register', 1);
    $edit = array();
    $edit['name'] = $name = $this->randomName();
26
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
27 28
    $this->drupalPost('user/register', $edit, t('Create new account'));
    $this->assertText(t('Your password and further instructions have been sent to your e-mail address.'), t('User registered successfully.'));
29 30 31 32 33
    $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail)));
    $this->assertTrue($new_user->status, t('New account is active after registration.'));
    
    // Allow registration by site visitors, but require administrator approval.
    variable_set('user_register', 2);
34
    $edit = array();
35 36 37 38 39 40 41 42 43 44 45 46 47
    $edit['name'] = $name = $this->randomName();
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
    $this->drupalPost('user/register', $edit, t('Create new account'));
    $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail)));
    $this->assertFalse($new_user->status, t('New account is blocked until approved by an administrator.'));
  }
  
  function testRegistrationWithoutEmailVerification() {
    // Don't require e-mail verification.
    variable_set('user_email_verification', FALSE);
    
    // Allow registration by site visitors without administrator approval.
    variable_set('user_register', 1);
48
    $edit = array();
49 50 51 52
    $edit['name'] = $name = $this->randomName();
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
    
    // Try entering a mismatching password.
53 54
    $edit['pass[pass1]'] = '99999.0';
    $edit['pass[pass2]'] = '99999';
55
    $this->drupalPost('user/register', $edit, t('Create new account'));
56 57
    $this->assertText(t('The specified passwords do not match.'), t('Type mismatched passwords display an error message.'));

58 59
    // Enter a correct password.
    $edit['pass[pass1]'] = $new_pass = $this->randomName();
60
    $edit['pass[pass2]'] = $new_pass;
61 62 63 64 65 66 67
    $this->drupalPost('user/register', $edit, t('Create new account'));
    $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail)));
    $this->assertText(t('Registration successful. You are now logged in.'), t('Users are logged in after registering.'));
    $this->drupalLogout();
    
    // Allow registration by site visitors, but require administrator approval.
    variable_set('user_register', 2);
68
    $edit = array();
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    $edit['name'] = $name = $this->randomName();
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
    $edit['pass[pass1]'] = $pass = $this->randomName();
    $edit['pass[pass2]'] = $pass;
    $this->drupalPost('user/register', $edit, t('Create new account'));
    $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), t('Users are notified of pending approval'));
    
    // Try to login before administrator approval.
    $auth = array(
      'name' => $name,
      'pass' => $pass,
    );
    $this->drupalPost('user/login', $auth, t('Log in'));
    $this->assertText(t('The username @name has not been activated or is blocked.', array('@name' => $name)), t('User cannot login yet.'));

    // Activate the new account.
    $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail)));
    $admin_user = $this->drupalCreateUser(array('administer users'));
    $this->drupalLogin($admin_user);
    $edit = array(
      'status' => 1,
    );
    $this->drupalPost('user/' . $new_user->uid . '/edit', $edit, t('Save'));
    $this->drupalLogout();
    
    // Login after administrator approval.
    $this->drupalPost('user/login', $auth, t('Log in'));
    $this->assertText(t('Member for'), t('User can log in after administrator approval.'));
  }
98

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  function testRegistrationDefaultValues() {
    // Allow registration by site visitors without administrator approval.
    variable_set('user_register', 1);
    
    // Don't require e-mail verification.
    variable_set('user_email_verification', FALSE);
    
    // Set the default timezone to Brussels.
    variable_set('configurable_timezones', 1);
    variable_set('date_default_timezone', 'Europe/Brussels');
    
    $edit = array();
    $edit['name'] = $name = $this->randomName();
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
    $edit['pass[pass1]'] = $new_pass = $this->randomName();
    $edit['pass[pass2]'] = $new_pass;
    $this->drupalPost('user/register', $edit, t('Create new account'));
    
    // Check user fields.
    $new_user = reset(user_load_multiple(array(), array('name' => $name, 'mail' => $mail)));
    $this->assertEqual($new_user->name, $name, t('Username matches.'));
    $this->assertEqual($new_user->mail, $mail, t('E-mail address matches.'));
    $this->assertEqual($new_user->theme, '', t('Correct theme field.'));
    $this->assertEqual($new_user->signature, '', t('Correct signature field.'));
    $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), t('Correct creation time.'));
    $this->assertEqual($new_user->status, variable_get('user_register', 1) == 1 ? 1 : 0, t('Correct status field.'));
    $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), t('Correct time zone field.'));
    $this->assertEqual($new_user->language, '', t('Correct language field.'));
    $this->assertEqual($new_user->picture, '', t('Correct picture field.'));
    $this->assertEqual($new_user->init, $mail, t('Correct init field.'));
129 130 131 132
  }
}

class UserValidationTestCase extends DrupalWebTestCase {
133
  public static function getInfo() {
134
    return array(
135 136 137
      'name' => 'Username/e-mail validation',
      'description' => 'Verify that username/email validity checks behave as designed.',
      'group' => 'User'
138 139 140 141
    );
  }

  // Username validation.
142 143 144 145 146 147 148 149 150 151
  function testUsernames() {
    $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'),
      'foo'                    => array('Valid username', 'assertNull'),
      'FOO'                    => array('Valid username', 'assertNull'),
      'Foo O\'Bar'             => array('Valid username', 'assertNull'),
      'foo@bar'                => array('Valid username', 'assertNull'),
      'foo@example.com'        => array('Valid username', 'assertNull'),
      'foo@-example.com'       => array('Valid username', 'assertNull'), // invalid domains are allowed in usernames
      'þòøÇߪř€'               => array('Valid username', 'assertNull'),
      'ᚠᛇᚻ᛫ᛒᛦᚦ'                => array('Valid UTF8 username', 'assertNull'), // runes
152 153 154 155 156 157 158 159
      ' foo'                   => array('Invalid username that starts with a space', 'assertNotNull'),
      'foo '                   => array('Invalid username that ends with a space', 'assertNotNull'),
      'foo  bar'               => array('Invalid username that contains 2 spaces \'&nbsp;&nbsp;\'', 'assertNotNull'),
      ''                       => array('Invalid empty username', 'assertNotNull'),
      'foo/'                   => array('Invalid username containing invalid chars', 'assertNotNull'),
      'foo' . chr(0) . 'bar'   => array('Invalid username containing chr(0)', 'assertNotNull'), // NULL
      'foo' . chr(13) . 'bar'  => array('Invalid username containing chr(13)', 'assertNotNull'), // CR
      str_repeat('x', USERNAME_MAX_LENGTH + 1) => array('Invalid excessively long username', 'assertNotNull'),
160 161 162 163
    );
    foreach ($test_cases as $name => $test_case) {
      list($description, $test) = $test_case;
      $result = user_validate_name($name);
164
      $this->$test($result, $description . ' (' . $name . ')');
165
    }
166 167
  }

168 169 170 171 172 173 174 175 176 177
  // Mail validation. More extensive tests can be found at common.test
  function testMailAddresses() {
    $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'),
      ''                => array('Empty mail address', 'assertNotNull'),
      'foo'             => array('Invalid mail address', 'assertNotNull'),
      'foo@example.com' => array('Valid mail address', 'assertNull'),
    );
    foreach ($test_cases as $name => $test_case) {
      list($description, $test) = $test_case;
      $result = user_validate_mail($name);
178
      $this->$test($result, $description . ' (' . $name . ')');
179
    }
180 181 182
  }
}

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
/**
 * Functional tests for user logins, including rate limiting of login attempts.
 */
class UserLoginTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'User login',
      'description' => 'Ensure that login works as expected.',
      'group' => 'User',
    );
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  /**
   * Make an unsuccessful login attempt.
   *
   * @param $account
   *   A user object with name and pass_raw attributes for the login attempt.
   * @param $flood_trigger
   *   Whether or not to expect that the flood control mechanism will be
   *   triggered.
   */
  function assertFailedLogin($account, $flood_trigger = NULL) {
    $edit = array(
      'name' => $account->name,
      'pass' => $account->pass_raw,
    );
    $this->drupalPost('user', $edit, t('Log in'));
    if (isset($flood_trigger)) {
      if ($flood_trigger == 'user') {
        $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. Please 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. Please try again later, or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
      }
      else {
        // No uid, so the limit is IP-based.
        $this->assertRaw(t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Please try again later, or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
      }
    }
    else {
      $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'));
    }
  }
}

300
class UserCancelTestCase extends DrupalWebTestCase {
301
  public static function getInfo() {
302
    return array(
303 304 305
      'name' => 'Cancel account',
      'description' => 'Ensure that account cancellation methods work as expected.',
      'group' => 'User',
306 307 308 309
    );
  }

  /**
310
   * Attempt to cancel account without permission.
311
   */
312 313 314 315 316 317 318
  function testUserCancelWithoutPermission() {
    variable_set('user_cancel_method', 'user_cancel_reassign');

    // Create a user.
    $account = $this->drupalCreateUser(array());
    $this->drupalLogin($account);
    // Load real user object.
319
    $account = user_load($account->uid, TRUE);
320 321 322 323 324 325 326 327 328 329 330 331

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

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

    // Attempt bogus account cancellation request confirmation.
    $timestamp = $account->login;
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
    $this->assertResponse(403, t('Bogus cancelling request rejected.'));
332 333
    $account = user_load($account->uid);
    $this->assertTrue($account->status == 1, t('User account was not canceled.'));
334 335 336 337 338

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

340 341 342 343 344 345 346 347 348 349
  /**
   * Attempt invalid account cancellations.
   */
  function testUserCancelInvalid() {
    variable_set('user_cancel_method', 'user_cancel_reassign');

    // Create a user.
    $account = $this->drupalCreateUser(array('cancel account'));
    $this->drupalLogin($account);
    // Load real user object.
350
    $account = user_load($account->uid, TRUE);
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

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

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

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

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

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

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

381 382 383 384 385 386 387
  /**
   * Disable account and keep all content.
   */
  function testUserBlock() {
    variable_set('user_cancel_method', 'user_cancel_block');

    // Create a user.
388 389 390
    $web_user = $this->drupalCreateUser(array('cancel account'));
    $this->drupalLogin($web_user);

391
    // Load real user object.
392
    $account = user_load($web_user->uid, TRUE);
393 394 395 396 397 398 399 400 401 402

    // Attempt to cancel account.
    $this->drupalGet('user/' . $account->uid . '/edit');
    $this->drupalPost(NULL, NULL, t('Cancel account'));
    $this->assertText(t('Are you sure you want to cancel your account?'), t('Confirmation form to cancel account displayed.'));
    $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.'), t('Informs that all content will be remain as is.'));
    $this->assertNoText(t('Select the method to cancel the account above.'), t('Does not allow user to select account cancellation method.'));

    // Confirm account cancellation.
    $timestamp = time();
403

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

    // Confirm account cancellation request.
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
409 410
    $account = user_load($account->uid, TRUE);
    $this->assertTrue($account->status == 0, t('User has been blocked.'));
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425

    // Confirm user is logged out.
    $this->assertNoText($account->name, t('Logged out.'));
  }

  /**
   * Disable account and unpublish all content.
   */
  function testUserBlockUnpublish() {
    variable_set('user_cancel_method', 'user_cancel_block_unpublish');

    // Create a user.
    $account = $this->drupalCreateUser(array('cancel account'));
    $this->drupalLogin($account);
    // Load real user object.
426
    $account = user_load($account->uid, TRUE);
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

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

    // Attempt to cancel account.
    $this->drupalGet('user/' . $account->uid . '/edit');
    $this->drupalPost(NULL, NULL, t('Cancel account'));
    $this->assertText(t('Are you sure you want to cancel your account?'), t('Confirmation form to cancel account displayed.'));
    $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.'), t('Informs that all content will be unpublished.'));

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

    // Confirm account cancellation request.
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
447 448
    $account = user_load($account->uid, TRUE);
    $this->assertTrue($account->status == 0, t('User has been blocked.'));
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

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

    // Confirm user is logged out.
    $this->assertNoText($account->name, t('Logged out.'));
  }

  /**
   * Delete account and anonymize all content.
   */
  function testUserAnonymize() {
    variable_set('user_cancel_method', 'user_cancel_reassign');

    // Create a user.
    $account = $this->drupalCreateUser(array('cancel account'));
    $this->drupalLogin($account);
    // Load real user object.
470
    $account = user_load($account->uid, TRUE);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

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

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

    // Attempt to cancel account.
    $this->drupalGet('user/' . $account->uid . '/edit');
    $this->drupalPost(NULL, NULL, t('Cancel account'));
    $this->assertText(t('Are you sure you want to cancel your account?'), t('Confirmation form to cancel account displayed.'));
    $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')))), t('Informs that all content will be attributed to anonymous account.'));

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

    // Confirm account cancellation request.
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
497
    $this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.'));
498 499 500 501 502

    // Confirm that user's content has been attributed to anonymous user.
    $test_node = node_load($node->nid, NULL, TRUE);
    $this->assertTrue(($test_node->uid == 0 && $test_node->status == 1), t('Node of the user has been attributed to anonymous user.'));
    $test_node = node_load($revision_node->nid, $revision, TRUE);
503
    $this->assertTrue(($test_node->revision_uid == 0 && $test_node->status == 1), t('Node revision of the user has been attributed to anonymous user.'));
504 505 506 507 508 509
    $test_node = node_load($revision_node->nid, NULL, TRUE);
    $this->assertTrue(($test_node->uid != 0 && $test_node->status == 1), t("Current revision of the user's node was not attributed to anonymous user."));

    // Confirm that user is logged out.
    $this->assertNoText($account->name, t('Logged out.'));
  }
510

511 512 513 514 515 516 517 518 519 520
  /**
   * Delete account and remove all content.
   */
  function testUserDelete() {
    variable_set('user_cancel_method', 'user_cancel_delete');

    // Create a user.
    $account = $this->drupalCreateUser(array('cancel account'));
    $this->drupalLogin($account);
    // Load real user object.
521
    $account = user_load($account->uid, TRUE);
522 523 524 525 526 527

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

    // Create comment.
    module_load_include('test', 'comment');
528
    $comment = CommentHelperCase::postComment($node, '', $this->randomName(32), FALSE, TRUE);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
    $this->assertTrue(comment_load($comment->id), t('Comment found.'));

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

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

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

    // Confirm account cancellation request.
    $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
553
    $this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.'));
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

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

    // Confirm that user is logged out.
    $this->assertNoText($account->name, t('Logged out.'));
  }

  /**
   * Create an administrative user and delete another user.
   */
  function testUserCancelByAdmin() {
    variable_set('user_cancel_method', 'user_cancel_reassign');

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

574
    // Create administrative user.
575 576 577
    $admin_user = $this->drupalCreateUser(array('administer users'));
    $this->drupalLogin($admin_user);

578 579 580 581 582
    // Delete regular user.
    $this->drupalGet('user/' . $account->uid . '/edit');
    $this->drupalPost(NULL, NULL, t('Cancel account'));
    $this->assertRaw(t('Are you sure you want to cancel the account %name?', array('%name' => $account->name)), t('Confirmation form to cancel account displayed.'));
    $this->assertText(t('Select the method to cancel the account above.'), t('Allows to select account cancellation method.'));
583 584

    // Confirm deletion.
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
    $this->drupalPost(NULL, NULL, t('Cancel account'));
    $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), t('User deleted.'));
    $this->assertFalse(user_load($account->uid), t('User is not found in the database.'));
  }

  /**
   * Create an administrative user and mass-delete other users.
   */
  function testMassUserCancelByAdmin() {
    variable_set('user_cancel_method', 'user_cancel_reassign');
    // Enable account cancellation notification.
    variable_set('user_mail_status_canceled_notify', TRUE);

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

    // Create some users.
    $users = array();
    for ($i = 0; $i < 3; $i++) {
      $account = $this->drupalCreateUser(array());
      $users[$account->uid] = $account;
    }

    // Cancel user accounts, including own one.
    $edit = array();
    $edit['operation'] = 'cancel';
    foreach ($users as $uid => $account) {
613
      $edit['accounts[' . $uid . ']'] = TRUE;
614
    }
615
    $edit['accounts[' . $admin_user->uid . ']'] = TRUE;
616
    $this->drupalPost('admin/people', $edit, t('Update'));
617 618 619 620 621 622 623 624 625 626
    $this->assertText(t('Are you sure you want to cancel these user accounts?'), t('Confirmation form to cancel accounts displayed.'));
    $this->assertText(t('When cancelling these accounts'), t('Allows to select account cancellation method.'));
    $this->assertText(t('Require e-mail confirmation to cancel account.'), t('Allows to send confirmation mail.'));
    $this->assertText(t('Notify user when account is canceled.'), t('Allows to send notification mail.'));

    // Confirm deletion.
    $this->drupalPost(NULL, NULL, t('Cancel accounts'));
    $status = TRUE;
    foreach ($users as $account) {
      $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->name))) !== FALSE);
627
      $status = $status && !user_load($account->uid, TRUE);
628 629 630 631 632
    }
    $this->assertTrue($status, t('Users deleted and not found in the database.'));

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

638 639 640
class UserPictureTestCase extends DrupalWebTestCase {
  protected $user;
  protected $_directory_test;
641

642
  public static function getInfo() {
643
    return array(
644 645 646
      'name' => 'Upload user picture',
      'description' => 'Assure that dimension check, extension check and image scaling work as designed.',
      'group' => 'User'
647 648
    );
  }
649

650 651 652 653
  function setUp() {
    parent::setUp();
    // Enable user pictures.
    variable_set('user_pictures', 1);
654

655
    $this->user = $this->drupalCreateUser();
656

657
    // Test if directories specified in settings exist in filesystem.
658 659 660
    $file_dir = 'public://';
    $file_check = file_prepare_directory($file_dir, FILE_CREATE_DIRECTORY);
    // TODO: Test public and private methods?
661

662
    $picture_dir = variable_get('user_picture_path', 'pictures');
663
    $picture_path = $file_dir . $picture_dir;
664

665
    $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY);
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
    $this->_directory_test = is_writable($picture_path);
    $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
  }

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

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

  /**
   * Do the test:
   *  GD Toolkit is installed
   *  Picture has invalid dimension
   *
   * results: The image should be uploaded because ImageGDToolkit resizes the picture
   */
  function testWithGDinvalidDimension() {
    if ($this->_directory_test)
      if (image_get_toolkit()) {
        $this->drupalLogin($this->user);

        $image = current($this->drupalGetTestFiles('image'));
692
        $info = image_get_info($image->uri);
693

694
        // Set new variables: invalid dimensions, valid filesize (0 = no limit).
695 696
        $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
        variable_set('user_picture_dimensions', $test_dim);
697
        variable_set('user_picture_file_size', 0);
698 699

        $pic_path = $this->saveUserPicture($image);
700 701 702 703
        // Check that the image was resized and is being displayed on the
        // user's profile page.
        $text = t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $test_dim));
        $this->assertRaw($text, t('Image was resized.'));
704
        $alt = t("@user's picture", array('@user' => $this->user->name));
705 706
        $style = variable_get('user_picture_style', '');
        $this->assertRaw(image_style_url($style, $pic_path), t("Image is displayed in user's edit page"));
707

708 709
        // Check if file is located in proper directory.
        $this->assertTrue(is_file($pic_path), t("File is located in proper directory"));
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
      }
  }

  /**
   * Do the test:
   *  GD Toolkit is installed
   *  Picture has invalid size
   *
   * results: The image should be uploaded because ImageGDToolkit resizes the picture
   */
  function testWithGDinvalidSize() {
    if ($this->_directory_test)
      if (image_get_toolkit()) {

        $this->drupalLogin($this->user);

726 727 728
        // Images are sorted first by size then by name. We need an image
        // bigger than 1 KB so we'll grab the last one.
        $image = end($this->drupalGetTestFiles('image'));
729
        $info = image_get_info($image->uri);
730

731
        // Set new variables: valid dimensions, invalid filesize.
732
        $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
733
        $test_size = 1;
734 735 736
        variable_set('user_picture_dimensions', $test_dim);
        variable_set('user_picture_file_size', $test_size);

737
        $pic_path = $this->saveUserPicture($image);
738

739
        // Test that the upload failed and that the correct reason was cited.
740
        $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
741
        $this->assertRaw($text, t('Upload failed.'));
742
        $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)));
743
        $this->assertRaw($text, t('File size cited as reason for failure.'));
744

745 746
        // Check if file is not uploaded.
        $this->assertFalse(is_file($pic_path), t('File was not uploaded.'));
747 748 749 750 751 752 753 754 755 756
      }
  }

  /**
   * Do the test:
   *  GD Toolkit is not installed
   *  Picture has invalid size
   *
   * results: The image shouldn't be uploaded
   */
757
  function testWithoutGDinvalidDimension() {
758 759 760 761 762 763
    if ($this->_directory_test)
      if (!image_get_toolkit()) {

        $this->drupalLogin($this->user);

        $image = current($this->drupalGetTestFiles('image'));
764
        $info = image_get_info($image->uri);
765

766
        // Set new variables: invalid dimensions, valid filesize (0 = no limit).
767 768
        $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
        variable_set('user_picture_dimensions', $test_dim);
769
        variable_set('user_picture_file_size', 0);
770 771 772

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

773
        // Test that the upload failed and that the correct reason was cited.
774
        $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
775 776 777 778 779 780
        $this->assertRaw($text, t('Upload failed.'));
        $text = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $test_dim));
        $this->assertRaw($text, t('Checking response on invalid image (dimensions).'));

        // Check if file is not uploaded.
        $this->assertFalse(is_file($pic_path), t('File was not uploaded.'));
781
      }
782
  }
783 784 785 786 787 788 789 790

  /**
   * Do the test:
   *  GD Toolkit is not installed
   *  Picture has invalid size
   *
   * results: The image shouldn't be uploaded
   */
791
  function testWithoutGDinvalidSize() {
792 793 794 795 796
    if ($this->_directory_test)
      if (!image_get_toolkit()) {
        $this->drupalLogin($this->user);

        $image = current($this->drupalGetTestFiles('image'));
797
        $info = image_get_info($image->uri);
798 799

        // Set new variables: valid dimensions, invalid filesize.
800
        $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
801
        $test_size = 1;
802 803 804 805 806
        variable_set('user_picture_dimensions', $test_dim);
        variable_set('user_picture_file_size', $test_size);

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

807
        // Test that the upload failed and that the correct reason was cited.
808
        $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
809
        $this->assertRaw($text, t('Upload failed.'));
810
        $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)));
811 812 813 814
        $this->assertRaw($text, t('File size cited as reason for failure.'));

        // Check if file is not uploaded.
        $this->assertFalse(is_file($pic_path), t('File was not uploaded.'));
815 816 817 818 819 820 821 822 823 824 825 826
      }
  }

  /**
   * Do the test:
   *  Picture is valid (proper size and dimension)
   *
   * results: The image should be uploaded
   */
  function testPictureIsValid() {
    if ($this->_directory_test) {
      $this->drupalLogin($this->user);
827

828
      $image = current($this->drupalGetTestFiles('image'));
829
      $info = image_get_info($image->uri);
830

831
      // Set new variables: valid dimensions, valid filesize (0 = no limit).
832 833
      $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
      variable_set('user_picture_dimensions', $test_dim);
834
      variable_set('user_picture_file_size', 0);
835 836 837

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

838 839
      // Check if image is displayed in user's profile page.
      $this->drupalGet('user');
840
      $this->assertRaw(file_uri_target($pic_path), t("Image is displayed in user's profile page"));
841

842
      // Check if file is located in proper directory.
843 844 845
      $this->assertTrue(is_file($pic_path), t('File is located in proper directory'));
    }
  }
846

847
  function saveUserPicture($image) {
848
    $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
849
    $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
850

851
    $img_info    = image_get_info($image->uri);
852
    $picture_dir = variable_get('user_picture_path', 'pictures');
853
    $pic_path    = 'public://' . $picture_dir . '/picture-' . $this->user->uid . '.' . $img_info['extension'];
854 855 856 857 858

    return $pic_path;
  }
}

859 860 861 862 863

class UserPermissionsTestCase extends DrupalWebTestCase {
  protected $admin_user;
  protected $rid;

864
  public static function getInfo() {
865
    return array(
866 867 868
      'name' => 'Role permissions',
      'description' => 'Verify that role permissions can be added and removed via the permissions page.',
      'group' => 'User'
869 870 871 872 873 874
    );
  }

  function setUp() {
    parent::setUp();

875
    $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer users'));
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891

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

  /**
   * Change user permissions and check user_access().
   */
  function testUserPermissionChanges() {
    $this->drupalLogin($this->admin_user);
    $rid = $this->rid;
    $account = $this->admin_user;

    // Add a permission.
892
    $this->assertFalse(user_access('administer nodes', $account), t('User does not have "administer nodes" permission.'));
893 894
    $edit = array();
    $edit[$rid . '[administer nodes]'] = TRUE;
895
    $this->drupalPost('admin/config/people/permissions', $edit, t('Save permissions'));
896
    $this->assertText(t('The changes have been saved.'), t('Successful save message displayed.'));
897 898 899
    drupal_static_reset('user_access');
    drupal_static_reset('user_role_permissions');
    $this->assertTrue(user_access('administer nodes', $account), t('User now has "administer nodes" permission.'));
900 901

    // Remove a permission.
902
    $this->assertTrue(user_access('access user profiles', $account), t('User has "access user profiles" permission.'));
903 904
    $edit = array();
    $edit[$rid . '[access user profiles]'] = FALSE;
905
    $this->drupalPost('admin/config/people/permissions', $edit, t('Save permissions'));
906
    $this->assertText(t('The changes have been saved.'), t('Successful save message displayed.'));
907 908 909
    drupal_static_reset('user_access');
    drupal_static_reset('user_role_permissions');
    $this->assertFalse(user_access('access user profiles', $account), t('User no longer has "access user profiles" permission.'));
910 911
  }

912 913 914 915 916
  /**
   * Test assigning of permissions for the administrator role.
   */
  function testAdministratorRole() {
    $this->drupalLogin($this->admin_user);
917
    $this->drupalGet('admin/config/people/accounts');
918 919 920 921

    // Set the user's role to be the administrator role.
    $edit = array();
    $edit['user_admin_role'] = $this->rid;
922
    $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
923 924 925 926 927

    // Enable aggregator module and ensure the 'administer news feeds'
    // permission is assigned by default.
    $edit = array();
    $edit['modules[Core][aggregator][enable]'] = TRUE;
928
    $this->drupalPost('admin/config/modules', $edit, t('Save configuration'));
929
    $this->assertTrue(user_access('administer news feeds', $this->admin_user), t('The permission was automatically assigned to the administrator role'));
930
  }
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955

  /**
   * Verify proper permission changes by user_role_change_permissions().
   */
  function testUserRoleChangePermissions() {
    $rid = $this->rid;
    $account = $this->admin_user;

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

    // Change permissions.
    $permissions = array(
      'administer nodes' => 1,
      'access user profiles' => 0,
    );
    user_role_change_permissions($rid, $permissions);

    // Verify proper permission changes.
    $this->assertTrue(user_access('administer nodes', $account), t('User now has "administer nodes" permission.'));
    $this->assertFalse(user_access('access user profiles', $account), t('User no longer has "access user profiles" permission.'));
    $this->assertTrue(user_access('administer site configuration', $account), t('User still has "administer site configuration" permission.'));
  }
956
}
957 958

class UserAdminTestCase extends DrupalWebTestCase {
959
  public static function getInfo() {
960
    return array(
961 962 963
      'name' => 'User administration',
      'description' => 'Test user administration page functionality.',
      'group' => 'User'
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
    );
  }

  /**
   * Registers a user and deletes it.
   */
  function testUserAdmin() {

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

    // Create admin user to delete registered user.
    $admin_user = $this->drupalCreateUser(array('administer users'));
    $this->drupalLogin($admin_user);
979
    $this->drupalGet('admin/people');
980 981 982 983 984
    $this->assertText($user_a->name, t('Found user A on admin users page'));
    $this->assertText($user_b->name, t('Found user B on admin users page'));
    $this->assertText($user_c->name, t('Found user C on admin users page'));
    $this->assertText($admin_user->name, t('Found Admin user on admin users page'));

985
    // Filter the users by permission 'administer taxonomy'.
986 987 988
    $edit = array();
    $edit['filter'] = 'permission';
    $edit['permission'] = 'administer taxonomy';
989
    $this->drupalPost('admin/people', $edit, t('Filter'));
990 991 992 993 994 995 996

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

    // Test blocking of a user.
997
    $account = user_load($user_b->uid);
998 999 1000
    $this->assertEqual($account->status, 1, 'User B not blocked');
    $edit = array();
    $edit['operation'] = 'block';
1001
    $edit['accounts[' . $account->uid . ']'] = TRUE;
1002
    $this->drupalPost('admin/people', $edit, t('Update'));
1003
    $account = user_load($user_b->uid, TRUE);
1004 1005 1006
    $this->assertEqual($account->status, 0, 'User B blocked');
  }
}
1007

1008 1009 1010 1011
/**
 * Tests for user-configurable time zones.
 */
class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
1012
  public static function getInfo() {
1013
    return array(
1014 1015 1016
      'name' => 'User time zones',
      'description' => 'Set a user time zone and verify that dates are displayed in local time.',
      'group' => 'User',
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    );
  }

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

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

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

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

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

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

1068 1069 1070 1071
/**
 * Test user autocompletion.
 */
class UserAutocompleteTestCase extends DrupalWebTestCase {
1072
  public static function getInfo() {
1073
    return array(
1074 1075 1076
      'name' => 'User autocompletion',
      'description' => 'Test user autocompletion functionality.',
      'group' => 'User'
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
    );
  }

  function setUp() {
    parent::setUp();

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

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

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

    // Using first letter of the user's name, make sure the user's full name is in the results.
    $this->assertRaw($this->unprivileged_user->name, t('User name found in autocompletion results.'));
  }
}
1107 1108 1109 1110 1111

/**
 * Test user blocks.
 */
class UserBlocksUnitTests extends DrupalWebTestCase {
1112
  public static function getInfo() {
1113
    return array(
1114 1115 1116
      'name' => 'User blocks',
      'description' => 'Test user blocks.',
      'group' => 'User'
1117 1118 1119
    );
  }

1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
  /**
   * Test the user login block.
   */
  function testUserLoginBlock() {
    // Create a user with some permission that anonymous users lack.
    $user = $this->drupalCreateUser(array('administer permissions'));

    // Log in using the block.
    $edit = array();
    $edit['name'] = $user->name;
    $edit['pass'] = $user->pass_raw;
1131
    $this->drupalPost('admin/config/people/permissions', $edit, t('Log in'));
1132
    $this->assertNoText(t('User login'), t('Logged in.'));
1133 1134 1135 1136 1137

    // Check that we are still on the same page.
    $this->assertPattern('!<title.*?' . t('Permissions') . '.*?</title>!', t('Still on the same page after login for access denied page'));

    // Now, log out and repeat with a non-403 page.
1138
    $this->drupalLogout();
1139
    $this->drupalPost('filter/tips', $edit, t('Log in'));
1140
    $this->assertNoText(t('User login'), t('Logged in.'));
1141 1142 1143
    $this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', t('Still on the same page after login for allowed page'));
  }

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
  /**
   * Test the Who's Online block.
   */
  function testWhosOnlineBlock() {
    // Generate users and make sure there are no current user sessions.
    $user1 = $this->drupalCreateUser(array());
    $user2 = $this->drupalCreateUser(array());
    $user3 = $this->drupalCreateUser(array());
    $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions}")->fetchField(), 0, t('Sessions table is empty.'));

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

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

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

    // Insert two anonymous user sessions.
    $this->insertSession();
    $this->insertSession();

    // Test block output.
1170
    $block = user_block_view('online');
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
    $this->drupalSetContent($block['content']);
    $this->assertRaw(t('%members and %visitors', array('%members' => '2 users', '%visitors' => '2 guests')), t('Correct number of online users (2 users and 2 guests).'));
    $this->assertText($user1->name, t('Active user 1 found in online list.'));
    $this->assertText($user2->name, t('Active user 2 found in online list.'));
    $this->assertNoText($user3->name, t("Inactive user not found in online list."));
    $this->assertTrue(strpos($this->drupalGetContent(), $user1->name) > strpos($this->drupalGetContent(), $user2->name), t('Online users are ordered correctly.'));
  }

  /**
   * Insert a user session into the {sessions} table. This function is used
   * since we cannot log in more than one user at the same time in tests.
   */
  private function insertSession(array $fields = array()) {
    $fields += array(
      'uid' => 0,
1186
      'sid' => md5(uniqid(mt_rand(), TRUE)),
1187 1188 1189 1190 1191 1192 1193 1194
      'timestamp' => REQUEST_TIME,
    );
    db_insert('sessions')
      ->fields($fields)
      ->execute();
    $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, t('Session record inserted.'));
  }
}
1195 1196 1197 1198 1199 1200

/**
 * Test case to test user_save() behaviour.
 */
class UserSaveTestCase extends DrupalWebTestCase {

1201
  public static function getInfo() {
1202
    return array(
1203 1204 1205
      'name' => 'User save test',
      'description' => 'Test user_save() for arbitrary new uid.',
      'group' => 'User',
1206 1207 1208 1209 1210 1211 1212 1213
    );
  }

  /**
   * Test creating a user with arbitrary uid.
   */
  function testUserImport() {
    // User ID must be a number that is not in the database.
1214
    $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField();
1215
    $test_uid = $max_uid + mt_rand(1000, 1000000);
1216
    $test_name = $this->randomName();
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226

    // Create the base user, based on drupalCreateUser().
    $user = array(
      'name' => $test_name,
      'uid' => $test_uid,
      'mail' => $test_name . '@example.com',
      'is_new' => TRUE,
      'pass' => user_password(),
      'status' => 1,
    );
1227
    $user_by_return = user_save(drupal_anonymous_user(), $user);
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
    $this->assertTrue($user_by_return, t('Loading user by return of user_save().'));

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

    $user_by_name = user_load_by_name($test_name);
    $this->assertTrue($user_by_name, t('Loading user by name.'));
  }
}
1238

1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
/**
 * Test the create user administration page.
 */
class UserCreateTestCase extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'User create',
      'description' => 'Test the creat user administration page.',
      'group' => 'User',
    );
  }

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

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

      if ($notify) {
        $this->assertText(t('Password and further instructions have been e-mailed to the new user @name.', array('@name' => $edit['name'])), 'User created');
        $this->assertEqual(count($this->drupalGetMails()), 1, 'Notification e-mail sent');
      }
      else {
        $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created');
        $this->assertEqual(count($this->drupalGetMails()), 0, 'Notification e-mail not sent');
      }

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

1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
/**
 * Test case to test user_save() behaviour.
 */
class UserEditTestCase extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'User edit',
      'description' => 'Test user edit page.',
      'group' => 'User',
    );
  }

  /**
   * Test user edit page.
   */
  function testUserEdit() {
    // Test user edit functionality with user pictures disabled.
    variable_set('user_pictures', 0);
    $user1 = $this->drupalCreateUser(array('change own username'));
    $user2 = $this->drupalCreateUser(array());
    $this->drupalLogin($user1);

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

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