cms/drupal/modules/user/user.test
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     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    * Retrieves password reset email and extracts the login link.
       
   470    */
       
   471   public function getResetURL() {
       
   472     // Assume the most recent email.
       
   473     $_emails = $this->drupalGetMails();
       
   474     $email = end($_emails);
       
   475     $urls = array();
       
   476     preg_match('#.+user/reset/.+#', $email['body'], $urls);
       
   477 
       
   478     return $urls[0];
       
   479   }
       
   480 
       
   481   /**
       
   482    * Tests password reset functionality.
       
   483    */
       
   484   function testUserPasswordReset() {
       
   485     // Create a user.
       
   486     $account = $this->drupalCreateUser();
       
   487     $this->drupalLogin($account);
       
   488     $this->drupalLogout();
       
   489     // Attempt to reset password.
       
   490     $edit = array('name' => $account->name);
       
   491     $this->drupalPost('user/password', $edit, t('E-mail new password'));
       
   492     // Confirm the password reset.
       
   493     $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.');
       
   494 
       
   495     // Create an image field to enable an Ajax request on the user profile page.
       
   496     $field = array(
       
   497       'field_name' => 'field_avatar',
       
   498       'type' => 'image',
       
   499       'settings' => array(),
       
   500       'cardinality' => 1,
       
   501     );
       
   502     field_create_field($field);
       
   503 
       
   504     $instance = array(
       
   505       'field_name' => $field['field_name'],
       
   506       'entity_type' => 'user',
       
   507       'label' => 'Avatar',
       
   508       'bundle' => 'user',
       
   509       'required' => FALSE,
       
   510       'settings' => array(),
       
   511       'widget' => array(
       
   512         'type' => 'image_image',
       
   513         'settings' => array(),
       
   514       ),
       
   515     );
       
   516     field_create_instance($instance);
       
   517 
       
   518     $resetURL = $this->getResetURL();
       
   519     $this->drupalGet($resetURL);
       
   520 
       
   521     // Check successful login.
       
   522     $this->drupalPost(NULL, NULL, t('Log in'));
       
   523 
       
   524     // Make sure the Ajax request from uploading a file does not invalidate the
       
   525     // reset token.
       
   526     $image = current($this->drupalGetTestFiles('image'));
       
   527     $edit = array(
       
   528       'files[field_avatar_und_0]' => drupal_realpath($image->uri),
       
   529     );
       
   530     $this->drupalPostAJAX(NULL, $edit, 'field_avatar_und_0_upload_button');
       
   531 
       
   532     // Change the forgotten password.
       
   533     $password = user_password();
       
   534     $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password);
       
   535     $this->drupalPost(NULL, $edit, t('Save'));
       
   536     $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.');
       
   537   }
       
   538 
       
   539   /**
       
   540    * Test user password reset while logged in.
       
   541    */
       
   542   function testUserPasswordResetLoggedIn() {
       
   543     $account = $this->drupalCreateUser();
       
   544     $this->drupalLogin($account);
       
   545     // Make sure the test account has a valid password.
       
   546     user_save($account, array('pass' => user_password()));
       
   547 
       
   548     // Generate one time login link.
       
   549     $reset_url = user_pass_reset_url($account);
       
   550     $this->drupalGet($reset_url);
       
   551 
       
   552     $this->assertText('Reset password');
       
   553     $this->drupalPost(NULL, NULL, t('Log in'));
       
   554 
       
   555     $this->assertText('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.');
       
   556 
       
   557     $pass = user_password();
       
   558     $edit = array(
       
   559       'pass[pass1]' => $pass,
       
   560       'pass[pass2]' => $pass,
       
   561     );
       
   562     $this->drupalPost(NULL, $edit, t('Save'));
       
   563 
       
   564     $this->assertText('The changes have been saved.');
       
   565   }
       
   566 
       
   567   /**
       
   568    * Attempts login using an expired password reset link.
       
   569    */
       
   570   function testUserPasswordResetExpired() {
       
   571     // Set password reset timeout variable to 43200 seconds = 12 hours.
       
   572     $timeout = 43200;
       
   573     variable_set('user_password_reset_timeout', $timeout);
       
   574 
       
   575     // Create a user.
       
   576     $account = $this->drupalCreateUser();
       
   577     $this->drupalLogin($account);
       
   578     // Load real user object.
       
   579     $account = user_load($account->uid, TRUE);
       
   580     $this->drupalLogout();
       
   581 
       
   582     // To attempt an expired password reset, create a password reset link as if
       
   583     // its request time was 60 seconds older than the allowed limit of timeout.
       
   584     $bogus_timestamp = REQUEST_TIME - variable_get('user_password_reset_timeout', 86400) - 60;
       
   585     $this->drupalGet("user/reset/$account->uid/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid));
       
   586     $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.');
       
   587   }
       
   588 
       
   589   /**
       
   590    * Prefill the text box on incorrect login via link to password reset page.
       
   591    */
       
   592   function testUserPasswordTextboxFilled() {
       
   593     $this->drupalGet('user/login');
       
   594     $edit = array(
       
   595       'name' => $this->randomName(),
       
   596       'pass' => $this->randomName(),
       
   597     );
       
   598     $this->drupalPost('user', $edit, t('Log in'));
       
   599     $this->assertRaw(t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>',
       
   600       array('@password' => url('user/password', array('query' => array('name' => $edit['name']))))));
       
   601     unset($edit['pass']);
       
   602     $this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
       
   603     $this->assertFieldByName('name', $edit['name'], 'User name found.');
       
   604   }
       
   605 
       
   606   /**
       
   607    * Make sure that users cannot forge password reset URLs of other users.
       
   608    */
       
   609   function testResetImpersonation() {
       
   610     // Make sure user 1 has a valid password, so it does not interfere with the
       
   611     // test user accounts that are created below.
       
   612     $account = user_load(1);
       
   613     user_save($account, array('pass' => user_password()));
       
   614 
       
   615     // Create two identical user accounts except for the user name. They must
       
   616     // have the same empty password, so we can't use $this->drupalCreateUser().
       
   617     $edit = array();
       
   618     $edit['name'] = $this->randomName();
       
   619     $edit['mail'] = $edit['name'] . '@example.com';
       
   620     $edit['status'] = 1;
       
   621 
       
   622     $user1 = user_save(drupal_anonymous_user(), $edit);
       
   623 
       
   624     $edit['name'] = $this->randomName();
       
   625     $user2 = user_save(drupal_anonymous_user(), $edit);
       
   626 
       
   627     // The password reset URL must not be valid for the second user when only
       
   628     // the user ID is changed in the URL.
       
   629     $reset_url = user_pass_reset_url($user1);
       
   630     $attack_reset_url = str_replace("user/reset/$user1->uid", "user/reset/$user2->uid", $reset_url);
       
   631     $this->drupalGet($attack_reset_url);
       
   632     $this->assertNoText($user2->name, 'The invalid password reset page does not show the user name.');
       
   633     $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.');
       
   634     $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
       
   635 
       
   636     // When legacy code calls user_pass_rehash() without providing the $uid
       
   637     // parameter, neither password reset URL should be valid since it is
       
   638     // impossible for the system to determine which user account the token was
       
   639     // intended for.
       
   640     $timestamp = REQUEST_TIME;
       
   641     // Pass an explicit NULL for the $uid parameter of user_pass_rehash()
       
   642     // rather than not passing it at all, to avoid triggering PHP warnings in
       
   643     // the test.
       
   644     $reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL);
       
   645     $reset_url = url("user/reset/$user1->uid/$timestamp/$reset_url_token", array('absolute' => TRUE));
       
   646     $this->drupalGet($reset_url);
       
   647     $this->assertNoText($user1->name, 'The invalid password reset page does not show the user name.');
       
   648     $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.');
       
   649     $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
       
   650     $attack_reset_url = str_replace("user/reset/$user1->uid", "user/reset/$user2->uid", $reset_url);
       
   651     $this->drupalGet($attack_reset_url);
       
   652     $this->assertNoText($user2->name, 'The invalid password reset page does not show the user name.');
       
   653     $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.');
       
   654     $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
       
   655 
       
   656     // To verify that user_pass_rehash() never returns a valid result in the
       
   657     // above situation (even if legacy code also called it to attempt to
       
   658     // validate the token, rather than just to generate the URL), check that a
       
   659     // second call with the same parameters produces a different result.
       
   660     $new_reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL);
       
   661     $this->assertNotEqual($reset_url_token, $new_reset_url_token);
       
   662 
       
   663     // However, when the duplicate account is removed, the password reset URL
       
   664     // should be valid.
       
   665     user_delete($user2->uid);
       
   666     $reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL);
       
   667     $reset_url = url("user/reset/$user1->uid/$timestamp/$reset_url_token", array('absolute' => TRUE));
       
   668     $this->drupalGet($reset_url);
       
   669     $this->assertText($user1->name, 'The valid password reset page shows the user name.');
       
   670     $this->assertUrl($reset_url, array(), 'The user remains on the password reset login page.');
       
   671     $this->assertNoText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
       
   672   }
       
   673 
       
   674 }
       
   675 
       
   676 /**
       
   677  * Test cancelling a user.
       
   678  */
       
   679 class UserCancelTestCase extends DrupalWebTestCase {
       
   680   public static function getInfo() {
       
   681     return array(
       
   682       'name' => 'Cancel account',
       
   683       'description' => 'Ensure that account cancellation methods work as expected.',
       
   684       'group' => 'User',
       
   685     );
       
   686   }
       
   687 
       
   688   function setUp() {
       
   689     parent::setUp('comment');
       
   690   }
       
   691 
       
   692   /**
       
   693    * Attempt to cancel account without permission.
       
   694    */
       
   695   function testUserCancelWithoutPermission() {
       
   696     variable_set('user_cancel_method', 'user_cancel_reassign');
       
   697 
       
   698     // Create a user.
       
   699     $account = $this->drupalCreateUser(array());
       
   700     $this->drupalLogin($account);
       
   701     // Load real user object.
       
   702     $account = user_load($account->uid, TRUE);
       
   703 
       
   704     // Create a node.
       
   705     $node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   706 
       
   707     // Attempt to cancel account.
       
   708     $this->drupalGet('user/' . $account->uid . '/edit');
       
   709     $this->assertNoRaw(t('Cancel account'), 'No cancel account button displayed.');
       
   710 
       
   711     // Attempt bogus account cancellation request confirmation.
       
   712     $timestamp = $account->login;
       
   713     $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid));
       
   714     $this->assertResponse(403, 'Bogus cancelling request rejected.');
       
   715     $account = user_load($account->uid);
       
   716     $this->assertTrue($account->status == 1, 'User account was not canceled.');
       
   717 
       
   718     // Confirm user's content has not been altered.
       
   719     $test_node = node_load($node->nid, NULL, TRUE);
       
   720     $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
       
   721   }
       
   722 
       
   723   /**
       
   724    * Tests that user account for uid 1 cannot be cancelled.
       
   725    *
       
   726    * This should never be possible, or the site owner would become unable to
       
   727    * administer the site.
       
   728    */
       
   729   function testUserCancelUid1() {
       
   730     // Update uid 1's name and password to we know it.
       
   731     $password = user_password();
       
   732     require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
       
   733     $account = array(
       
   734       'name' => 'user1',
       
   735       'pass' => user_hash_password(trim($password)),
       
   736     );
       
   737     // We cannot use user_save() here or the password would be hashed again.
       
   738     db_update('users')
       
   739       ->fields($account)
       
   740       ->condition('uid', 1)
       
   741       ->execute();
       
   742 
       
   743     // Reload and log in uid 1.
       
   744     $user1 = user_load(1, TRUE);
       
   745     $user1->pass_raw = $password;
       
   746 
       
   747     // Try to cancel uid 1's account with a different user.
       
   748     $this->admin_user = $this->drupalCreateUser(array('administer users'));
       
   749     $this->drupalLogin($this->admin_user);
       
   750     $edit = array(
       
   751       'operation' => 'cancel',
       
   752       'accounts[1]' => TRUE,
       
   753     );
       
   754     $this->drupalPost('admin/people', $edit, t('Update'));
       
   755 
       
   756     // Verify that uid 1's account was not cancelled.
       
   757     $user1 = user_load(1, TRUE);
       
   758     $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
       
   759   }
       
   760 
       
   761   /**
       
   762    * Attempt invalid account cancellations.
       
   763    */
       
   764   function testUserCancelInvalid() {
       
   765     variable_set('user_cancel_method', 'user_cancel_reassign');
       
   766 
       
   767     // Create a user.
       
   768     $account = $this->drupalCreateUser(array('cancel account'));
       
   769     $this->drupalLogin($account);
       
   770     // Load real user object.
       
   771     $account = user_load($account->uid, TRUE);
       
   772 
       
   773     // Create a node.
       
   774     $node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   775 
       
   776     // Attempt to cancel account.
       
   777     $this->drupalPost('user/' . $account->uid . '/edit', NULL, t('Cancel account'));
       
   778 
       
   779     // Confirm account cancellation.
       
   780     $timestamp = time();
       
   781     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   782     $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
       
   783 
       
   784     // Attempt bogus account cancellation request confirmation.
       
   785     $bogus_timestamp = $timestamp + 60;
       
   786     $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid));
       
   787     $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.');
       
   788     $account = user_load($account->uid);
       
   789     $this->assertTrue($account->status == 1, 'User account was not canceled.');
       
   790 
       
   791     // Attempt expired account cancellation request confirmation.
       
   792     $bogus_timestamp = $timestamp - 86400 - 60;
       
   793     $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid));
       
   794     $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.');
       
   795     $accounts = user_load_multiple(array($account->uid), array('status' => 1));
       
   796     $this->assertTrue(reset($accounts), 'User account was not canceled.');
       
   797 
       
   798     // Confirm user's content has not been altered.
       
   799     $test_node = node_load($node->nid, NULL, TRUE);
       
   800     $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
       
   801   }
       
   802 
       
   803   /**
       
   804    * Disable account and keep all content.
       
   805    */
       
   806   function testUserBlock() {
       
   807     variable_set('user_cancel_method', 'user_cancel_block');
       
   808 
       
   809     // Create a user.
       
   810     $web_user = $this->drupalCreateUser(array('cancel account'));
       
   811     $this->drupalLogin($web_user);
       
   812 
       
   813     // Load real user object.
       
   814     $account = user_load($web_user->uid, TRUE);
       
   815 
       
   816     // Attempt to cancel account.
       
   817     $this->drupalGet('user/' . $account->uid . '/edit');
       
   818     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   819     $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
       
   820     $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.');
       
   821     $this->assertNoText(t('Select the method to cancel the account above.'), 'Does not allow user to select account cancellation method.');
       
   822 
       
   823     // Confirm account cancellation.
       
   824     $timestamp = time();
       
   825 
       
   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, $account->uid));
       
   831     $account = user_load($account->uid, TRUE);
       
   832     $this->assertTrue($account->status == 0, 'User has been blocked.');
       
   833 
       
   834     // Confirm that the confirmation message made it through to the end user.
       
   835     $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
       
   836   }
       
   837 
       
   838   /**
       
   839    * Disable account and unpublish all content.
       
   840    */
       
   841   function testUserBlockUnpublish() {
       
   842     variable_set('user_cancel_method', 'user_cancel_block_unpublish');
       
   843 
       
   844     // Create a user.
       
   845     $account = $this->drupalCreateUser(array('cancel account'));
       
   846     $this->drupalLogin($account);
       
   847     // Load real user object.
       
   848     $account = user_load($account->uid, TRUE);
       
   849 
       
   850     // Create a node with two revisions.
       
   851     $node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   852     $settings = get_object_vars($node);
       
   853     $settings['revision'] = 1;
       
   854     $node = $this->drupalCreateNode($settings);
       
   855 
       
   856     // Attempt to cancel account.
       
   857     $this->drupalGet('user/' . $account->uid . '/edit');
       
   858     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   859     $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
       
   860     $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.');
       
   861 
       
   862     // Confirm account cancellation.
       
   863     $timestamp = time();
       
   864     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   865     $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
       
   866 
       
   867     // Confirm account cancellation request.
       
   868     $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid));
       
   869     $account = user_load($account->uid, TRUE);
       
   870     $this->assertTrue($account->status == 0, 'User has been blocked.');
       
   871 
       
   872     // Confirm user's content has been unpublished.
       
   873     $test_node = node_load($node->nid, NULL, TRUE);
       
   874     $this->assertTrue($test_node->status == 0, 'Node of the user has been unpublished.');
       
   875     $test_node = node_load($node->nid, $node->vid, TRUE);
       
   876     $this->assertTrue($test_node->status == 0, 'Node revision of the user has been unpublished.');
       
   877 
       
   878     // Confirm that the confirmation message made it through to the end user.
       
   879     $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
       
   880   }
       
   881 
       
   882   /**
       
   883    * Delete account and anonymize all content.
       
   884    */
       
   885   function testUserAnonymize() {
       
   886     variable_set('user_cancel_method', 'user_cancel_reassign');
       
   887 
       
   888     // Create a user.
       
   889     $account = $this->drupalCreateUser(array('cancel account'));
       
   890     $this->drupalLogin($account);
       
   891     // Load real user object.
       
   892     $account = user_load($account->uid, TRUE);
       
   893 
       
   894     // Create a simple node.
       
   895     $node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   896 
       
   897     // Create a node with two revisions, the initial one belonging to the
       
   898     // cancelling user.
       
   899     $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   900     $revision = $revision_node->vid;
       
   901     $settings = get_object_vars($revision_node);
       
   902     $settings['revision'] = 1;
       
   903     $settings['uid'] = 1; // Set new/current revision to someone else.
       
   904     $revision_node = $this->drupalCreateNode($settings);
       
   905 
       
   906     // Attempt to cancel account.
       
   907     $this->drupalGet('user/' . $account->uid . '/edit');
       
   908     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   909     $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
       
   910     $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.');
       
   911 
       
   912     // Confirm account cancellation.
       
   913     $timestamp = time();
       
   914     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   915     $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
       
   916 
       
   917     // Confirm account cancellation request.
       
   918     $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid));
       
   919     $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
       
   920 
       
   921     // Confirm that user's content has been attributed to anonymous user.
       
   922     $test_node = node_load($node->nid, NULL, TRUE);
       
   923     $this->assertTrue(($test_node->uid == 0 && $test_node->status == 1), 'Node of the user has been attributed to anonymous user.');
       
   924     $test_node = node_load($revision_node->nid, $revision, TRUE);
       
   925     $this->assertTrue(($test_node->revision_uid == 0 && $test_node->status == 1), 'Node revision of the user has been attributed to anonymous user.');
       
   926     $test_node = node_load($revision_node->nid, NULL, TRUE);
       
   927     $this->assertTrue(($test_node->uid != 0 && $test_node->status == 1), "Current revision of the user's node was not attributed to anonymous user.");
       
   928 
       
   929     // Confirm that the confirmation message made it through to the end user.
       
   930     $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
       
   931   }
       
   932 
       
   933   /**
       
   934    * Delete account and remove all content.
       
   935    */
       
   936   function testUserDelete() {
       
   937     variable_set('user_cancel_method', 'user_cancel_delete');
       
   938 
       
   939     // Create a user.
       
   940     $account = $this->drupalCreateUser(array('cancel account', 'post comments', 'skip comment approval'));
       
   941     $this->drupalLogin($account);
       
   942     // Load real user object.
       
   943     $account = user_load($account->uid, TRUE);
       
   944 
       
   945     // Create a simple node.
       
   946     $node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   947 
       
   948     // Create comment.
       
   949     $langcode = LANGUAGE_NONE;
       
   950     $edit = array();
       
   951     $edit['subject'] = $this->randomName(8);
       
   952     $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
       
   953 
       
   954     $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
       
   955     $this->drupalPost(NULL, array(), t('Save'));
       
   956     $this->assertText(t('Your comment has been posted.'));
       
   957     $comments = comment_load_multiple(array(), array('subject' => $edit['subject']));
       
   958     $comment = reset($comments);
       
   959     $this->assertTrue($comment->cid, 'Comment found.');
       
   960 
       
   961     // Create a node with two revisions, the initial one belonging to the
       
   962     // cancelling user.
       
   963     $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
       
   964     $revision = $revision_node->vid;
       
   965     $settings = get_object_vars($revision_node);
       
   966     $settings['revision'] = 1;
       
   967     $settings['uid'] = 1; // Set new/current revision to someone else.
       
   968     $revision_node = $this->drupalCreateNode($settings);
       
   969 
       
   970     // Attempt to cancel account.
       
   971     $this->drupalGet('user/' . $account->uid . '/edit');
       
   972     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   973     $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
       
   974     $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.');
       
   975 
       
   976     // Confirm account cancellation.
       
   977     $timestamp = time();
       
   978     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
   979     $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
       
   980 
       
   981     // Confirm account cancellation request.
       
   982     $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid));
       
   983     $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
       
   984 
       
   985     // Confirm that user's content has been deleted.
       
   986     $this->assertFalse(node_load($node->nid, NULL, TRUE), 'Node of the user has been deleted.');
       
   987     $this->assertFalse(node_load($node->nid, $revision, TRUE), 'Node revision of the user has been deleted.');
       
   988     $this->assertTrue(node_load($revision_node->nid, NULL, TRUE), "Current revision of the user's node was not deleted.");
       
   989     $this->assertFalse(comment_load($comment->cid), 'Comment of the user has been deleted.');
       
   990 
       
   991     // Confirm that the confirmation message made it through to the end user.
       
   992     $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
       
   993   }
       
   994 
       
   995   /**
       
   996    * Create an administrative user and delete another user.
       
   997    */
       
   998   function testUserCancelByAdmin() {
       
   999     variable_set('user_cancel_method', 'user_cancel_reassign');
       
  1000 
       
  1001     // Create a regular user.
       
  1002     $account = $this->drupalCreateUser(array());
       
  1003 
       
  1004     // Create administrative user.
       
  1005     $admin_user = $this->drupalCreateUser(array('administer users'));
       
  1006     $this->drupalLogin($admin_user);
       
  1007 
       
  1008     // Delete regular user.
       
  1009     $this->drupalGet('user/' . $account->uid . '/edit');
       
  1010     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
  1011     $this->assertRaw(t('Are you sure you want to cancel the account %name?', array('%name' => $account->name)), 'Confirmation form to cancel account displayed.');
       
  1012     $this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.');
       
  1013 
       
  1014     // Confirm deletion.
       
  1015     $this->drupalPost(NULL, NULL, t('Cancel account'));
       
  1016     $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), 'User deleted.');
       
  1017     $this->assertFalse(user_load($account->uid), 'User is not found in the database.');
       
  1018   }
       
  1019 
       
  1020   /**
       
  1021    * Create an administrative user and mass-delete other users.
       
  1022    */
       
  1023   function testMassUserCancelByAdmin() {
       
  1024     variable_set('user_cancel_method', 'user_cancel_reassign');
       
  1025     // Enable account cancellation notification.
       
  1026     variable_set('user_mail_status_canceled_notify', TRUE);
       
  1027 
       
  1028     // Create administrative user.
       
  1029     $admin_user = $this->drupalCreateUser(array('administer users'));
       
  1030     $this->drupalLogin($admin_user);
       
  1031 
       
  1032     // Create some users.
       
  1033     $users = array();
       
  1034     for ($i = 0; $i < 3; $i++) {
       
  1035       $account = $this->drupalCreateUser(array());
       
  1036       $users[$account->uid] = $account;
       
  1037     }
       
  1038 
       
  1039     // Cancel user accounts, including own one.
       
  1040     $edit = array();
       
  1041     $edit['operation'] = 'cancel';
       
  1042     foreach ($users as $uid => $account) {
       
  1043       $edit['accounts[' . $uid . ']'] = TRUE;
       
  1044     }
       
  1045     $edit['accounts[' . $admin_user->uid . ']'] = TRUE;
       
  1046     // Also try to cancel uid 1.
       
  1047     $edit['accounts[1]'] = TRUE;
       
  1048     $this->drupalPost('admin/people', $edit, t('Update'));
       
  1049     $this->assertText(t('Are you sure you want to cancel these user accounts?'), 'Confirmation form to cancel accounts displayed.');
       
  1050     $this->assertText(t('When cancelling these accounts'), 'Allows to select account cancellation method.');
       
  1051     $this->assertText(t('Require e-mail confirmation to cancel account.'), 'Allows to send confirmation mail.');
       
  1052     $this->assertText(t('Notify user when account is canceled.'), 'Allows to send notification mail.');
       
  1053 
       
  1054     // Confirm deletion.
       
  1055     $this->drupalPost(NULL, NULL, t('Cancel accounts'));
       
  1056     $status = TRUE;
       
  1057     foreach ($users as $account) {
       
  1058       $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->name))) !== FALSE);
       
  1059       $status = $status && !user_load($account->uid, TRUE);
       
  1060     }
       
  1061     $this->assertTrue($status, 'Users deleted and not found in the database.');
       
  1062 
       
  1063     // Ensure that admin account was not cancelled.
       
  1064     $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
       
  1065     $admin_user = user_load($admin_user->uid);
       
  1066     $this->assertTrue($admin_user->status == 1, 'Administrative user is found in the database and enabled.');
       
  1067 
       
  1068     // Verify that uid 1's account was not cancelled.
       
  1069     $user1 = user_load(1, TRUE);
       
  1070     $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
       
  1071   }
       
  1072 }
       
  1073 
       
  1074 class UserPictureTestCase extends DrupalWebTestCase {
       
  1075   protected $user;
       
  1076   protected $_directory_test;
       
  1077 
       
  1078   public static function getInfo() {
       
  1079     return array(
       
  1080       'name' => 'Upload user picture',
       
  1081       'description' => 'Assure that dimension check, extension check and image scaling work as designed.',
       
  1082       'group' => 'User'
       
  1083     );
       
  1084   }
       
  1085 
       
  1086   function setUp() {
       
  1087     parent::setUp();
       
  1088     // Enable user pictures.
       
  1089     variable_set('user_pictures', 1);
       
  1090 
       
  1091     $this->user = $this->drupalCreateUser();
       
  1092 
       
  1093     // Test if directories specified in settings exist in filesystem.
       
  1094     $file_dir = 'public://';
       
  1095     $file_check = file_prepare_directory($file_dir, FILE_CREATE_DIRECTORY);
       
  1096     // TODO: Test public and private methods?
       
  1097 
       
  1098     $picture_dir = variable_get('user_picture_path', 'pictures');
       
  1099     $picture_path = $file_dir . $picture_dir;
       
  1100 
       
  1101     $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY);
       
  1102     $this->_directory_test = is_writable($picture_path);
       
  1103     $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
       
  1104   }
       
  1105 
       
  1106   function testNoPicture() {
       
  1107     $this->drupalLogin($this->user);
       
  1108 
       
  1109     // Try to upload a file that is not an image for the user picture.
       
  1110     $not_an_image = current($this->drupalGetTestFiles('html'));
       
  1111     $this->saveUserPicture($not_an_image);
       
  1112     $this->assertRaw(t('Only JPEG, PNG and GIF images are allowed.'), 'Non-image files are not accepted.');
       
  1113   }
       
  1114 
       
  1115   /**
       
  1116    * Do the test:
       
  1117    *  GD Toolkit is installed
       
  1118    *  Picture has invalid dimension
       
  1119    *
       
  1120    * results: The image should be uploaded because ImageGDToolkit resizes the picture
       
  1121    */
       
  1122   function testWithGDinvalidDimension() {
       
  1123     if ($this->_directory_test && image_get_toolkit()) {
       
  1124       $this->drupalLogin($this->user);
       
  1125 
       
  1126       $image = current($this->drupalGetTestFiles('image'));
       
  1127       $info = image_get_info($image->uri);
       
  1128 
       
  1129       // Set new variables: invalid dimensions, valid filesize (0 = no limit).
       
  1130       $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
       
  1131       variable_set('user_picture_dimensions', $test_dim);
       
  1132       variable_set('user_picture_file_size', 0);
       
  1133 
       
  1134       $pic_path = $this->saveUserPicture($image);
       
  1135       // Check that the image was resized and is being displayed on the
       
  1136       // user's profile page.
       
  1137       $text = t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $test_dim));
       
  1138       $this->assertRaw($text, 'Image was resized.');
       
  1139       $alt = t("@user's picture", array('@user' => format_username($this->user)));
       
  1140       $style = variable_get('user_picture_style', '');
       
  1141       $this->assertRaw(check_plain(image_style_url($style, $pic_path)), "Image is displayed in user's edit page");
       
  1142 
       
  1143       // Check if file is located in proper directory.
       
  1144       $this->assertTrue(is_file($pic_path), "File is located in proper directory");
       
  1145     }
       
  1146   }
       
  1147 
       
  1148   /**
       
  1149    * Do the test:
       
  1150    *  GD Toolkit is installed
       
  1151    *  Picture has invalid size
       
  1152    *
       
  1153    * results: The image should be uploaded because ImageGDToolkit resizes the picture
       
  1154    */
       
  1155   function testWithGDinvalidSize() {
       
  1156     if ($this->_directory_test && image_get_toolkit()) {
       
  1157       $this->drupalLogin($this->user);
       
  1158 
       
  1159       // Images are sorted first by size then by name. We need an image
       
  1160       // bigger than 1 KB so we'll grab the last one.
       
  1161       $files = $this->drupalGetTestFiles('image');
       
  1162       $image = end($files);
       
  1163       $info = image_get_info($image->uri);
       
  1164 
       
  1165       // Set new variables: valid dimensions, invalid filesize.
       
  1166       $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
       
  1167       $test_size = 1;
       
  1168       variable_set('user_picture_dimensions', $test_dim);
       
  1169       variable_set('user_picture_file_size', $test_size);
       
  1170 
       
  1171       $pic_path = $this->saveUserPicture($image);
       
  1172 
       
  1173       // Test that the upload failed and that the correct reason was cited.
       
  1174       $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
       
  1175       $this->assertRaw($text, 'Upload failed.');
       
  1176       $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)));
       
  1177       $this->assertRaw($text, 'File size cited as reason for failure.');
       
  1178 
       
  1179       // Check if file is not uploaded.
       
  1180       $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
       
  1181     }
       
  1182   }
       
  1183 
       
  1184   /**
       
  1185    * Do the test:
       
  1186    *  GD Toolkit is not installed
       
  1187    *  Picture has invalid size
       
  1188    *
       
  1189    * results: The image shouldn't be uploaded
       
  1190    */
       
  1191   function testWithoutGDinvalidDimension() {
       
  1192     if ($this->_directory_test && !image_get_toolkit()) {
       
  1193       $this->drupalLogin($this->user);
       
  1194 
       
  1195       $image = current($this->drupalGetTestFiles('image'));
       
  1196       $info = image_get_info($image->uri);
       
  1197 
       
  1198       // Set new variables: invalid dimensions, valid filesize (0 = no limit).
       
  1199       $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
       
  1200       variable_set('user_picture_dimensions', $test_dim);
       
  1201       variable_set('user_picture_file_size', 0);
       
  1202 
       
  1203       $pic_path = $this->saveUserPicture($image);
       
  1204 
       
  1205       // Test that the upload failed and that the correct reason was cited.
       
  1206       $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
       
  1207       $this->assertRaw($text, 'Upload failed.');
       
  1208       $text = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $test_dim));
       
  1209       $this->assertRaw($text, 'Checking response on invalid image (dimensions).');
       
  1210 
       
  1211       // Check if file is not uploaded.
       
  1212       $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
       
  1213     }
       
  1214   }
       
  1215 
       
  1216   /**
       
  1217    * Do the test:
       
  1218    *  GD Toolkit is not installed
       
  1219    *  Picture has invalid size
       
  1220    *
       
  1221    * results: The image shouldn't be uploaded
       
  1222    */
       
  1223   function testWithoutGDinvalidSize() {
       
  1224     if ($this->_directory_test && !image_get_toolkit()) {
       
  1225       $this->drupalLogin($this->user);
       
  1226 
       
  1227       $image = current($this->drupalGetTestFiles('image'));
       
  1228       $info = image_get_info($image->uri);
       
  1229 
       
  1230       // Set new variables: valid dimensions, invalid filesize.
       
  1231       $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
       
  1232       $test_size = 1;
       
  1233       variable_set('user_picture_dimensions', $test_dim);
       
  1234       variable_set('user_picture_file_size', $test_size);
       
  1235 
       
  1236       $pic_path = $this->saveUserPicture($image);
       
  1237 
       
  1238       // Test that the upload failed and that the correct reason was cited.
       
  1239       $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
       
  1240       $this->assertRaw($text, 'Upload failed.');
       
  1241       $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)));
       
  1242       $this->assertRaw($text, 'File size cited as reason for failure.');
       
  1243 
       
  1244       // Check if file is not uploaded.
       
  1245       $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
       
  1246     }
       
  1247   }
       
  1248 
       
  1249   /**
       
  1250    * Do the test:
       
  1251    *  Picture is valid (proper size and dimension)
       
  1252    *
       
  1253    * results: The image should be uploaded
       
  1254    */
       
  1255   function testPictureIsValid() {
       
  1256     if ($this->_directory_test) {
       
  1257       $this->drupalLogin($this->user);
       
  1258 
       
  1259       $image = current($this->drupalGetTestFiles('image'));
       
  1260       $info = image_get_info($image->uri);
       
  1261 
       
  1262       // Set new variables: valid dimensions, valid filesize (0 = no limit).
       
  1263       $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
       
  1264       variable_set('user_picture_dimensions', $test_dim);
       
  1265       variable_set('user_picture_file_size', 0);
       
  1266 
       
  1267       $pic_path = $this->saveUserPicture($image);
       
  1268 
       
  1269       // Check if image is displayed in user's profile page.
       
  1270       $this->drupalGet('user');
       
  1271       $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
       
  1272 
       
  1273       // Check if file is located in proper directory.
       
  1274       $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
       
  1275 
       
  1276       // Set new picture dimensions.
       
  1277       $test_dim = ($info['width'] + 5) . 'x' . ($info['height'] + 5);
       
  1278       variable_set('user_picture_dimensions', $test_dim);
       
  1279 
       
  1280       $pic_path2 = $this->saveUserPicture($image);
       
  1281       $this->assertNotEqual($pic_path, $pic_path2, 'Filename of second picture is different.');
       
  1282 
       
  1283       // Check if user picture has a valid file ID after saving the user.
       
  1284       $account = user_load($this->user->uid, TRUE);
       
  1285       $this->assertTrue(is_object($account->picture), 'User picture object is valid after user load.');
       
  1286       $this->assertNotNull($account->picture->fid, 'User picture object has a FID after user load.');
       
  1287       $this->assertTrue(is_file($account->picture->uri), 'File is located in proper directory after user load.');
       
  1288       user_save($account);
       
  1289       // Verify that the user save does not destroy the user picture object.
       
  1290       $this->assertTrue(is_object($account->picture), 'User picture object is valid after user save.');
       
  1291       $this->assertNotNull($account->picture->fid, 'User picture object has a FID after user save.');
       
  1292       $this->assertTrue(is_file($account->picture->uri), 'File is located in proper directory after user save.');
       
  1293     }
       
  1294   }
       
  1295 
       
  1296   /**
       
  1297    * Test HTTP schema working with user pictures.
       
  1298    */
       
  1299   function testExternalPicture() {
       
  1300     $this->drupalLogin($this->user);
       
  1301     // Set the default picture to an URI with a HTTP schema.
       
  1302     $images = $this->drupalGetTestFiles('image');
       
  1303     $image = $images[0];
       
  1304     $pic_path = file_create_url($image->uri);
       
  1305     variable_set('user_picture_default', $pic_path);
       
  1306 
       
  1307     // Check if image is displayed in user's profile page.
       
  1308     $this->drupalGet('user');
       
  1309 
       
  1310     // Get the user picture image via xpath.
       
  1311     $elements = $this->xpath('//div[@class="user-picture"]/img');
       
  1312     $this->assertEqual(count($elements), 1, "There is exactly one user picture on the user's profile page");
       
  1313     $this->assertEqual($pic_path, (string) $elements[0]['src'], "User picture source is correct.");
       
  1314   }
       
  1315 
       
  1316   /**
       
  1317    * Tests deletion of user pictures.
       
  1318    */
       
  1319   function testDeletePicture() {
       
  1320     $this->drupalLogin($this->user);
       
  1321 
       
  1322     $image = current($this->drupalGetTestFiles('image'));
       
  1323     $info = image_get_info($image->uri);
       
  1324 
       
  1325     // Set new variables: valid dimensions, valid filesize (0 = no limit).
       
  1326     $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
       
  1327     variable_set('user_picture_dimensions', $test_dim);
       
  1328     variable_set('user_picture_file_size', 0);
       
  1329 
       
  1330     // Save a new picture.
       
  1331     $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
       
  1332     $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
       
  1333 
       
  1334     // Load actual user data from database.
       
  1335     $account = user_load($this->user->uid, TRUE);
       
  1336     $pic_path = isset($account->picture) ? $account->picture->uri : NULL;
       
  1337 
       
  1338     // Check if image is displayed in user's profile page.
       
  1339     $this->drupalGet('user');
       
  1340     $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
       
  1341 
       
  1342     // Check if file is located in proper directory.
       
  1343     $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
       
  1344 
       
  1345     $edit = array('picture_delete' => 1);
       
  1346     $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
       
  1347 
       
  1348     // Load actual user data from database.
       
  1349     $account1 = user_load($this->user->uid, TRUE);
       
  1350     $this->assertNull($account1->picture, 'User object has no picture');
       
  1351 
       
  1352     $file = file_load($account->picture->fid);
       
  1353     $this->assertFalse($file, 'File is removed from database');
       
  1354 
       
  1355     // Clear out PHP's file stat cache so we see the current value.
       
  1356     clearstatcache();
       
  1357     $this->assertFalse(is_file($pic_path), 'File is removed from file system');
       
  1358   }
       
  1359 
       
  1360   function saveUserPicture($image) {
       
  1361     $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
       
  1362     $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
       
  1363 
       
  1364     // Load actual user data from database.
       
  1365     $account = user_load($this->user->uid, TRUE);
       
  1366     return isset($account->picture) ? $account->picture->uri : NULL;
       
  1367   }
       
  1368 
       
  1369   /**
       
  1370    * Tests the admin form validates user picture settings.
       
  1371    */
       
  1372   function testUserPictureAdminFormValidation() {
       
  1373     $this->drupalLogin($this->drupalCreateUser(array('administer users')));
       
  1374 
       
  1375     // The default values are valid.
       
  1376     $this->drupalPost('admin/config/people/accounts', array(), t('Save configuration'));
       
  1377     $this->assertText(t('The configuration options have been saved.'), 'The default values are valid.');
       
  1378 
       
  1379     // The form does not save with an invalid file size.
       
  1380     $edit = array(
       
  1381       'user_picture_file_size' => $this->randomName(),
       
  1382     );
       
  1383     $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
       
  1384     $this->assertNoText(t('The configuration options have been saved.'), 'The form does not save with an invalid file size.');
       
  1385   }
       
  1386 }
       
  1387 
       
  1388 
       
  1389 class UserPermissionsTestCase extends DrupalWebTestCase {
       
  1390   protected $admin_user;
       
  1391   protected $rid;
       
  1392 
       
  1393   public static function getInfo() {
       
  1394     return array(
       
  1395       'name' => 'Role permissions',
       
  1396       'description' => 'Verify that role permissions can be added and removed via the permissions page.',
       
  1397       'group' => 'User'
       
  1398     );
       
  1399   }
       
  1400 
       
  1401   function setUp() {
       
  1402     parent::setUp();
       
  1403 
       
  1404     $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users'));
       
  1405 
       
  1406     // Find the new role ID - it must be the maximum.
       
  1407     $all_rids = array_keys($this->admin_user->roles);
       
  1408     sort($all_rids);
       
  1409     $this->rid = array_pop($all_rids);
       
  1410   }
       
  1411 
       
  1412   /**
       
  1413    * Change user permissions and check user_access().
       
  1414    */
       
  1415   function testUserPermissionChanges() {
       
  1416     $this->drupalLogin($this->admin_user);
       
  1417     $rid = $this->rid;
       
  1418     $account = $this->admin_user;
       
  1419 
       
  1420     // Add a permission.
       
  1421     $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
       
  1422     $edit = array();
       
  1423     $edit[$rid . '[administer nodes]'] = TRUE;
       
  1424     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
       
  1425     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
       
  1426     drupal_static_reset('user_access');
       
  1427     drupal_static_reset('user_role_permissions');
       
  1428     $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
       
  1429 
       
  1430     // Remove a permission.
       
  1431     $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
       
  1432     $edit = array();
       
  1433     $edit[$rid . '[access user profiles]'] = FALSE;
       
  1434     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
       
  1435     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
       
  1436     drupal_static_reset('user_access');
       
  1437     drupal_static_reset('user_role_permissions');
       
  1438     $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
       
  1439   }
       
  1440 
       
  1441   /**
       
  1442    * Test assigning of permissions for the administrator role.
       
  1443    */
       
  1444   function testAdministratorRole() {
       
  1445     $this->drupalLogin($this->admin_user);
       
  1446     $this->drupalGet('admin/config/people/accounts');
       
  1447 
       
  1448     // Set the user's role to be the administrator role.
       
  1449     $edit = array();
       
  1450     $edit['user_admin_role'] = $this->rid;
       
  1451     $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
       
  1452 
       
  1453     // Enable aggregator module and ensure the 'administer news feeds'
       
  1454     // permission is assigned by default.
       
  1455     $edit = array();
       
  1456     $edit['modules[Core][aggregator][enable]'] = TRUE;
       
  1457     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
       
  1458     $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role');
       
  1459   }
       
  1460 
       
  1461   /**
       
  1462    * Verify proper permission changes by user_role_change_permissions().
       
  1463    */
       
  1464   function testUserRoleChangePermissions() {
       
  1465     $rid = $this->rid;
       
  1466     $account = $this->admin_user;
       
  1467 
       
  1468     // Verify current permissions.
       
  1469     $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
       
  1470     $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
       
  1471     $this->assertTrue(user_access('administer site configuration', $account), 'User has "administer site configuration" permission.');
       
  1472 
       
  1473     // Change permissions.
       
  1474     $permissions = array(
       
  1475       'administer nodes' => 1,
       
  1476       'access user profiles' => 0,
       
  1477     );
       
  1478     user_role_change_permissions($rid, $permissions);
       
  1479 
       
  1480     // Verify proper permission changes.
       
  1481     $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
       
  1482     $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
       
  1483     $this->assertTrue(user_access('administer site configuration', $account), 'User still has "administer site configuration" permission.');
       
  1484   }
       
  1485 }
       
  1486 
       
  1487 class UserAdminTestCase extends DrupalWebTestCase {
       
  1488   public static function getInfo() {
       
  1489     return array(
       
  1490       'name' => 'User administration',
       
  1491       'description' => 'Test user administration page functionality.',
       
  1492       'group' => 'User'
       
  1493     );
       
  1494   }
       
  1495 
       
  1496   /**
       
  1497    * Registers a user and deletes it.
       
  1498    */
       
  1499   function testUserAdmin() {
       
  1500 
       
  1501     $user_a = $this->drupalCreateUser(array());
       
  1502     $user_b = $this->drupalCreateUser(array('administer taxonomy'));
       
  1503     $user_c = $this->drupalCreateUser(array('administer taxonomy'));
       
  1504 
       
  1505     // Create admin user to delete registered user.
       
  1506     $admin_user = $this->drupalCreateUser(array('administer users'));
       
  1507     $this->drupalLogin($admin_user);
       
  1508     $this->drupalGet('admin/people');
       
  1509     $this->assertText($user_a->name, 'Found user A on admin users page');
       
  1510     $this->assertText($user_b->name, 'Found user B on admin users page');
       
  1511     $this->assertText($user_c->name, 'Found user C on admin users page');
       
  1512     $this->assertText($admin_user->name, 'Found Admin user on admin users page');
       
  1513 
       
  1514     // Test for existence of edit link in table.
       
  1515     $link = l(t('edit'), "user/$user_a->uid/edit", array('query' => array('destination' => 'admin/people')));
       
  1516     $this->assertRaw($link, 'Found user A edit link on admin users page');
       
  1517 
       
  1518     // Filter the users by permission 'administer taxonomy'.
       
  1519     $edit = array();
       
  1520     $edit['permission'] = 'administer taxonomy';
       
  1521     $this->drupalPost('admin/people', $edit, t('Filter'));
       
  1522 
       
  1523     // Check if the correct users show up.
       
  1524     $this->assertNoText($user_a->name, 'User A not on filtered by perm admin users page');
       
  1525     $this->assertText($user_b->name, 'Found user B on filtered by perm admin users page');
       
  1526     $this->assertText($user_c->name, 'Found user C on filtered by perm admin users page');
       
  1527 
       
  1528     // Filter the users by role. Grab the system-generated role name for User C.
       
  1529     $edit['role'] = max(array_flip($user_c->roles));
       
  1530     $this->drupalPost('admin/people', $edit, t('Refine'));
       
  1531 
       
  1532     // Check if the correct users show up when filtered by role.
       
  1533     $this->assertNoText($user_a->name, 'User A not on filtered by role on admin users page');
       
  1534     $this->assertNoText($user_b->name, 'User B not on filtered by role on admin users page');
       
  1535     $this->assertText($user_c->name, 'User C on filtered by role on admin users page');
       
  1536 
       
  1537     // Test blocking of a user.
       
  1538     $account = user_load($user_c->uid);
       
  1539     $this->assertEqual($account->status, 1, 'User C not blocked');
       
  1540     $edit = array();
       
  1541     $edit['operation'] = 'block';
       
  1542     $edit['accounts[' . $account->uid . ']'] = TRUE;
       
  1543     $this->drupalPost('admin/people', $edit, t('Update'));
       
  1544     $account = user_load($user_c->uid, TRUE);
       
  1545     $this->assertEqual($account->status, 0, 'User C blocked');
       
  1546 
       
  1547     // Test unblocking of a user from /admin/people page and sending of activation mail
       
  1548     $editunblock = array();
       
  1549     $editunblock['operation'] = 'unblock';
       
  1550     $editunblock['accounts[' . $account->uid . ']'] = TRUE;
       
  1551     $this->drupalPost('admin/people', $editunblock, t('Update'));
       
  1552     $account = user_load($user_c->uid, TRUE);
       
  1553     $this->assertEqual($account->status, 1, 'User C unblocked');
       
  1554     $this->assertMail("to", $account->mail, "Activation mail sent to user C");
       
  1555 
       
  1556     // Test blocking and unblocking another user from /user/[uid]/edit form and sending of activation mail
       
  1557     $user_d = $this->drupalCreateUser(array());
       
  1558     $account1 = user_load($user_d->uid, TRUE);
       
  1559     $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => 0), t('Save'));
       
  1560     $account1 = user_load($user_d->uid, TRUE);
       
  1561     $this->assertEqual($account1->status, 0, 'User D blocked');
       
  1562     $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => TRUE), t('Save'));
       
  1563     $account1 = user_load($user_d->uid, TRUE);
       
  1564     $this->assertEqual($account1->status, 1, 'User D unblocked');
       
  1565     $this->assertMail("to", $account1->mail, "Activation mail sent to user D");
       
  1566   }
       
  1567 }
       
  1568 
       
  1569 /**
       
  1570  * Tests for user-configurable time zones.
       
  1571  */
       
  1572 class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
       
  1573   public static function getInfo() {
       
  1574     return array(
       
  1575       'name' => 'User time zones',
       
  1576       'description' => 'Set a user time zone and verify that dates are displayed in local time.',
       
  1577       'group' => 'User',
       
  1578     );
       
  1579   }
       
  1580 
       
  1581   /**
       
  1582    * Tests the display of dates and time when user-configurable time zones are set.
       
  1583    */
       
  1584   function testUserTimeZone() {
       
  1585     // Setup date/time settings for Los Angeles time.
       
  1586     variable_set('date_default_timezone', 'America/Los_Angeles');
       
  1587     variable_set('configurable_timezones', 1);
       
  1588 
       
  1589     // Override the 'medium' date format, which is the default for node
       
  1590     // creation time. Since we are testing time zones with Daylight Saving
       
  1591     // Time, and need to future proof against changes to the zoneinfo database,
       
  1592     // we choose the 'I' format placeholder instead of a human-readable zone
       
  1593     // name. With 'I', a 1 means the date is in DST, and 0 if not.
       
  1594     variable_set('date_format_medium', 'Y-m-d H:i I');
       
  1595 
       
  1596     // Create a user account and login.
       
  1597     $web_user = $this->drupalCreateUser();
       
  1598     $this->drupalLogin($web_user);
       
  1599 
       
  1600     // Create some nodes with different authored-on dates.
       
  1601     // Two dates in PST (winter time):
       
  1602     $date1 = '2007-03-09 21:00:00 -0800';
       
  1603     $date2 = '2007-03-11 01:00:00 -0800';
       
  1604     // One date in PDT (summer time):
       
  1605     $date3 = '2007-03-20 21:00:00 -0700';
       
  1606     $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article'));
       
  1607     $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article'));
       
  1608     $node3 = $this->drupalCreateNode(array('created' => strtotime($date3), 'type' => 'article'));
       
  1609 
       
  1610     // Confirm date format and time zone.
       
  1611     $this->drupalGet("node/$node1->nid");
       
  1612     $this->assertText('2007-03-09 21:00 0', 'Date should be PST.');
       
  1613     $this->drupalGet("node/$node2->nid");
       
  1614     $this->assertText('2007-03-11 01:00 0', 'Date should be PST.');
       
  1615     $this->drupalGet("node/$node3->nid");
       
  1616     $this->assertText('2007-03-20 21:00 1', 'Date should be PDT.');
       
  1617 
       
  1618     // Change user time zone to Santiago time.
       
  1619     $edit = array();
       
  1620     $edit['mail'] = $web_user->mail;
       
  1621     $edit['timezone'] = 'America/Santiago';
       
  1622     $this->drupalPost("user/$web_user->uid/edit", $edit, t('Save'));
       
  1623     $this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.');
       
  1624 
       
  1625     // Confirm date format and time zone.
       
  1626     $this->drupalGet("node/$node1->nid");
       
  1627     $this->assertText('2007-03-10 02:00 1', 'Date should be Chile summer time; five hours ahead of PST.');
       
  1628     $this->drupalGet("node/$node2->nid");
       
  1629     $this->assertText('2007-03-11 05:00 0', 'Date should be Chile time; four hours ahead of PST');
       
  1630     $this->drupalGet("node/$node3->nid");
       
  1631     $this->assertText('2007-03-21 00:00 0', 'Date should be Chile time; three hours ahead of PDT.');
       
  1632   }
       
  1633 }
       
  1634 
       
  1635 /**
       
  1636  * Test user autocompletion.
       
  1637  */
       
  1638 class UserAutocompleteTestCase extends DrupalWebTestCase {
       
  1639   public static function getInfo() {
       
  1640     return array(
       
  1641       'name' => 'User autocompletion',
       
  1642       'description' => 'Test user autocompletion functionality.',
       
  1643       'group' => 'User'
       
  1644     );
       
  1645   }
       
  1646 
       
  1647   function setUp() {
       
  1648     parent::setUp();
       
  1649 
       
  1650     // Set up two users with different permissions to test access.
       
  1651     $this->unprivileged_user = $this->drupalCreateUser();
       
  1652     $this->privileged_user = $this->drupalCreateUser(array('access user profiles'));
       
  1653   }
       
  1654 
       
  1655   /**
       
  1656    * Tests access to user autocompletion and verify the correct results.
       
  1657    */
       
  1658   function testUserAutocomplete() {
       
  1659     // Check access from unprivileged user, should be denied.
       
  1660     $this->drupalLogin($this->unprivileged_user);
       
  1661     $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
       
  1662     $this->assertResponse(403, 'Autocompletion access denied to user without permission.');
       
  1663 
       
  1664     // Check access from privileged user.
       
  1665     $this->drupalLogout();
       
  1666     $this->drupalLogin($this->privileged_user);
       
  1667     $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
       
  1668     $this->assertResponse(200, 'Autocompletion access allowed.');
       
  1669 
       
  1670     // Using first letter of the user's name, make sure the user's full name is in the results.
       
  1671     $this->assertRaw($this->unprivileged_user->name, 'User name found in autocompletion results.');
       
  1672   }
       
  1673 }
       
  1674 
       
  1675 
       
  1676 /**
       
  1677  * Tests user links in the secondary menu.
       
  1678  */
       
  1679 class UserAccountLinksUnitTests extends DrupalWebTestCase {
       
  1680   public static function getInfo() {
       
  1681     return array(
       
  1682       'name' => 'User account links',
       
  1683       'description' => 'Test user-account links.',
       
  1684       'group' => 'User'
       
  1685     );
       
  1686   }
       
  1687 
       
  1688   function setUp() {
       
  1689     parent::setUp('menu');
       
  1690   }
       
  1691 
       
  1692   /**
       
  1693    * Tests the secondary menu.
       
  1694    */
       
  1695   function testSecondaryMenu() {
       
  1696     // Create a regular user.
       
  1697     $user = $this->drupalCreateUser(array());
       
  1698 
       
  1699     // Log in and get the homepage.
       
  1700     $this->drupalLogin($user);
       
  1701     $this->drupalGet('<front>');
       
  1702 
       
  1703     // For a logged-in user, expect the secondary menu to have links for "My
       
  1704     // account" and "Log out".
       
  1705     $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
       
  1706       ':menu_id' => 'secondary-menu-links',
       
  1707       ':href' => 'user',
       
  1708       ':text' => 'My account',
       
  1709     ));
       
  1710     $this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
       
  1711 
       
  1712     $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
       
  1713       ':menu_id' => 'secondary-menu-links',
       
  1714       ':href' => 'user/logout',
       
  1715       ':text' => 'Log out',
       
  1716     ));
       
  1717     $this->assertEqual(count($link), 1, 'Log out link is in secondary menu.');
       
  1718 
       
  1719     // Log out and get the homepage.
       
  1720     $this->drupalLogout();
       
  1721     $this->drupalGet('<front>');
       
  1722 
       
  1723     // For a logged-out user, expect no secondary links.
       
  1724     $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links'));
       
  1725     $this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.');
       
  1726   }
       
  1727 
       
  1728   /**
       
  1729    * Tests disabling the 'My account' link.
       
  1730    */
       
  1731   function testDisabledAccountLink() {
       
  1732     // Create an admin user and log in.
       
  1733     $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu')));
       
  1734 
       
  1735     // Verify that the 'My account' link is enabled.
       
  1736     $this->drupalGet('admin/structure/menu/manage/user-menu');
       
  1737     $label = $this->xpath('//label[contains(.,:text)]/@for', array(':text' => 'Enable My account menu link'));
       
  1738     $this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
       
  1739 
       
  1740     // Disable the 'My account' link.
       
  1741     $input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0]));
       
  1742     $edit = array(
       
  1743       (string) $input[0] => FALSE,
       
  1744     );
       
  1745     $this->drupalPost('admin/structure/menu/manage/user-menu', $edit, t('Save configuration'));
       
  1746 
       
  1747     // Get the homepage.
       
  1748     $this->drupalGet('<front>');
       
  1749 
       
  1750     // Verify that the 'My account' link does not appear when disabled.
       
  1751     $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
       
  1752       ':menu_id' => 'secondary-menu-links',
       
  1753       ':href' => 'user',
       
  1754       ':text' => 'My account',
       
  1755     ));
       
  1756     $this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.');
       
  1757   }
       
  1758 
       
  1759 }
       
  1760 
       
  1761 /**
       
  1762  * Test user blocks.
       
  1763  */
       
  1764 class UserBlocksUnitTests extends DrupalWebTestCase {
       
  1765   public static function getInfo() {
       
  1766     return array(
       
  1767       'name' => 'User blocks',
       
  1768       'description' => 'Test user blocks.',
       
  1769       'group' => 'User'
       
  1770     );
       
  1771   }
       
  1772 
       
  1773   /**
       
  1774    * Test the user login block.
       
  1775    */
       
  1776   function testUserLoginBlock() {
       
  1777     // Create a user with some permission that anonymous users lack.
       
  1778     $user = $this->drupalCreateUser(array('administer permissions'));
       
  1779 
       
  1780     // Log in using the block.
       
  1781     $edit = array();
       
  1782     $edit['name'] = $user->name;
       
  1783     $edit['pass'] = $user->pass_raw;
       
  1784     $this->drupalPost('admin/people/permissions', $edit, t('Log in'));
       
  1785     $this->assertNoText(t('User login'), 'Logged in.');
       
  1786 
       
  1787     // Check that we are still on the same page.
       
  1788     $this->assertEqual(url('admin/people/permissions', array('absolute' => TRUE)), $this->getUrl(), 'Still on the same page after login for access denied page');
       
  1789 
       
  1790     // Now, log out and repeat with a non-403 page.
       
  1791     $this->drupalLogout();
       
  1792     $this->drupalPost('filter/tips', $edit, t('Log in'));
       
  1793     $this->assertNoText(t('User login'), 'Logged in.');
       
  1794     $this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
       
  1795 
       
  1796     // Check that the user login block is not vulnerable to information
       
  1797     // disclosure to third party sites.
       
  1798     $this->drupalLogout();
       
  1799     $this->drupalPost('http://example.com/', $edit, t('Log in'), array('external' => FALSE));
       
  1800     // Check that we remain on the site after login.
       
  1801     $this->assertEqual(url('user/' . $user->uid, array('absolute' => TRUE)), $this->getUrl(), 'Redirected to user profile page after login from the frontpage');
       
  1802   }
       
  1803 
       
  1804   /**
       
  1805    * Test the Who's Online block.
       
  1806    */
       
  1807   function testWhosOnlineBlock() {
       
  1808     // Generate users and make sure there are no current user sessions.
       
  1809     $user1 = $this->drupalCreateUser(array());
       
  1810     $user2 = $this->drupalCreateUser(array());
       
  1811     $user3 = $this->drupalCreateUser(array());
       
  1812     $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions}")->fetchField(), 0, 'Sessions table is empty.');
       
  1813 
       
  1814     // Insert a user with two sessions.
       
  1815     $this->insertSession(array('uid' => $user1->uid));
       
  1816     $this->insertSession(array('uid' => $user1->uid));
       
  1817     $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid", array(':uid' => $user1->uid))->fetchField(), 2, 'Duplicate user session has been inserted.');
       
  1818 
       
  1819     // Insert a user with only one session.
       
  1820     $this->insertSession(array('uid' => $user2->uid, 'timestamp' => REQUEST_TIME + 1));
       
  1821 
       
  1822     // Insert an inactive logged-in user who should not be seen in the block.
       
  1823     $this->insertSession(array('uid' => $user3->uid, 'timestamp' => (REQUEST_TIME - variable_get('user_block_seconds_online', 900) - 1)));
       
  1824 
       
  1825     // Insert two anonymous user sessions.
       
  1826     $this->insertSession();
       
  1827     $this->insertSession();
       
  1828 
       
  1829     // Test block output.
       
  1830     $block = user_block_view('online');
       
  1831     $this->drupalSetContent($block['content']);
       
  1832     $this->assertRaw(t('2 users'), 'Correct number of online users (2 users).');
       
  1833     $this->assertText($user1->name, 'Active user 1 found in online list.');
       
  1834     $this->assertText($user2->name, 'Active user 2 found in online list.');
       
  1835     $this->assertNoText($user3->name, "Inactive user not found in online list.");
       
  1836     $this->assertTrue(strpos($this->drupalGetContent(), $user1->name) > strpos($this->drupalGetContent(), $user2->name), 'Online users are ordered correctly.');
       
  1837   }
       
  1838 
       
  1839   /**
       
  1840    * Insert a user session into the {sessions} table. This function is used
       
  1841    * since we cannot log in more than one user at the same time in tests.
       
  1842    */
       
  1843   private function insertSession(array $fields = array()) {
       
  1844     $fields += array(
       
  1845       'uid' => 0,
       
  1846       'sid' => drupal_hash_base64(uniqid(mt_rand(), TRUE)),
       
  1847       'timestamp' => REQUEST_TIME,
       
  1848     );
       
  1849     db_insert('sessions')
       
  1850       ->fields($fields)
       
  1851       ->execute();
       
  1852     $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.');
       
  1853   }
       
  1854 }
       
  1855 
       
  1856 /**
       
  1857  * Tests saving a user account.
       
  1858  */
       
  1859 class UserSaveTestCase extends DrupalWebTestCase {
       
  1860 
       
  1861   public static function getInfo() {
       
  1862     return array(
       
  1863       'name' => 'User save test',
       
  1864       'description' => 'Test user_save() for arbitrary new uid.',
       
  1865       'group' => 'User',
       
  1866     );
       
  1867   }
       
  1868 
       
  1869   /**
       
  1870    * Test creating a user with arbitrary uid.
       
  1871    */
       
  1872   function testUserImport() {
       
  1873     // User ID must be a number that is not in the database.
       
  1874     $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField();
       
  1875     $test_uid = $max_uid + mt_rand(1000, 1000000);
       
  1876     $test_name = $this->randomName();
       
  1877 
       
  1878     // Create the base user, based on drupalCreateUser().
       
  1879     $user = array(
       
  1880       'name' => $test_name,
       
  1881       'uid' => $test_uid,
       
  1882       'mail' => $test_name . '@example.com',
       
  1883       'is_new' => TRUE,
       
  1884       'pass' => user_password(),
       
  1885       'status' => 1,
       
  1886     );
       
  1887     $user_by_return = user_save(drupal_anonymous_user(), $user);
       
  1888     $this->assertTrue($user_by_return, 'Loading user by return of user_save().');
       
  1889 
       
  1890     // Test if created user exists.
       
  1891     $user_by_uid = user_load($test_uid);
       
  1892     $this->assertTrue($user_by_uid, 'Loading user by uid.');
       
  1893 
       
  1894     $user_by_name = user_load_by_name($test_name);
       
  1895     $this->assertTrue($user_by_name, 'Loading user by name.');
       
  1896   }
       
  1897 }
       
  1898 
       
  1899 /**
       
  1900  * Test the create user administration page.
       
  1901  */
       
  1902 class UserCreateTestCase extends DrupalWebTestCase {
       
  1903 
       
  1904   public static function getInfo() {
       
  1905     return array(
       
  1906       'name' => 'User create',
       
  1907       'description' => 'Test the create user administration page.',
       
  1908       'group' => 'User',
       
  1909     );
       
  1910   }
       
  1911 
       
  1912   /**
       
  1913    * Create a user through the administration interface and ensure that it
       
  1914    * displays in the user list.
       
  1915    */
       
  1916   protected function testUserAdd() {
       
  1917     $user = $this->drupalCreateUser(array('administer users'));
       
  1918     $this->drupalLogin($user);
       
  1919 
       
  1920     foreach (array(FALSE, TRUE) as $notify) {
       
  1921       $edit = array(
       
  1922         'name' => $this->randomName(),
       
  1923         'mail' => $this->randomName() . '@example.com',
       
  1924         'pass[pass1]' => $pass = $this->randomString(),
       
  1925         'pass[pass2]' => $pass,
       
  1926         'notify' => $notify,
       
  1927       );
       
  1928       $this->drupalPost('admin/people/create', $edit, t('Create new account'));
       
  1929 
       
  1930       if ($notify) {
       
  1931         $this->assertText(t('A welcome message with further instructions has been e-mailed to the new user @name.', array('@name' => $edit['name'])), 'User created');
       
  1932         $this->assertEqual(count($this->drupalGetMails()), 1, 'Notification e-mail sent');
       
  1933       }
       
  1934       else {
       
  1935         $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created');
       
  1936         $this->assertEqual(count($this->drupalGetMails()), 0, 'Notification e-mail not sent');
       
  1937       }
       
  1938 
       
  1939       $this->drupalGet('admin/people');
       
  1940       $this->assertText($edit['name'], 'User found in list of users');
       
  1941     }
       
  1942 
       
  1943     // Test that the password '0' is considered a password.
       
  1944     $name = $this->randomName();
       
  1945     $edit = array(
       
  1946       'name' => $name,
       
  1947       'mail' => $name . '@example.com',
       
  1948       'pass[pass1]' => 0,
       
  1949       'pass[pass2]' => 0,
       
  1950       'notify' => FALSE,
       
  1951     );
       
  1952     $this->drupalPost('admin/people/create', $edit, t('Create new account'));
       
  1953     $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created with password 0');
       
  1954     $this->assertNoText('Password field is required');
       
  1955   }
       
  1956 }
       
  1957 
       
  1958 /**
       
  1959  * Tests editing a user account.
       
  1960  */
       
  1961 class UserEditTestCase extends DrupalWebTestCase {
       
  1962 
       
  1963   public static function getInfo() {
       
  1964     return array(
       
  1965       'name' => 'User edit',
       
  1966       'description' => 'Test user edit page.',
       
  1967       'group' => 'User',
       
  1968     );
       
  1969   }
       
  1970 
       
  1971   /**
       
  1972    * Test user edit page.
       
  1973    */
       
  1974   function testUserEdit() {
       
  1975     // Test user edit functionality with user pictures disabled.
       
  1976     variable_set('user_pictures', 0);
       
  1977     $user1 = $this->drupalCreateUser(array('change own username'));
       
  1978     $user2 = $this->drupalCreateUser(array());
       
  1979     $this->drupalLogin($user1);
       
  1980 
       
  1981     // Test that error message appears when attempting to use a non-unique user name.
       
  1982     $edit['name'] = $user2->name;
       
  1983     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  1984     $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
       
  1985 
       
  1986     // Repeat the test with user pictures enabled, which modifies the form.
       
  1987     variable_set('user_pictures', 1);
       
  1988     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  1989     $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
       
  1990 
       
  1991     // Check that filling out a single password field does not validate.
       
  1992     $edit = array();
       
  1993     $edit['pass[pass1]'] = '';
       
  1994     $edit['pass[pass2]'] = $this->randomName();
       
  1995     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  1996     $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
       
  1997 
       
  1998     $edit['pass[pass1]'] = $this->randomName();
       
  1999     $edit['pass[pass2]'] = '';
       
  2000     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2001     $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
       
  2002 
       
  2003     // Test that the error message appears when attempting to change the mail or
       
  2004     // pass without the current password.
       
  2005     $edit = array();
       
  2006     $edit['mail'] = $this->randomName() . '@new.example.com';
       
  2007     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2008     $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('E-mail address'))));
       
  2009 
       
  2010     $edit['current_pass'] = $user1->pass_raw;
       
  2011     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2012     $this->assertRaw(t("The changes have been saved."));
       
  2013 
       
  2014     // Test that the user must enter current password before changing passwords.
       
  2015     $edit = array();
       
  2016     $edit['pass[pass1]'] = $new_pass = $this->randomName();
       
  2017     $edit['pass[pass2]'] = $new_pass;
       
  2018     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2019     $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password'))));
       
  2020 
       
  2021     // Try again with the current password.
       
  2022     $edit['current_pass'] = $user1->pass_raw;
       
  2023     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2024     $this->assertRaw(t("The changes have been saved."));
       
  2025 
       
  2026     // Make sure the user can log in with their new password.
       
  2027     $this->drupalLogout();
       
  2028     $user1->pass_raw = $new_pass;
       
  2029     $this->drupalLogin($user1);
       
  2030     $this->drupalLogout();
       
  2031   }
       
  2032 
       
  2033   /**
       
  2034    * Tests setting the password to "0".
       
  2035    */
       
  2036   public function testUserWith0Password() {
       
  2037     $admin = $this->drupalCreateUser(array('administer users'));
       
  2038     $this->drupalLogin($admin);
       
  2039     // Create a regular user.
       
  2040     $user1 = $this->drupalCreateUser(array());
       
  2041 
       
  2042     $edit = array('pass[pass1]' => '0', 'pass[pass2]' => '0');
       
  2043     $this->drupalPost("user/" . $user1->uid . "/edit", $edit, t('Save'));
       
  2044     $this->assertRaw(t("The changes have been saved."));
       
  2045 
       
  2046     $this->drupalLogout();
       
  2047     $user1->pass_raw = '0';
       
  2048     $this->drupalLogin($user1);
       
  2049     $this->drupalLogout();
       
  2050   }
       
  2051 }
       
  2052 
       
  2053 /**
       
  2054  * Tests editing a user account with and without a form rebuild.
       
  2055  */
       
  2056 class UserEditRebuildTestCase extends DrupalWebTestCase {
       
  2057 
       
  2058   public static function getInfo() {
       
  2059     return array(
       
  2060       'name' => 'User edit with form rebuild',
       
  2061       'description' => 'Test user edit page when a form rebuild is triggered.',
       
  2062       'group' => 'User',
       
  2063     );
       
  2064   }
       
  2065 
       
  2066   function setUp() {
       
  2067     parent::setUp('user_form_test');
       
  2068   }
       
  2069 
       
  2070   /**
       
  2071    * Test user edit page when the form is set to rebuild.
       
  2072    */
       
  2073   function testUserEditFormRebuild() {
       
  2074     $user1 = $this->drupalCreateUser(array('change own username'));
       
  2075     $this->drupalLogin($user1);
       
  2076 
       
  2077     $roles = array_keys($user1->roles);
       
  2078     // Save the user form twice.
       
  2079     $edit = array();
       
  2080     $edit['current_pass'] = $user1->pass_raw;
       
  2081     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2082     $this->assertRaw(t("The changes have been saved."));
       
  2083     $this->drupalPost(NULL, $edit, t('Save'));
       
  2084     $this->assertRaw(t("The changes have been saved."));
       
  2085     $saved_user1 = entity_load_unchanged('user', $user1->uid);
       
  2086     $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.');
       
  2087     $diff = array_diff(array_keys($saved_user1->roles), $roles);
       
  2088     $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles))));
       
  2089     // Set variable that causes the form to be rebuilt in user_form_test.module.
       
  2090     variable_set('user_form_test_user_profile_form_rebuild', TRUE);
       
  2091     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
       
  2092     $this->assertRaw(t("The changes have been saved."));
       
  2093     $this->drupalPost(NULL, $edit, t('Save'));
       
  2094     $this->assertRaw(t("The changes have been saved."));
       
  2095     $saved_user1 = entity_load_unchanged('user', $user1->uid);
       
  2096     $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.');
       
  2097     $diff = array_diff(array_keys($saved_user1->roles), $roles);
       
  2098     $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles))));
       
  2099   }
       
  2100 }
       
  2101 
       
  2102 /**
       
  2103  * Test case for user signatures.
       
  2104  */
       
  2105 class UserSignatureTestCase extends DrupalWebTestCase {
       
  2106   public static function getInfo() {
       
  2107     return array(
       
  2108       'name' => 'User signatures',
       
  2109       'description' => 'Test user signatures.',
       
  2110       'group' => 'User',
       
  2111     );
       
  2112   }
       
  2113 
       
  2114   function setUp() {
       
  2115     parent::setUp('comment');
       
  2116 
       
  2117     // Enable user signatures.
       
  2118     variable_set('user_signatures', 1);
       
  2119 
       
  2120     // Prefetch text formats.
       
  2121     $this->full_html_format = filter_format_load('full_html');
       
  2122     $this->plain_text_format = filter_format_load('plain_text');
       
  2123 
       
  2124     // Create regular and administrative users.
       
  2125     $this->web_user = $this->drupalCreateUser(array());
       
  2126     $admin_permissions = array('administer comments');
       
  2127     foreach (filter_formats() as $format) {
       
  2128       if ($permission = filter_permission_name($format)) {
       
  2129         $admin_permissions[] = $permission;
       
  2130       }
       
  2131     }
       
  2132     $this->admin_user = $this->drupalCreateUser($admin_permissions);
       
  2133   }
       
  2134 
       
  2135   /**
       
  2136    * Test that a user can change their signature format and that it is respected
       
  2137    * upon display.
       
  2138    */
       
  2139   function testUserSignature() {
       
  2140     // Create a new node with comments on.
       
  2141     $node = $this->drupalCreateNode(array('comment' => COMMENT_NODE_OPEN));
       
  2142 
       
  2143     // Verify that user signature field is not displayed on registration form.
       
  2144     $this->drupalGet('user/register');
       
  2145     $this->assertNoText(t('Signature'));
       
  2146 
       
  2147     // Log in as a regular user and create a signature.
       
  2148     $this->drupalLogin($this->web_user);
       
  2149     $signature_text = "<h1>" . $this->randomName() . "</h1>";
       
  2150     $edit = array(
       
  2151       'signature[value]' => $signature_text,
       
  2152       'signature[format]' => $this->plain_text_format->format,
       
  2153     );
       
  2154     $this->drupalPost('user/' . $this->web_user->uid . '/edit', $edit, t('Save'));
       
  2155 
       
  2156     // Verify that values were stored.
       
  2157     $this->assertFieldByName('signature[value]', $edit['signature[value]'], 'Submitted signature text found.');
       
  2158     $this->assertFieldByName('signature[format]', $edit['signature[format]'], 'Submitted signature format found.');
       
  2159 
       
  2160     // Create a comment.
       
  2161     $langcode = LANGUAGE_NONE;
       
  2162     $edit = array();
       
  2163     $edit['subject'] = $this->randomName(8);
       
  2164     $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
       
  2165     $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
       
  2166     $this->drupalPost(NULL, array(), t('Save'));
       
  2167 
       
  2168     // Get the comment ID. (This technique is the same one used in the Comment
       
  2169     // module's CommentHelperCase test case.)
       
  2170     preg_match('/#comment-([0-9]+)/', $this->getURL(), $match);
       
  2171     $comment_id = $match[1];
       
  2172 
       
  2173     // Log in as an administrator and edit the comment to use Full HTML, so
       
  2174     // that the comment text itself is not filtered at all.
       
  2175     $this->drupalLogin($this->admin_user);
       
  2176     $edit['comment_body[' . $langcode . '][0][format]'] = $this->full_html_format->format;
       
  2177     $this->drupalPost('comment/' . $comment_id . '/edit', $edit, t('Save'));
       
  2178 
       
  2179     // Assert that the signature did not make it through unfiltered.
       
  2180     $this->drupalGet('node/' . $node->nid);
       
  2181     $this->assertNoRaw($signature_text, 'Unfiltered signature text not found.');
       
  2182     $this->assertRaw(check_markup($signature_text, $this->plain_text_format->format), 'Filtered signature text found.');
       
  2183   }
       
  2184 }
       
  2185 
       
  2186 /*
       
  2187  * Test that a user, having editing their own account, can still log in.
       
  2188  */
       
  2189 class UserEditedOwnAccountTestCase extends DrupalWebTestCase {
       
  2190 
       
  2191   public static function getInfo() {
       
  2192     return array(
       
  2193       'name' => 'User edited own account',
       
  2194       'description' => 'Test user edited own account can still log in.',
       
  2195       'group' => 'User',
       
  2196     );
       
  2197   }
       
  2198 
       
  2199   function testUserEditedOwnAccount() {
       
  2200     // Change account setting 'Who can register accounts?' to Administrators
       
  2201     // only.
       
  2202     variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY);
       
  2203 
       
  2204     // Create a new user account and log in.
       
  2205     $account = $this->drupalCreateUser(array('change own username'));
       
  2206     $this->drupalLogin($account);
       
  2207 
       
  2208     // Change own username.
       
  2209     $edit = array();
       
  2210     $edit['name'] = $this->randomName();
       
  2211     $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save'));
       
  2212 
       
  2213     // Log out.
       
  2214     $this->drupalLogout();
       
  2215 
       
  2216     // Set the new name on the user account and attempt to log back in.
       
  2217     $account->name = $edit['name'];
       
  2218     $this->drupalLogin($account);
       
  2219   }
       
  2220 }
       
  2221 
       
  2222 /**
       
  2223  * Test case to test adding, editing and deleting roles.
       
  2224  */
       
  2225 class UserRoleAdminTestCase extends DrupalWebTestCase {
       
  2226 
       
  2227   public static function getInfo() {
       
  2228     return array(
       
  2229       'name' => 'User role administration',
       
  2230       'description' => 'Test adding, editing and deleting user roles and changing role weights.',
       
  2231       'group' => 'User',
       
  2232     );
       
  2233   }
       
  2234 
       
  2235   function setUp() {
       
  2236     parent::setUp();
       
  2237     $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
       
  2238   }
       
  2239 
       
  2240   /**
       
  2241    * Test adding, renaming and deleting roles.
       
  2242    */
       
  2243   function testRoleAdministration() {
       
  2244     $this->drupalLogin($this->admin_user);
       
  2245 
       
  2246     // Test adding a role. (In doing so, we use a role name that happens to
       
  2247     // correspond to an integer, to test that the role administration pages
       
  2248     // correctly distinguish between role names and IDs.)
       
  2249     $role_name = '123';
       
  2250     $edit = array('name' => $role_name);
       
  2251     $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
       
  2252     $this->assertText(t('The role has been added.'), 'The role has been added.');
       
  2253     $role = user_role_load_by_name($role_name);
       
  2254     $this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
       
  2255 
       
  2256     // Try adding a duplicate role.
       
  2257     $this->drupalPost(NULL, $edit, t('Add role'));
       
  2258     $this->assertRaw(t('The role name %name already exists. Choose another role name.', array('%name' => $role_name)), 'Duplicate role warning displayed.');
       
  2259 
       
  2260     // Test renaming a role.
       
  2261     $old_name = $role_name;
       
  2262     $role_name = '456';
       
  2263     $edit = array('name' => $role_name);
       
  2264     $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", $edit, t('Save role'));
       
  2265     $this->assertText(t('The role has been renamed.'), 'The role has been renamed.');
       
  2266     $this->assertFalse(user_role_load_by_name($old_name), 'The role can no longer be retrieved from the database using its old name.');
       
  2267     $this->assertTrue(is_object(user_role_load_by_name($role_name)), 'The role can be retrieved from the database using its new name.');
       
  2268 
       
  2269     // Test deleting the default administrator role.
       
  2270     $role_name = 'administrator';
       
  2271     $role = user_role_load_by_name($role_name);
       
  2272     $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", NULL, t('Delete role'));
       
  2273     $this->drupalPost(NULL, NULL, t('Delete'));
       
  2274     $this->assertText(t('The role has been deleted.'), 'The role has been deleted');
       
  2275     $this->assertNoLinkByHref("admin/people/permissions/roles/edit/{$role->rid}", 'Role edit link removed.');
       
  2276     $this->assertFalse(user_role_load_by_name($role_name), 'A deleted role can no longer be loaded.');
       
  2277     // Make sure this role is no longer configured as the administrator role.
       
  2278     $this->assertNull(variable_get('user_admin_role'), 'The administrator role is no longer configured as the administrator role.');
       
  2279 
       
  2280     // Make sure that the system-defined roles cannot be edited via the user
       
  2281     // interface.
       
  2282     $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_ANONYMOUS_RID);
       
  2283     $this->assertResponse(403, 'Access denied when trying to edit the built-in anonymous role.');
       
  2284     $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_AUTHENTICATED_RID);
       
  2285     $this->assertResponse(403, 'Access denied when trying to edit the built-in authenticated role.');
       
  2286   }
       
  2287 
       
  2288   /**
       
  2289    * Test user role weight change operation.
       
  2290    */
       
  2291   function testRoleWeightChange() {
       
  2292     $this->drupalLogin($this->admin_user);
       
  2293 
       
  2294     // Pick up a random role and get its weight.
       
  2295     $rid = array_rand(user_roles());
       
  2296     $role = user_role_load($rid);
       
  2297     $old_weight = $role->weight;
       
  2298 
       
  2299     // Change the role weight and submit the form.
       
  2300     $edit = array('roles['. $rid .'][weight]' => $old_weight + 1);
       
  2301     $this->drupalPost('admin/people/permissions/roles', $edit, t('Save order'));
       
  2302     $this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
       
  2303 
       
  2304     // Retrieve the saved role and compare its weight.
       
  2305     $role = user_role_load($rid);
       
  2306     $new_weight = $role->weight;
       
  2307     $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.');
       
  2308   }
       
  2309 }
       
  2310 
       
  2311 /**
       
  2312  * Test user token replacement in strings.
       
  2313  */
       
  2314 class UserTokenReplaceTestCase extends DrupalWebTestCase {
       
  2315   public static function getInfo() {
       
  2316     return array(
       
  2317       'name' => 'User token replacement',
       
  2318       'description' => 'Generates text using placeholders for dummy content to check user token replacement.',
       
  2319       'group' => 'User',
       
  2320     );
       
  2321   }
       
  2322 
       
  2323   /**
       
  2324    * Creates a user, then tests the tokens generated from it.
       
  2325    */
       
  2326   function testUserTokenReplacement() {
       
  2327     global $language;
       
  2328     $url_options = array(
       
  2329       'absolute' => TRUE,
       
  2330       'language' => $language,
       
  2331     );
       
  2332 
       
  2333     // Create two users and log them in one after another.
       
  2334     $user1 = $this->drupalCreateUser(array());
       
  2335     $user2 = $this->drupalCreateUser(array());
       
  2336     $this->drupalLogin($user1);
       
  2337     $this->drupalLogout();
       
  2338     $this->drupalLogin($user2);
       
  2339 
       
  2340     $account = user_load($user1->uid);
       
  2341     $global_account = user_load($GLOBALS['user']->uid);
       
  2342 
       
  2343     // Generate and test sanitized tokens.
       
  2344     $tests = array();
       
  2345     $tests['[user:uid]'] = $account->uid;
       
  2346     $tests['[user:name]'] = check_plain(format_username($account));
       
  2347     $tests['[user:mail]'] = check_plain($account->mail);
       
  2348     $tests['[user:url]'] = url("user/$account->uid", $url_options);
       
  2349     $tests['[user:edit-url]'] = url("user/$account->uid/edit", $url_options);
       
  2350     $tests['[user:last-login]'] = format_date($account->login, 'medium', '', NULL, $language->language);
       
  2351     $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language);
       
  2352     $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language);
       
  2353     $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language);
       
  2354     $tests['[current-user:name]'] = check_plain(format_username($global_account));
       
  2355 
       
  2356     // Test to make sure that we generated something for each token.
       
  2357     $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
       
  2358 
       
  2359     foreach ($tests as $input => $expected) {
       
  2360       $output = token_replace($input, array('user' => $account), array('language' => $language));
       
  2361       $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input)));
       
  2362     }
       
  2363 
       
  2364     // Generate and test unsanitized tokens.
       
  2365     $tests['[user:name]'] = format_username($account);
       
  2366     $tests['[user:mail]'] = $account->mail;
       
  2367     $tests['[current-user:name]'] = format_username($global_account);
       
  2368 
       
  2369     foreach ($tests as $input => $expected) {
       
  2370       $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
       
  2371       $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input)));
       
  2372     }
       
  2373   }
       
  2374 }
       
  2375 
       
  2376 /**
       
  2377  * Test user search.
       
  2378  */
       
  2379 class UserUserSearchTestCase extends DrupalWebTestCase {
       
  2380   public static function getInfo() {
       
  2381     return array(
       
  2382       'name' => 'User search',
       
  2383       'description' => 'Tests the user search page and verifies that sensitive information is hidden from unauthorized users.',
       
  2384       'group' => 'User',
       
  2385     );
       
  2386   }
       
  2387 
       
  2388   function testUserSearch() {
       
  2389     $user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search'));
       
  2390     $this->drupalLogin($user1);
       
  2391     $keys = $user1->mail;
       
  2392     $edit = array('keys' => $keys);
       
  2393     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2394     $this->assertNoText($keys);
       
  2395     $this->drupalLogout();
       
  2396 
       
  2397     $user2 = $this->drupalCreateUser(array('administer users', 'access user profiles', 'search content', 'use advanced search'));
       
  2398     $this->drupalLogin($user2);
       
  2399     $keys = $user2->mail;
       
  2400     $edit = array('keys' => $keys);
       
  2401     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2402     $this->assertText($keys);
       
  2403 
       
  2404     // Verify that wildcard search works.
       
  2405     $keys = $user1->name;
       
  2406     $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
       
  2407     $edit = array('keys' => $keys);
       
  2408     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2409     $this->assertText($user1->name, 'Search for username wildcard resulted in user name on page for administrative user.');
       
  2410 
       
  2411     // Verify that wildcard search works for email.
       
  2412     $keys = $user1->mail;
       
  2413     $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
       
  2414     $edit = array('keys' => $keys);
       
  2415     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2416     $this->assertText($user1->name, 'Search for email wildcard resulted in user name on page for administrative user.');
       
  2417 
       
  2418     // Create a blocked user.
       
  2419     $blocked_user = $this->drupalCreateUser();
       
  2420     $edit = array('status' => 0);
       
  2421     $blocked_user = user_save($blocked_user, $edit);
       
  2422 
       
  2423     // Verify that users with "administer users" permissions can see blocked
       
  2424     // accounts in search results.
       
  2425     $edit = array('keys' => $blocked_user->name);
       
  2426     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2427     $this->assertText($blocked_user->name, 'Blocked users are listed on the user search results for users with the "administer users" permission.');
       
  2428 
       
  2429     // Verify that users without "administer users" permissions do not see
       
  2430     // blocked accounts in search results.
       
  2431     $this->drupalLogin($user1);
       
  2432     $edit = array('keys' => $blocked_user->name);
       
  2433     $this->drupalPost('search/user/', $edit, t('Search'));
       
  2434     $this->assertNoText($blocked_user->name, 'Blocked users are hidden from the user search results.');
       
  2435 
       
  2436     $this->drupalLogout();
       
  2437   }
       
  2438 }
       
  2439 
       
  2440 /**
       
  2441  * Test role assignment.
       
  2442  */
       
  2443 class UserRolesAssignmentTestCase extends DrupalWebTestCase {
       
  2444   protected $admin_user;
       
  2445 
       
  2446   public static function getInfo() {
       
  2447     return array(
       
  2448       'name' => 'Role assignment',
       
  2449       'description' => 'Tests that users can be assigned and unassigned roles.',
       
  2450       'group' => 'User'
       
  2451     );
       
  2452   }
       
  2453 
       
  2454   function setUp() {
       
  2455     parent::setUp();
       
  2456     $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
       
  2457     $this->drupalLogin($this->admin_user);
       
  2458   }
       
  2459 
       
  2460   /**
       
  2461    * Tests that a user can be assigned a role and that the role can be removed
       
  2462    * again.
       
  2463    */
       
  2464   function testAssignAndRemoveRole()  {
       
  2465     $rid = $this->drupalCreateRole(array('administer content types'));
       
  2466     $account = $this->drupalCreateUser();
       
  2467 
       
  2468     // Assign the role to the user.
       
  2469     $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => $rid), t('Save'));
       
  2470     $this->assertText(t('The changes have been saved.'));
       
  2471     $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
       
  2472     $this->userLoadAndCheckRoleAssigned($account, $rid);
       
  2473 
       
  2474     // Remove the role from the user.
       
  2475     $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
       
  2476     $this->assertText(t('The changes have been saved.'));
       
  2477     $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
       
  2478     $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
       
  2479   }
       
  2480 
       
  2481   /**
       
  2482    * Tests that when creating a user the role can be assigned. And that it can
       
  2483    * be removed again.
       
  2484    */
       
  2485   function testCreateUserWithRole() {
       
  2486     $rid = $this->drupalCreateRole(array('administer content types'));
       
  2487     // Create a new user and add the role at the same time.
       
  2488     $edit = array(
       
  2489       'name' => $this->randomName(),
       
  2490       'mail' => $this->randomName() . '@example.com',
       
  2491       'pass[pass1]' => $pass = $this->randomString(),
       
  2492       'pass[pass2]' => $pass,
       
  2493       "roles[$rid]" => $rid,
       
  2494     );
       
  2495     $this->drupalPost('admin/people/create', $edit, t('Create new account'));
       
  2496     $this->assertText(t('Created a new user account for !name.', array('!name' => $edit['name'])));
       
  2497     // Get the newly added user.
       
  2498     $account = user_load_by_name($edit['name']);
       
  2499 
       
  2500     $this->drupalGet('user/' . $account->uid . '/edit');
       
  2501     $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
       
  2502     $this->userLoadAndCheckRoleAssigned($account, $rid);
       
  2503 
       
  2504     // Remove the role again.
       
  2505     $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
       
  2506     $this->assertText(t('The changes have been saved.'));
       
  2507     $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
       
  2508     $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
       
  2509   }
       
  2510 
       
  2511   /**
       
  2512    * Check role on user object.
       
  2513    *
       
  2514    * @param object $account
       
  2515    *   The user account to check.
       
  2516    * @param string $rid
       
  2517    *   The role ID to search for.
       
  2518    * @param bool $is_assigned
       
  2519    *   (optional) Whether to assert that $rid exists (TRUE) or not (FALSE).
       
  2520    *   Defaults to TRUE.
       
  2521    */
       
  2522   private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) {
       
  2523     $account = user_load($account->uid, TRUE);
       
  2524     if ($is_assigned) {
       
  2525       $this->assertTrue(array_key_exists($rid, $account->roles), 'The role is present in the user object.');
       
  2526     }
       
  2527     else {
       
  2528       $this->assertFalse(array_key_exists($rid, $account->roles), 'The role is not present in the user object.');
       
  2529     }
       
  2530   }
       
  2531 }
       
  2532 
       
  2533 
       
  2534 /**
       
  2535  * Unit test for authmap assignment.
       
  2536  */
       
  2537 class UserAuthmapAssignmentTestCase extends DrupalWebTestCase {
       
  2538   public static function getInfo() {
       
  2539     return array(
       
  2540       'name' => 'Authmap assignment',
       
  2541       'description' => 'Tests that users can be assigned and unassigned authmaps.',
       
  2542       'group' => 'User'
       
  2543     );
       
  2544   }
       
  2545 
       
  2546   /**
       
  2547    * Test authmap assignment and retrieval.
       
  2548    */
       
  2549   function testAuthmapAssignment()  {
       
  2550     $account = $this->drupalCreateUser();
       
  2551 
       
  2552     // Assign authmaps to the user.
       
  2553     $authmaps = array(
       
  2554       'authname_poll' => 'external username one',
       
  2555       'authname_book' => 'external username two',
       
  2556     );
       
  2557     user_set_authmaps($account, $authmaps);
       
  2558 
       
  2559     // Test for expected authmaps.
       
  2560     $expected_authmaps = array(
       
  2561       'external username one' => array(
       
  2562         'poll' => 'external username one',
       
  2563       ),
       
  2564       'external username two' => array(
       
  2565         'book' => 'external username two',
       
  2566       ),
       
  2567     );
       
  2568     foreach ($expected_authmaps as $authname => $expected_output) {
       
  2569       $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
       
  2570     }
       
  2571 
       
  2572     // Remove authmap for module poll, add authmap for module blog.
       
  2573     $authmaps = array(
       
  2574       'authname_poll' => NULL,
       
  2575       'authname_blog' => 'external username three',
       
  2576     );
       
  2577     user_set_authmaps($account, $authmaps);
       
  2578 
       
  2579     // Assert that external username one does not have authmaps.
       
  2580     $remove_username = 'external username one';
       
  2581     unset($expected_authmaps[$remove_username]);
       
  2582     $this->assertFalse(user_get_authmaps($remove_username), format_string('Authmap for %authname was removed.', array('%authname' => $remove_username)));
       
  2583 
       
  2584     // Assert that a new authmap was created for external username three, and
       
  2585     // existing authmaps for external username two were unchanged.
       
  2586     $expected_authmaps['external username three'] = array('blog' => 'external username three');
       
  2587     foreach ($expected_authmaps as $authname => $expected_output) {
       
  2588       $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
       
  2589     }
       
  2590   }
       
  2591 }
       
  2592 
       
  2593 /**
       
  2594  * Tests user_validate_current_pass on a custom form.
       
  2595  */
       
  2596 class UserValidateCurrentPassCustomForm extends DrupalWebTestCase {
       
  2597 
       
  2598   public static function getInfo() {
       
  2599     return array(
       
  2600       'name' => 'User validate current pass custom form',
       
  2601       'description' => 'Test that user_validate_current_pass is usable on a custom form.',
       
  2602       'group' => 'User',
       
  2603     );
       
  2604   }
       
  2605 
       
  2606   /**
       
  2607    * User with permission to view content.
       
  2608    */
       
  2609   protected $accessUser;
       
  2610 
       
  2611   /**
       
  2612    * User permission to administer users.
       
  2613    */
       
  2614   protected $adminUser;
       
  2615 
       
  2616   function setUp() {
       
  2617     parent::setUp('user_form_test');
       
  2618     // Create two users
       
  2619     $this->accessUser = $this->drupalCreateUser(array('access content'));
       
  2620     $this->adminUser = $this->drupalCreateUser(array('administer users'));
       
  2621   }
       
  2622 
       
  2623   /**
       
  2624    * Tests that user_validate_current_pass can be reused on a custom form.
       
  2625    */
       
  2626   function testUserValidateCurrentPassCustomForm() {
       
  2627     $this->drupalLogin($this->adminUser);
       
  2628 
       
  2629     // Submit the custom form with the admin user using the access user's password.
       
  2630     $edit = array();
       
  2631     $edit['user_form_test_field'] = $this->accessUser->name;
       
  2632     $edit['current_pass'] = $this->accessUser->pass_raw;
       
  2633     $this->drupalPost('user_form_test_current_password/' . $this->accessUser->uid, $edit, t('Test'));
       
  2634     $this->assertText(t('The password has been validated and the form submitted successfully.'));
       
  2635   }
       
  2636 }