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'));
+ }
}