From dcdc0f4dc7d0126c3c1a06efee68f142340c7a59 Mon Sep 17 00:00:00 2001 From: "Mark A. Hershberger" Date: Wed, 6 Jan 2010 03:50:59 +0000 Subject: [PATCH] New tests for LanguageConverter->getPreferredVariant() Refactor getPreferredVariant, new function getHeaderVariant() New function (FauxRequest::setHeader()) to help with testing. --- includes/WebRequest.php | 4 + languages/LanguageConverter.php | 162 ++++++++++++++++++-------------- tests/ArticleTest.php | 2 + tests/LanguageConverterTest.php | 121 ++++++++++++++++++++++++ tests/bootstrap.php | 18 +++- 5 files changed, 235 insertions(+), 72 deletions(-) create mode 100644 tests/LanguageConverterTest.php diff --git a/includes/WebRequest.php b/includes/WebRequest.php index 15126a3088..8b68434fd6 100644 --- a/includes/WebRequest.php +++ b/includes/WebRequest.php @@ -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; diff --git a/languages/LanguageConverter.php b/languages/LanguageConverter.php index 6b54d99238..ad667890be 100644 --- a/languages/LanguageConverter.php +++ b/languages/LanguageConverter.php @@ -16,7 +16,7 @@ * @maintainers fdcn , shinjiman , PhiLiP */ 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,41 +143,45 @@ class LanguageConverter { global $wgUser, $wgRequest, $wgVariantArticlePath, $wgDefaultLanguageVariant, $wgOut; - // bug 21974, don't return $this->mPreferredVariant if $fromUser = false - if ( $fromUser && $this->mPreferredVariant ) { + // see if the preference is set in the request + $req = $wgRequest->getText( 'variant' ); + if ( in_array( $req, $this->mVariants ) ) { + $this->mPreferredVariant = $req; return $this->mPreferredVariant; } - // figure out user lang without constructing wgLang to avoid - // infinite recursion - if ( $fromUser ) { + 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; - } - - // see if the preference is set in the request - $req = $wgRequest->getText( 'variant' ); - if ( in_array( $req, $this->mVariants ) ) { - $this->mPreferredVariant = $req; - 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' ); + } 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; + } + } } /** diff --git a/tests/ArticleTest.php b/tests/ArticleTest.php index f36b0262a2..9025b7459b 100644 --- a/tests/ArticleTest.php +++ b/tests/ArticleTest.php @@ -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, diff --git a/tests/LanguageConverterTest.php b/tests/LanguageConverterTest.php new file mode 100644 index 0000000000..bdf43a6b3d --- /dev/null +++ b/tests/LanguageConverterTest.php @@ -0,0 +1,121 @@ +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 ); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 234d01c4c8..c879d037b4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,8 +1,18 @@