minor #14437 [2.6][Translator] Extend, refactor and simplify Translator tests. (mpdude)
This PR was squashed before being merged into the 2.6 branch (closes #14437).
Discussion
----------
[2.6][Translator] Extend, refactor and simplify Translator tests.
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Fixed tickets | ~
| Tests pass? | yes
| License | MIT
These are the improvements from #14291 that we can easily backport to the 2.6 branch as requested [here](https://github.com/symfony/symfony/pull/14291#issuecomment-94863733).
Commits
-------
a8c4471
[2.6][Translator] Extend, refactor and simplify Translator tests.
This commit is contained in:
commit
386f7332c9
@ -11,10 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageSelector;
|
||||
|
||||
class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -51,91 +52,107 @@ class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
|
||||
rmdir($this->tmpDir);
|
||||
}
|
||||
|
||||
public function testTransWithoutCaching()
|
||||
/**
|
||||
* @dataProvider runForDebugAndProduction
|
||||
*/
|
||||
public function testThatACacheIsUsed($debug)
|
||||
{
|
||||
$translator = $this->getTranslator($this->getLoader());
|
||||
$translator->setLocale('fr');
|
||||
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
$this->assertEquals('foo (FR)', $translator->trans('foo'));
|
||||
$this->assertEquals('bar (EN)', $translator->trans('bar'));
|
||||
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
|
||||
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
|
||||
$this->assertEquals('no translation', $translator->trans('no translation'));
|
||||
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
|
||||
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
|
||||
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
|
||||
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
|
||||
// Prime the cache
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// Try again and see we get a valid result whilst no loader can be used
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, $this->createFailingLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$this->assertEquals('OK', $translator->trans($msgid), '-> caching does not work in '.($debug ? 'debug' : 'production'));
|
||||
}
|
||||
|
||||
public function testTransWithCaching()
|
||||
public function testCatalogueIsReloadedWhenResourcesAreNoLongerFresh()
|
||||
{
|
||||
// prime the cache
|
||||
$translator = $this->getTranslator($this->getLoader(), $this->tmpDir);
|
||||
$translator->setLocale('fr');
|
||||
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
|
||||
/*
|
||||
* The testThatACacheIsUsed() test showed that we don't need the loader as long as the cache
|
||||
* is fresh.
|
||||
*
|
||||
* Now we add a Resource that is never fresh and make sure that the
|
||||
* cache is discarded (the loader is called twice).
|
||||
*
|
||||
* We need to run this for debug=true only because in production the cache
|
||||
* will never be revalidated.
|
||||
*/
|
||||
|
||||
$this->assertEquals('foo (FR)', $translator->trans('foo'));
|
||||
$this->assertEquals('bar (EN)', $translator->trans('bar'));
|
||||
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
|
||||
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
|
||||
$this->assertEquals('no translation', $translator->trans('no translation'));
|
||||
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
|
||||
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
|
||||
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
|
||||
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
// do it another time as the cache is primed now
|
||||
$catalogue = new MessageCatalogue($locale, array());
|
||||
$catalogue->addResource(new StaleResource()); // better use a helper class than a mock, because it gets serialized in the cache and re-loaded
|
||||
|
||||
/** @var LoaderInterface|\PHPUnit_Framework_MockObject_MockObject $loader */
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$translator = $this->getTranslator($loader, $this->tmpDir);
|
||||
$translator->setLocale('fr');
|
||||
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
|
||||
$loader
|
||||
->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->will($this->returnValue($catalogue))
|
||||
;
|
||||
|
||||
$this->assertEquals('foo (FR)', $translator->trans('foo'));
|
||||
$this->assertEquals('bar (EN)', $translator->trans('bar'));
|
||||
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
|
||||
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
|
||||
$this->assertEquals('no translation', $translator->trans('no translation'));
|
||||
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
|
||||
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
|
||||
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
|
||||
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
|
||||
// 1st pass
|
||||
$translator = new Translator($locale, null, $this->tmpDir, true);
|
||||
$translator->addLoader($format, $loader);
|
||||
$translator->addResource($format, null, $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// 2nd pass
|
||||
$translator = new Translator($locale, null, $this->tmpDir, true);
|
||||
$translator->addLoader($format, $loader);
|
||||
$translator->addResource($format, null, $locale);
|
||||
$translator->trans($msgid);
|
||||
}
|
||||
|
||||
public function testTransWithCachingWithInvalidLocale()
|
||||
/**
|
||||
* @dataProvider runForDebugAndProduction
|
||||
*/
|
||||
public function testDifferentTranslatorsForSameLocaleDoNotOverwriteEachOthersCache($debug)
|
||||
{
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$translator = $this->getTranslator($loader, $this->tmpDir, 'Symfony\Component\Translation\Tests\TranslatorWithInvalidLocale');
|
||||
/*
|
||||
* Similar to the previous test. After we used the second translator, make
|
||||
* sure there's still a useable cache for the first one.
|
||||
*/
|
||||
|
||||
$translator->setLocale('invalid locale');
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
try {
|
||||
$translator->trans('foo');
|
||||
$this->fail();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/catalogue.invalid locale.php'));
|
||||
}
|
||||
}
|
||||
// Create a Translator and prime its cache
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
public function testLoadCatalogueWithCachingWithInvalidLocale()
|
||||
{
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$translator = $this->getTranslator($loader, $this->tmpDir, 'Symfony\Component\Translation\Tests\TranslatorWithInvalidLocale');
|
||||
// Create another Translator with a different catalogue for the same locale
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'FAIL'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
try {
|
||||
$translator->proxyLoadCatalogue('invalid locale');
|
||||
$this->fail();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/catalogue.invalid locale.php'));
|
||||
}
|
||||
// Now the first translator must still have a useable cache.
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, $this->createFailingLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$this->assertEquals('OK', $translator->trans($msgid), '-> the cache was overwritten by another translator instance in '.($debug ? 'debug' : 'production'));
|
||||
}
|
||||
|
||||
public function testDifferentCacheFilesAreUsedForDifferentSetsOfFallbackLocales()
|
||||
{
|
||||
/*
|
||||
* Because the cache file contains a catalogue including all of its fallback
|
||||
* catalogues (either "inlined" in Symfony 2.7 production or "standalone"),
|
||||
* we must take the active set of fallback locales into consideration when
|
||||
* catalogues, we must take the set of fallback locales into consideration when
|
||||
* loading a catalogue from the cache.
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
@ -161,6 +178,54 @@ class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('bar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
public function testPrimaryAndFallbackCataloguesContainTheSameMessagesRegardlessOfCaching()
|
||||
{
|
||||
/*
|
||||
* As a safeguard against potential BC breaks, make sure that primary and fallback
|
||||
* catalogues (reachable via getFallbackCatalogue()) always contain the full set of
|
||||
* messages provided by the loader. This must also be the case when these catalogues
|
||||
* are (internally) read from a cache.
|
||||
*
|
||||
* Optimizations inside the translator must not change this behaviour.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a translator that loads two catalogues for two different locales.
|
||||
* The catalogues contain distinct sets of messages.
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('foo' => 'foo (b)'), 'b');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$catalogue = $translator->getCatalogue('a');
|
||||
$this->assertFalse($catalogue->defines('bar')); // Sure, the "a" catalogue does not contain that message.
|
||||
|
||||
$fallback = $catalogue->getFallbackCatalogue();
|
||||
$this->assertTrue($fallback->defines('foo')); // "foo" is present in "a" and "b"
|
||||
|
||||
/*
|
||||
* Now, repeat the same test.
|
||||
* Behind the scenes, the cache is used. But that should not matter, right?
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('foo' => 'foo (b)'), 'b');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$catalogue = $translator->getCatalogue('a');
|
||||
$this->assertFalse($catalogue->defines('bar'));
|
||||
|
||||
$fallback = $catalogue->getFallbackCatalogue();
|
||||
$this->assertTrue($fallback->defines('foo'));
|
||||
}
|
||||
|
||||
public function testRefreshCacheWhenResourcesAreNoLongerFresh()
|
||||
{
|
||||
$resource = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
@ -197,93 +262,38 @@ class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
protected function getLoader()
|
||||
public function runForDebugAndProduction()
|
||||
{
|
||||
return array(array(true), array(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoaderInterface
|
||||
*/
|
||||
private function createFailingLoader()
|
||||
{
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$loader
|
||||
->expects($this->at(0))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('fr', array(
|
||||
'foo' => 'foo (FR)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(1))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('en', array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
'choice' => '{0} choice 0 (EN)|{1} choice 1 (EN)|]1,Inf] choice inf (EN)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(2))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('es', array(
|
||||
'foobar' => 'foobar (ES)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(3))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('pt-PT', array(
|
||||
'foobarfoo' => 'foobarfoo (PT-PT)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(4))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('pt_BR', array(
|
||||
'other choice' => '{0} other choice 0 (PT-BR)|{1} other choice 1 (PT-BR)|]1,Inf] other choice inf (PT-BR)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(5))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('fr.UTF-8', array(
|
||||
'foobarbaz' => 'foobarbaz (fr.UTF-8)',
|
||||
))))
|
||||
;
|
||||
$loader
|
||||
->expects($this->at(6))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('sr@latin', array(
|
||||
'foobarbax' => 'foobarbax (sr@latin)',
|
||||
))))
|
||||
;
|
||||
->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
return $loader;
|
||||
}
|
||||
|
||||
public function getTranslator($loader, $cacheDir = null, $translatorClass = '\Symfony\Component\Translation\Translator')
|
||||
{
|
||||
$translator = new $translatorClass('fr', new MessageSelector(), $cacheDir);
|
||||
|
||||
$translator->addLoader('loader', $loader);
|
||||
$translator->addResource('loader', 'foo', 'fr');
|
||||
$translator->addResource('loader', 'foo', 'en');
|
||||
$translator->addResource('loader', 'foo', 'es');
|
||||
$translator->addResource('loader', 'foo', 'pt-PT'); // European Portuguese
|
||||
$translator->addResource('loader', 'foo', 'pt_BR'); // Brazilian Portuguese
|
||||
$translator->addResource('loader', 'foo', 'fr.UTF-8');
|
||||
$translator->addResource('loader', 'foo', 'sr@latin'); // Latin Serbian
|
||||
|
||||
return $translator;
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatorWithInvalidLocale extends Translator
|
||||
class StaleResource implements ResourceInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
$this->locale = $locale;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function proxyLoadCatalogue($locale)
|
||||
public function getResource()
|
||||
{
|
||||
$this->loadCatalogue($locale);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,30 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(new MessageCatalogue('fr'), $translator->getCatalogue('fr'));
|
||||
}
|
||||
|
||||
public function testGetCatalogueReturnsConsolidatedCatalogue()
|
||||
{
|
||||
/*
|
||||
* This will be useful once we refactor so that different domains will be loaded lazily (on-demand).
|
||||
* In that case, getCatalogue() will probably have to load all missing domains in order to return
|
||||
* one complete catalogue.
|
||||
*/
|
||||
|
||||
$locale = 'whatever';
|
||||
$translator = new Translator($locale);
|
||||
$translator->addLoader('loader-a', new ArrayLoader());
|
||||
$translator->addLoader('loader-b', new ArrayLoader());
|
||||
$translator->addResource('loader-a', array('foo' => 'foofoo'), $locale, 'domain-a');
|
||||
$translator->addResource('loader-b', array('bar' => 'foobar'), $locale, 'domain-b');
|
||||
|
||||
/*
|
||||
* Test that we get a single catalogue comprising messages
|
||||
* from different loaders and different domains
|
||||
*/
|
||||
$catalogue = $translator->getCatalogue($locale);
|
||||
$this->assertTrue($catalogue->defines('foo', 'domain-a'));
|
||||
$this->assertTrue($catalogue->defines('bar', 'domain-b'));
|
||||
}
|
||||
|
||||
public function testSetFallbackLocales()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
@ -136,12 +160,11 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
public function testTransWithFallbackLocale()
|
||||
{
|
||||
$translator = new Translator('fr_FR');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'en');
|
||||
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'en');
|
||||
|
||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
@ -280,12 +303,12 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testTransValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en', new MessageSelector());
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
$translator->addResource('array', array('test' => 'OK'), $locale);
|
||||
|
||||
$translator->trans('foo', array(), '', $locale);
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
$this->assertEquals('OK', $translator->trans('test'));
|
||||
$this->assertEquals('OK', $translator->trans('test', array(), null, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user