);
}
+ /**
+ * @dataProvider provideIPs
+ * @covers User::isIP
+ */
+ public function testIsIP( $value, $result, $message ) {
+ $this->assertEquals( $this->user->isIP( $value ), $result, $message );
+ }
+
+ public static function provideIPs() {
+ return array(
+ array( '', false, 'Empty string' ),
+ array( ' ', false, 'Blank space' ),
+ array( '10.0.0.0', true, 'IPv4 private 10/8' ),
+ array( '10.255.255.255', true, 'IPv4 private 10/8' ),
+ array( '192.168.1.1', true, 'IPv4 private 192.168/16' ),
+ array( '203.0.113.0', true, 'IPv4 example' ),
+ array( '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff', true, 'IPv6 example' ),
+ // Not valid IPs but classified as such by MediaWiki for negated asserting
+ // of whether this might be the identifier of a logged-out user or whether
+ // to allow usernames like it.
+ array( '300.300.300.300', true, 'Looks too much like an IPv4 address' ),
+ array( '203.0.113.xxx', true, 'Assigned by UseMod to cloaked logged-out users' ),
+ );
+ }
+
/**
* @dataProvider provideUserNames
* @covers User::isValidUserName
array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
array( 'ജോസ്തോമസ്', false, 'ZWNJ- Format control character' ),
array( 'Ab cd', false, ' Ideographic space' ),
+ array( '300.300.300.300', false, 'Looks too much like an IPv4 address' ),
+ array( '302.113.311.900', false, 'Looks too much like an IPv4 address' ),
+ array( '203.0.113.xxx', false, 'Reserved for usage by UseMod for cloaked logged-out users' ),
);
}
* Extensions and core
*/
public function testAllRightsWithMessage() {
- //Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
+ // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
$allRights = User::getAllRights();
$allMessageKeys = Language::getMessageKeysFor( 'en' );
}
$user->clearInstanceCache();
- $this->assertEquals( 3, $user->getEditCount(), 'After three edits, the user edit count should be 3' );
+ $this->assertEquals(
+ 3,
+ $user->getEditCount(),
+ 'After three edits, the user edit count should be 3'
+ );
// increase the edit count and clear the cache
$user->incEditCount();
$user->clearInstanceCache();
- $this->assertEquals( 4, $user->getEditCount(), 'After increasing the edit count manually, the user edit count should be 4' );
+ $this->assertEquals(
+ 4,
+ $user->getEditCount(),
+ 'After increasing the edit count manually, the user edit count should be 4'
+ );
}
/**
}
/**
- * Helper, fetch user properties from the database.
- * @param int $userId
+ * Test password expiration.
+ * @covers User::getPasswordExpired()
*/
- function dbUserProperties( $userId ) {
- $res = wfGetDB( DB_SLAVE )->select(
- 'user_properties',
- array( 'up_property', 'up_value' ),
- array( 'up_user' => $userId ),
- __METHOD__
- );
- $ret = array();
- foreach( $res as $row ) {
- $ret[$row->up_property] = $row->up_value;
- }
- return $ret;
- }
+ public function testPasswordExpire() {
+ global $wgPasswordExpireGrace;
+ $wgTemp = $wgPasswordExpireGrace;
+ $wgPasswordExpireGrace = 3600 * 24 * 7; // 7 days
- public function testOnlySaveChangedOptions() {
- $user = User::newFromName( 'UnitTestUser2' );
- $user->addToDatabase();
+ $user = User::newFromName( 'UnitTestUser' );
+ $user->loadDefaults();
+ $this->assertEquals( false, $user->getPasswordExpired() );
- // Fresh user only has default, so nothing should be in the DB
- $dbProps = $this->dbUserProperties( $user->getId() );
- $this->assertEmpty( $dbProps,
- "A new user should not have any user property saved in the DB" );
+ $ts = time() - ( 3600 * 24 * 1 ); // 1 day ago
+ $user->expirePassword( $ts );
+ $this->assertEquals( 'soft', $user->getPasswordExpired() );
- // Make sure we only save the altered option
- $user->setOption( 'changed_opt', 'alix_20281' );
- $user->setOption( 'switch', 1 );
- $user->setOption( 'anotherswitch', 1 );
- $user->saveSettings();
+ $ts = time() - ( 3600 * 24 * 10 ); // 10 days ago
+ $user->expirePassword( $ts );
+ $this->assertEquals( 'hard', $user->getPasswordExpired() );
- $expected = array (
- 'changed_opt' => 'alix_20281',
- 'switch' => '1',
- 'anotherswitch' => '1',
- );
- $dbProps = $this->dbUserProperties( $user->getId() );
+ $wgPasswordExpireGrace = $wgTemp;
+ }
+
+ /**
+ * Test password validity checks. There are 3 checks in core,
+ * - ensure the password meets the minimal length
+ * - ensure the password is not the same as the username
+ * - ensure the username/password combo isn't forbidden
+ * @covers User::checkPasswordValidity()
+ * @covers User::getPasswordValidity()
+ * @covers User::isValidPassword()
+ */
+ public function testCheckPasswordValidity() {
+ $this->setMwGlobals( 'wgMinimalPasswordLength', 6 );
+ $user = User::newFromName( 'Useruser' );
+ // Sanity
+ $this->assertTrue( $user->isValidPassword( 'Password1234' ) );
+
+ // Minimum length
+ $this->assertFalse( $user->isValidPassword( 'a' ) );
+ $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
+ $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
+
+ // Matches username
+ $this->assertFalse( $user->checkPasswordValidity( 'Useruser' )->isGood() );
+ $this->assertEquals( 'password-name-match', $user->getPasswordValidity( 'Useruser' ) );
+
+ // On the forbidden list
+ $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
+ $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
+ }
- $this->assertEquals( $expected, $dbProps,
- "non default options should be saved, and default ones should not" );
+ /**
+ * @covers User::getCanonicalName()
+ * @dataProvider provideGetCanonicalName
+ */
+ public function testGetCanonicalName( $name, $expectedArray, $msg ) {
+ foreach ( $expectedArray as $validate => $expected ) {
+ $this->assertEquals(
+ User::getCanonicalName( $name, $validate === 'false' ? false : $validate ),
+ $expected,
+ $msg . ' (' . $validate . ')'
+ );
+ }
+ }
+ public function provideGetCanonicalName() {
+ return array(
+ array( ' trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
+ // @todo FIXME: Maybe the createable name should be 'Talk:Username' or false to reject?
+ array( 'Talk:Username', array( 'creatable' => 'Username', 'usable' => 'Username',
+ 'valid' => 'Username', 'false' => 'Talk:Username' ), 'Namespace prefix' ),
+ array( ' name with # hash', array( 'creatable' => false, 'usable' => false ), 'With hash' ),
+ array( 'Multi spaces', array( 'creatable' => 'Multi spaces',
+ 'usable' => 'Multi spaces' ), 'Multi spaces' ),
+ array( 'lowercase', array( 'creatable' => 'Lowercase' ), 'Lowercase' ),
+ array( 'in[]valid', array( 'creatable' => false, 'usable' => false, 'valid' => false,
+ 'false' => 'In[]valid' ), 'Invalid' ),
+ array( 'with / slash', array( 'creatable' => false, 'usable' => false, 'valid' => false,
+ 'false' => 'With / slash' ), 'With slash' ),
+ );
}
}