New tests for LanguageConverter->getPreferredVariant()

Refactor getPreferredVariant, new function getHeaderVariant()
New function (FauxRequest::setHeader()) to help with testing.
This commit is contained in:
Mark A. Hershberger 2010-01-06 03:50:59 +00:00
parent 9ef63ede49
commit dcdc0f4dc7
5 changed files with 242 additions and 79 deletions

View file

@ -762,6 +762,10 @@ class FauxRequest extends WebRequest {
return isset( $this->headers[$name] ) ? $this->headers[$name] : false;
}
public function setHeader( $name, $val ) {
$this->headers[$name] = $val;
}
public function getSessionData( $key ) {
if( !isset( $this->session[$key] ) )
return null;

View file

@ -16,7 +16,7 @@
* @maintainers fdcn <fdcn64@gmail.com>, shinjiman <shinjiman@gmail.com>, PhiLiP <philip.npc@gmail.com>
*/
class LanguageConverter {
var $mPreferredVariant = '';
var $mPreferredVariant = ''; // The User's preferred variant
var $mMainLanguageCode;
var $mVariants, $mVariantFallbacks, $mVariantNames;
var $mTablesLoaded = false;
@ -34,6 +34,7 @@ class LanguageConverter {
var $mUcfirst = false;
var $mTitleOriginal = '';
var $mTitleDisplay = '';
var $mHeaderVariant = null;
const CACHE_VERSION_KEY = 'VERSION 6';
@ -142,29 +143,6 @@ class LanguageConverter {
global $wgUser, $wgRequest, $wgVariantArticlePath,
$wgDefaultLanguageVariant, $wgOut;
// bug 21974, don't return $this->mPreferredVariant if $fromUser = false
if ( $fromUser && $this->mPreferredVariant ) {
return $this->mPreferredVariant;
}
// figure out user lang without constructing wgLang to avoid
// infinite recursion
if ( $fromUser ) {
$defaultUserLang = $wgUser->getOption( 'language' );
} else {
$defaultUserLang = $this->mMainLanguageCode;
}
$userLang = $wgRequest->getVal( 'uselang', $defaultUserLang );
// see if interface language is same as content, if not, prevent
// conversion
if ( ! in_array( $userLang, $this->mVariants ) ) {
// no conversion
$this->mPreferredVariant = $this->mMainLanguageCode;
return $this->mPreferredVariant;
}
// see if the preference is set in the request
$req = $wgRequest->getText( 'variant' );
if ( in_array( $req, $this->mVariants ) ) {
@ -172,11 +150,38 @@ class LanguageConverter {
return $this->mPreferredVariant;
}
// get language variant preference from logged in users
// Don't call this on stub objects because that causes infinite
// recursion during initialisation
if ( $fromUser && $wgUser->isLoggedIn() ) {
$this->mPreferredVariant = $wgUser->getOption( 'variant' );
if ( $fromUser ) {
// bug 21974, don't return $this->mPreferredVariant if
// $fromUser = false
if ( $this->mPreferredVariant ) {
return $this->mPreferredVariant;
}
// figure out user lang without constructing wgLang to avoid
// infinite recursion
$defaultUserLang = $wgUser->getOption( 'language' );
// get language variant preference from logged in users
// Don't call this on stub objects because that causes infinite
// recursion during initialisation
if ( $wgUser->isLoggedIn() ) {
$this->mPreferredVariant = $wgUser->getOption( 'variant' );
}
} else {
$defaultUserLang = $this->mMainLanguageCode;
}
$userLang = $wgRequest->getVal( 'uselang', $defaultUserLang );
// see if interface language is same as content, if not, prevent
// conversion
if ( ! in_array( $userLang, $this->mVariants ) ) {
// no conversion
$this->mPreferredVariant = $this->mMainLanguageCode;
return $this->mPreferredVariant;
} elseif ( $this->mPreferredVariant ) {
// if the variant was set above and it iss a variant of
// the content language
return $this->mPreferredVariant;
}
@ -187,60 +192,81 @@ class LanguageConverter {
return $this->mPreferredVariant;
}
if ( !$this->mPreferredVariant ) {
// see if some supported language variant is set in the
// http header, but we don't set the mPreferredVariant
// variable in case this is called before the user's
// preference is loaded
$headerVariant = $this->getHeaderVariant();
if ( $fromHeader && $headerVariant ) {
return $headerVariant;
}
$acceptLanguage = $wgRequest->getHeader( 'Accept-Language' );
if ( $fromHeader && $acceptLanguage ) {
// explode by comma
$result = explode( ',', strtolower( $acceptLanguage ) );
return $this->mMainLanguageCode;
}
$languages = array();
/**
* Determine the language variant from the Accept-Language header.
*
* @returns mixed variant if one found, false otherwise.
*/
function getHeaderVariant() {
global $wgRequest;
foreach ( $result as $elem ) {
// if $elem likes 'zh-cn;q=0.9'
if ( ( $posi = strpos( $elem, ';' ) ) !== false ) {
// get the real language code likes 'zh-cn'
$languages[] = substr( $elem, 0, $posi );
} else {
$languages[] = $elem;
}
}
if ( $this->mHeaderVariant ) {
return $this->mHeaderVariant;
}
$fallback_languages = array();
foreach ( $languages as $language ) {
// strip whitespace
$language = trim( $language );
if ( in_array( $language, $this->mVariants ) ) {
return $language;
} else {
// To see if there are fallbacks of current language.
// We record these fallback variants, and process
// them later.
$fallbacks = $this->getVariantFallbacks( $language );
if ( is_string( $fallbacks ) ) {
$fallback_languages[] = $fallbacks;
} elseif ( is_array( $fallbacks ) ) {
$fallback_languages =
array_merge( $fallback_languages,
$fallbacks );
}
}
}
// see if some supported language variant is set in the
// http header, but we don't set the mPreferredVariant
// variable in case this is called before the user's
// preference is loaded
// process fallback languages now
$fallback_languages = array_unique( $fallback_languages );
foreach ( $fallback_languages as $language ) {
if ( in_array( $language, $this->mVariants ) ) {
return $language;
}
$acceptLanguage = $wgRequest->getHeader( 'Accept-Language' );
if ( !$acceptLanguage ) {
return false;
}
// explode by comma
$result = explode( ',', strtolower( $acceptLanguage ) );
$languages = array();
foreach ( $result as $elem ) {
// if $elem likes 'zh-cn;q=0.9'
if ( ( $posi = strpos( $elem, ';' ) ) !== false ) {
// get the real language code likes 'zh-cn'
$languages[] = substr( $elem, 0, $posi );
} else {
$languages[] = $elem;
}
}
$fallback_languages = array();
foreach ( $languages as $language ) {
// strip whitespace
$language = trim( $language );
if ( in_array( $language, $this->mVariants ) ) {
$this->mHeaderVariant = $language;
return $language;
} else {
// To see if there are fallbacks of current language.
// We record these fallback variants, and process
// them later.
$fallbacks = $this->getVariantFallbacks( $language );
if ( is_string( $fallbacks ) ) {
$fallback_languages[] = $fallbacks;
} elseif ( is_array( $fallbacks ) ) {
$fallback_languages =
array_merge( $fallback_languages,
$fallbacks );
}
}
}
return $this->mMainLanguageCode;
// process fallback languages now
$fallback_languages = array_unique( $fallback_languages );
foreach ( $fallback_languages as $language ) {
if ( in_array( $language, $this->mVariants ) ) {
$this->mHeaderVariant = $language;
return $language;
}
}
}
/**

View file

@ -4,6 +4,8 @@ class ArticleTest extends PHPUnit_Framework_TestCase {
var $saveGlobals = array();
function setUp() {
global $wgContLang;
$wgContLang = Language::factory( 'en' );
$globalSet = array(
'wgLegacyEncoding' => false,
'wgCompressRevisions' => false,

View file

@ -0,0 +1,121 @@
<?php
class LanguageConverterTest extends PHPUnit_Framework_TestCase {
protected $lang = null;
protected $lc = null;
function setUp() {
$this->lang = new LanguageTest();
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
}
function tearDown() {
unset($this->lc);
unset($this->lang);
}
function testGetPreferredVariant() {
global $wgRequest, $wgUsePathInfo, $wgLanguageCode,
$wgVariantArticlePath, $wgUser, $wgContLang,
$wgDefaultLanguageVariant;
$wgRequest = new FauxRequest(array());
$wgUser = new User;
$wgContLang = Language::factory( 'tg-latn' );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
$wgRequest->setHeader('Accept-Language', 'tg-latn');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
$wgRequest->setHeader('Accept-Language', 'tg;q=1');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
$wgRequest->setHeader('Accept-Language', 'tg-latn;q=1');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
$wgRequest->setHeader('Accept-Language', 'en, tg-latn;q=1');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
$wgRequest->setHeader('Accept-Language', '');
$wgUser = User::newFromId("admin");
$wgContLang = Language::factory( 'tg-latn' );
$wgUser->setId(1);
$wgUser->setOption('variant', 'tg-latn');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
$wgRequest->setVal('variant', 'tg');
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
$wgRequest->setVal('variant', null);
$wgDefaultLanguageVariant = 'tg-latn';
$this->lc = new TestConverter( $this->lang, 'tg',
array( 'tg', 'tg-latn' ) );
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false));
$this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
}
}
/**
* Test converter (from Tajiki to latin orthography)
*/
class TestConverter extends LanguageConverter {
private $table = array(
'б' => 'b',
'в' => 'v',
'г' => 'g',
);
function loadDefaultTables() {
$this->mTables = array(
'tg-latn' => new ReplacementArray( $this->table ),
'tg' => new ReplacementArray()
);
}
}
class LanguageTest extends Language {
function __construct() {
parent::__construct();
$variants = array( 'tg', 'tg-latn' );
$this->mConverter = new TestConverter( $this, 'tg', $variants );
}
}

View file

@ -1,8 +1,18 @@
<?php
$IP = realpath(dirname( __FILE__ ) . '/..');
global $wgCommandLineMode, $IP, $wgMemc;
$wgCommandLineMode = true;
define('MEDIAWIKI', 1);
global $optionsWithArgs;
$optionsWithArgs = array();
require_once( '../maintenance/commandLine.inc' );
require dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR."LocalSettings.php";
require "Defines.php";
require "ProfilerStub.php";
require 'GlobalFunctions.php';
require 'Hooks.php';
require "AutoLoader.php";
require 'ProxyTools.php';
require 'ObjectCache.php';
require 'ImageFunctions.php';
$wgMemc =& wfGetMainCache();