diff --git a/application/transaction.class.inc.php b/application/transaction.class.inc.php index 2986308f8..5a65c1c0f 100644 --- a/application/transaction.class.inc.php +++ b/application/transaction.class.inc.php @@ -196,16 +196,19 @@ class privUITransactionSession */ class privUITransactionFile { + /** @var int Value to use when no user logged */ + const UNAUTHENTICATED_USER_ID = -666; + /** - * @return int - * @throws \SecurityException if no connected user + * @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged * * @since 2.6.5 2.7.6 3.0.0 N°4289 method creation */ - private static function GetCurrentUserId() { + private static function GetCurrentUserId() + { $iCurrentUserId = UserRights::GetConnectedUserId(); if ('' === $iCurrentUserId) { - throw new SecurityException('Cannot creation transaction_id when no user logged'); + $iCurrentUserId = static::UNAUTHENTICATED_USER_ID; } return $iCurrentUserId; diff --git a/core/apc-service.class.inc.php b/core/apc-service.class.inc.php new file mode 100644 index 000000000..ca541eb84 --- /dev/null +++ b/core/apc-service.class.inc.php @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/core/dict.class.inc.php b/core/dict.class.inc.php index eb10f188b..8bbf7afb4 100644 --- a/core/dict.class.inc.php +++ b/core/dict.class.inc.php @@ -35,6 +35,8 @@ class Dict protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...) protected static $m_aData = array(); protected static $m_sApplicationPrefix = null; + /** @var \ApcService $m_oApcService */ + protected static $m_oApcService = null; /** * @param $sLanguageCode @@ -116,15 +118,17 @@ class Dict { // Attempt to find the string in the user language // - self::InitLangIfNeeded(self::GetUserLanguage()); + $sLangCode = self::GetUserLanguage(); + self::InitLangIfNeeded($sLangCode); - if (!array_key_exists(self::GetUserLanguage(), self::$m_aData)) + if (!array_key_exists($sLangCode, self::$m_aData)) { + IssueLog::Warning("Cannot find $sLangCode in dictionnaries. default labels displayed"); // It may happen, when something happens before the dictionaries get loaded return $sStringCode; } - $aCurrentDictionary = self::$m_aData[self::GetUserLanguage()]; - if (array_key_exists($sStringCode, $aCurrentDictionary)) + $aCurrentDictionary = self::$m_aData[$sLangCode]; + if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary)) { return $aCurrentDictionary[$sStringCode]; } @@ -135,7 +139,7 @@ class Dict self::InitLangIfNeeded(self::$m_sDefaultLanguage); $aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage]; - if (array_key_exists($sStringCode, $aDefaultDictionary)) + if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) { return $aDefaultDictionary[$sStringCode]; } @@ -144,7 +148,7 @@ class Dict self::InitLangIfNeeded('EN US'); $aDefaultDictionary = self::$m_aData['EN US']; - if (array_key_exists($sStringCode, $aDefaultDictionary)) + if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) { return $aDefaultDictionary[$sStringCode]; } @@ -203,7 +207,26 @@ class Dict { self::$m_aLanguages = $aLanguagesList; } - + + /** + * @since 2.7.6 N°4125 + * @return \ApcService + */ + public static function GetApcService() { + if (self::$m_oApcService === null){ + self::$m_oApcService = new ApcService(); + } + return self::$m_oApcService; + } + + /** + * @since 2.7.6 N°4125 + * @param \ApcService $m_oApcService + */ + public static function SetApcService($oApcService) { + self::$m_oApcService = $oApcService; + } + /** * Load a language from the language dictionary, if not already loaded * @param string $sLangCode Language code @@ -212,20 +235,23 @@ class Dict public static function InitLangIfNeeded($sLangCode) { if (array_key_exists($sLangCode, self::$m_aData)) return true; - + $bResult = false; - - if (function_exists('apc_fetch') && (self::$m_sApplicationPrefix !== null)) + + if (self::GetApcService()->function_exists('apc_fetch') + && (self::$m_sApplicationPrefix !== null)) { // Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter // - self::$m_aData[$sLangCode] = apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode); - if (self::$m_aData[$sLangCode] === false) - { + self::$m_aData[$sLangCode] = self::GetApcService()->apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode); + if (self::$m_aData[$sLangCode] === false) { unset(self::$m_aData[$sLangCode]); - } - else - { + } else if (! is_array(self::$m_aData[$sLangCode])) { + // N°4125: we dont fix dictionnary corrupted cache (on iTop side). + // but we log an error in a dedicated channel to let itop administrator be aware of a potential APCu issue to fix. + IssueLog::Error("APCu corrupted data (with $sLangCode dictionnary). APCu configuration and running version should be troubleshooted...", LogChannels::APC); + $bResult = true; + } else { $bResult = true; } } @@ -234,9 +260,10 @@ class Dict $sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php'; require_once($sDictFile); - if (function_exists('apc_store') && (self::$m_sApplicationPrefix !== null)) + if (self::GetApcService()->function_exists('apc_store') + && (self::$m_sApplicationPrefix !== null)) { - apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]); + self::GetApcService()->apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]); } $bResult = true; } diff --git a/core/log.class.inc.php b/core/log.class.inc.php index 7efd61ad6..999779b9a 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -549,6 +549,7 @@ class LogChannels public const PORTAL = 'portal'; public const CMDB_SOURCE = 'cmdbsource'; public const CORE = 'core'; + public const APC = 'apc'; } diff --git a/datamodels/2.x/itop-attachments/renderers.itop-attachments.php b/datamodels/2.x/itop-attachments/renderers.itop-attachments.php index 1acc8ade7..21077bd4e 100644 --- a/datamodels/2.x/itop-attachments/renderers.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/renderers.itop-attachments.php @@ -556,7 +556,7 @@ JS 'filename' => ''.$sFileName.''.$sAttachmentMeta, 'formatted-size' => $sFileFormattedSize, 'upload-date' => $sAttachmentDateFormatted, - 'uploader' => $sAttachmentUploader, + 'uploader' => $sAttachmentUploaderForHtml, 'type' => $sFileType, 'js' => '', ); diff --git a/js/search/search_form_criteria_enum.js b/js/search/search_form_criteria_enum.js index 754ecf4e8..1434b1f5e 100644 --- a/js/search/search_form_criteria_enum.js +++ b/js/search/search_form_criteria_enum.js @@ -225,7 +225,7 @@ $(function() for (var i in aSortedValues) { var sValCode = aSortedValues[i][0]; - var sValLabel = aSortedValues[i][1]; + var sValLabel = $('
').html(aSortedValues[i][1]).text(); //_makeListItemElement: function(sLabel, sValue, bInitChecked, bInitHidden,bObsolete, sAdditionalField) var oValueElem = this._makeListItemElement(sValLabel, sValCode, false, false, aSortedValues[i][2], aSortedValues[i][3]); oValueElem.appendTo(oDynamicListElem); diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 70afa5edb..a6e68d7cb 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -19,6 +19,7 @@ return array( 'ActionEmail' => $baseDir . '/core/action.class.inc.php', 'ActionNotification' => $baseDir . '/core/action.class.inc.php', 'AjaxPage' => $baseDir . '/sources/application/WebPage/AjaxPage.php', + 'ApcService' => $baseDir . '/core/apc-service.class.inc.php', 'ApplicationContext' => $baseDir . '/application/applicationcontext.class.inc.php', 'ApplicationException' => $baseDir . '/application/exceptions/ApplicationException.php', 'ApplicationMenu' => $baseDir . '/application/menunode.class.inc.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 777be3c35..a12146d12 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -249,6 +249,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b 'ActionEmail' => __DIR__ . '/../..' . '/core/action.class.inc.php', 'ActionNotification' => __DIR__ . '/../..' . '/core/action.class.inc.php', 'AjaxPage' => __DIR__ . '/../..' . '/sources/application/WebPage/AjaxPage.php', + 'ApcService' => __DIR__ . '/../..' . '/core/apc-service.class.inc.php', 'ApplicationContext' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php', 'ApplicationException' => __DIR__ . '/../..' . '/application/exceptions/ApplicationException.php', 'ApplicationMenu' => __DIR__ . '/../..' . '/application/menunode.class.inc.php', diff --git a/test/application/privUITransactionFileTest.php b/test/application/privUITransactionFileTest.php index a7093ff66..818bcf476 100644 --- a/test/application/privUITransactionFileTest.php +++ b/test/application/privUITransactionFileTest.php @@ -178,5 +178,13 @@ class privUITransactionFileTest extends ItopDataTestCase $this->assertTrue($bUser1Login2, 'Login with user1 throw an error'); $bResult = privUITransactionFile::RemoveTransaction($sTransactionIdUserSupport); $this->assertTrue($bResult, 'Token created by support user must be removed in the support user context'); + + // test when no user logged (combodo-unauthenticated-form module for example) + UserRights::_ResetSessionCache(); + $sTransactionIdUnauthenticatedUser = privUITransactionFile::GetNewTransactionId(); + $bResult = privUITransactionFile::IsTransactionValid($sTransactionIdUnauthenticatedUser, false); + $this->assertTrue($bResult, 'Token created by unauthenticated user must be valid when no user logged'); + $bResult = privUITransactionFile::RemoveTransaction($sTransactionIdUnauthenticatedUser); + $this->assertTrue($bResult, 'Token created by unauthenticated user must be removed when no user logged'); } } diff --git a/test/core/dictApcuTest.php b/test/core/dictApcuTest.php new file mode 100644 index 000000000..cce8060f9 --- /dev/null +++ b/test/core/dictApcuTest.php @@ -0,0 +1,402 @@ + +// + +/** + * Created by PhpStorm. + * User: Eric + * Date: 30/10/2017 + * Time: 13:43 + */ + +namespace Combodo\iTop\Test\UnitTest\Core; + +use Combodo\iTop\Test\UnitTest\ItopTestCase; +use Dict; +use Exception; + + +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * @backupGlobals disabled + */ +class dictApcuTest extends ItopTestCase +{ + private $sEnvName; + private $oApcService; + private $sDictionaryFolder; + + protected function setUp() + { + parent::setUp(); + require_once (APPROOT.'core' . DIRECTORY_SEPARATOR . 'coreexception.class.inc.php'); + require_once (APPROOT.'core' . DIRECTORY_SEPARATOR . 'dict.class.inc.php'); + require_once (APPROOT.'core' . DIRECTORY_SEPARATOR . 'apc-service.class.inc.php'); + + $this->sEnvName = time(); + $_SESSION['itop_env'] = $this->sEnvName; + + $this->oApcService = $this->createMock(\ApcService::class); + Dict::SetApcService($this->oApcService); + Dict::EnableCache('toto'); + + Dict::SetLanguagesList(['FR FR' => 'fr', 'EN US' => 'en', 'DE DE' => 'de', 'RU RU' => 'de']); + + $this->InitDictionnaries(); + } + + private function InitDictionnaries(){ + clearstatcache(); + $this->sDictionaryFolder = APPROOT."env-$this->sEnvName" . DIRECTORY_SEPARATOR . "dictionaries"; + @mkdir($this->sDictionaryFolder, 0777, true); + + $sLabels = << 'fr1', +STR; + $this->InitDictionnary($this->sDictionaryFolder, 'FR FR', 'fr-fr', $sLabels); + + $sLabels = << 'ru1', + 'label2' => 'ru2', +STR; + $this->InitDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru', $sLabels); + $sLabels = << 'en1', + 'label2' => 'en2', + 'label3' => 'en3', +STR; + $this->InitDictionnary($this->sDictionaryFolder, 'EN US', 'en-us', $sLabels); + + clearstatcache(); + } + + private function InitDictionnary($sDictionaryFolder, $sLanguageCode, $sLanguageCodeInFilename, $sLabels){ + $sContent = <<sEnvName" . DIRECTORY_SEPARATOR . "dictionaries" . DIRECTORY_SEPARATOR . "*") as $sFile){ + unlink($sFile); + } + rmdir(APPROOT."env-$this->sEnvName" . DIRECTORY_SEPARATOR . "dictionaries"); + rmdir(APPROOT."env-$this->sEnvName"); + } + + public function InitLangIfNeeded_NoApcProvider(){ + return [ + 'apcu mocked' => [ 'bApcuMocked' => true ], + 'integration test - apcu service like in production - install php-apcu before' => [ 'bApcuMocked' => false ], + ]; + } + + /** + * @dataProvider InitLangIfNeeded_NoApcProvider + */ + public function testInitLangIfNeeded_NoApc($bApcuMocked){ + if ($bApcuMocked) { + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $this->oApcService->expects($this->never()) + ->method('apc_fetch'); + + $this->oApcService->expects($this->never()) + ->method('apc_store'); + } else { + Dict::SetApcService(null); + } + + //EN US default language + $this->assertEquals('en1', Dict::S('label1')); + $this->assertEquals('en2', Dict::S('label2')); + $this->assertEquals('en3', Dict::S('label3')); + $this->assertEquals('not_defined_label', Dict::S('not_defined_label')); + + //default language set to RU RU + Dict::SetDefaultLanguage('RU RU'); + $this->assertEquals('ru1', Dict::S('label1')); + $this->assertEquals('ru2', Dict::S('label2')); + $this->assertEquals('en3', Dict::S('label3')); + $this->assertEquals('not_defined_label', Dict::S('not_defined_label')); + + //user language set to FR FR + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('fr1', Dict::S('label1')); + $this->assertEquals('ru2', Dict::S('label2')); + $this->assertEquals('en3', Dict::S('label3')); + $this->assertEquals('not_defined_label', Dict::S('not_defined_label')); + } + + public function testInitLangIfNeeded_Apc_LanguageMismatchDictionnary(){ + //language mismatch!! + $sLabels = << 'de1', +STR; + $this->InitDictionnary($this->sDictionaryFolder, 'RU RU', 'de-de', $sLabels); + + clearstatcache(); + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_fetch'); + + $this->oApcService->expects($this->never()) + ->method('apc_store'); + + Dict::SetUserLanguage('DE DE'); + $this->assertEquals('label1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_Apc_BrokenUserDictionnary(){ + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de'); + + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_fetch'); + + $this->oApcService->expects($this->never()) + ->method('apc_store'); + + Dict::SetUserLanguage('DE DE'); + $this->assertEquals('en1', Dict::S('label1')); + + Dict::SetDefaultLanguage('RU RU'); + $this->assertEquals('ru1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_Apc_BrokenDictionnary_UserAndDefault(){ + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de'); + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru'); + + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_fetch'); + + $this->oApcService->expects($this->never()) + ->method('apc_store'); + + Dict::SetUserLanguage('DE DE'); + Dict::SetDefaultLanguage('RU RU'); + $this->assertEquals('en1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_Apc_BrokenDictionnary_ALL(){ + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'DE DE', 'de-de'); + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'RU RU', 'ru-ru'); + $this->InitBrokenDictionnary($this->sDictionaryFolder, 'EN US', 'en-us'); + + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_fetch'); + + $this->oApcService->expects($this->never()) + ->method('apc_store'); + + Dict::SetUserLanguage('DE DE'); + Dict::SetDefaultLanguage('RU RU'); + $this->assertEquals('label1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_ApcFromCache_PropertyInUserDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(1)) + ->method('apc_fetch') + ->with('toto-dict-FR FR') + ->willReturn(['label1' => 'fr1']); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_store'); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('fr1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_ApcStore_PropertyInUserDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(1)) + ->method('apc_fetch') + ->with('toto-dict-FR FR') + ->willReturn(false); + + $this->oApcService->expects($this->exactly(1)) + ->method('apc_store') + ->with('toto-dict-FR FR', ['label1' => 'fr1']); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('fr1', Dict::S('label1')); + } + + //corrupted data not fixed + //we will return label from another dictionary (defaut one => russian here) + public function testInitLangIfNeeded_Apc_CorruptedCache_PropertyInUserDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(2)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU']) + ->willReturnOnConsecutiveCalls('corrupteddata', ['label1' => 'ru1']); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_store'); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('ru1', Dict::S('label1')); + } + + public function testInitLangIfNeeded_Apc_PropertyInDefaultLanguageDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(2)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU']) + ->willReturnOnConsecutiveCalls([], false); + + $this->oApcService->expects($this->exactly(1)) + ->method('apc_store') + ->withConsecutive(['toto-dict-RU RU', ['label1' => 'ru1', 'label2' => 'ru2']] + ); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('ru2', Dict::S('label2')); + } + + //corrupted data not fixed + //we will return label from default language dictionary (EN here) + public function testInitLangIfNeeded_ApcCorrupted_PropertyInDefaultLanguageDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(3)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US']) + ->willReturnOnConsecutiveCalls([], 'corrupteddata', ['label1' => 'en1', 'label2' => 'en2', 'label3' => 'en3']); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_store'); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('en2', Dict::S('label2')); + } + + public function testInitLangIfNeeded_Apc_PropertyInDictDefaultLanguageDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(3)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US']) + ->willReturnOnConsecutiveCalls([], [], false); + + $this->oApcService->expects($this->exactly(1)) + ->method('apc_store') + ->withConsecutive( + ['toto-dict-EN US', ['label1' => 'en1', 'label2' => 'en2', 'label3' => 'en3']] + ); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('en3', Dict::S('label3')); + } + + public function testInitLangIfNeeded_ApcCorrupted_PropertyInDictDefaultLanguageDictionnary(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(3)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US']) + ->willReturnOnConsecutiveCalls([], [], 'corrupteddata'); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_store'); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('label3', Dict::S('label3')); + } + + public function testInitLangIfNeeded_Apc_PropertyNotFound(){ + $this->oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(true); + + $this->oApcService->expects($this->exactly(3)) + ->method('apc_fetch') + ->withConsecutive(['toto-dict-FR FR'], ['toto-dict-RU RU'], ['toto-dict-EN US']) + ->willReturnOnConsecutiveCalls([], [], []); + + $this->oApcService->expects($this->exactly(0)) + ->method('apc_store'); + + Dict::SetDefaultLanguage('RU RU'); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('undefined_label', Dict::S('undefined_label')); + } +} diff --git a/test/core/dictTest.php b/test/core/dictTest.php index 4323ac60f..d30daede9 100644 --- a/test/core/dictTest.php +++ b/test/core/dictTest.php @@ -38,19 +38,83 @@ use Exception; */ class dictTest extends ItopTestCase { + private $sEnvName; + protected function setUp() { parent::setUp(); - require_once (APPROOT.'core/dict.class.inc.php'); - require_once 'mockDict.incphp'; + + require_once(APPROOT.'core'.DIRECTORY_SEPARATOR.'apc-service.class.inc.php'); + + $this->sEnvName = time(); + $sDictionaryFolder = APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries"; + @mkdir($sDictionaryFolder, 0777, true); + + $sContent = << 'gabu', +)); +PHP; + file_put_contents($sDictionaryFolder.DIRECTORY_SEPARATOR."fr-fr.dict.php", $sContent); + $sContent = << 'zomeu', +)); +PHP; + file_put_contents($sDictionaryFolder.DIRECTORY_SEPARATOR."en-en.dict.php", $sContent); + + $_SESSION['itop_env'] = $this->sEnvName; } - /** - * @throws Exception - */ - public function testType() + protected function tearDown() { + foreach (glob(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries".DIRECTORY_SEPARATOR."*") as $sFile) { + unlink($sFile); + } + rmdir(APPROOT."env-$this->sEnvName".DIRECTORY_SEPARATOR."dictionaries"); + rmdir(APPROOT."env-$this->sEnvName"); + } + + /** + * @throws Exception + */ + public function testType() + { + $_SESSION['itop_env'] = 'production'; $this->assertInternalType('string', Dict::S('Core:AttributeURL')); $this->assertInternalType('string', Dict::Format('Change:AttName_SetTo', '1', '2')); } + + public function testInitLangIfNeeded_NoApc() + { + $oApcService = $this->createMock(\ApcService::class); + Dict::SetApcService($oApcService); + Dict::EnableCache('toto'); + + $oApcService->expects($this->any()) + ->method('function_exists') + ->willReturn(false); + + $oApcService->expects($this->never()) + ->method('apc_fetch') + ->willReturn(false); + + $oApcService->expects($this->never()) + ->method('apc_store') + ->willReturn(false); + + Dict::SetLanguagesList(['FR FR' => 'fr', 'EN EN' => 'en']); + Dict::SetUserLanguage('FR FR'); + $this->assertEquals('gabu', Dict::S('label1')); + Dict::SetUserLanguage('EN EN'); + $this->assertEquals('zomeu', Dict::S('label1')); + } }