1
0

FactoryTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-or-later
  7. */
  8. namespace Test\L10N;
  9. use OC\L10N\Factory;
  10. use OC\L10N\LanguageNotFoundException;
  11. use OCP\App\AppPathNotFoundException;
  12. use OCP\App\IAppManager;
  13. use OCP\ICacheFactory;
  14. use OCP\IConfig;
  15. use OCP\IRequest;
  16. use OCP\IUser;
  17. use OCP\IUserSession;
  18. use OCP\L10N\ILanguageIterator;
  19. use PHPUnit\Framework\MockObject\MockObject;
  20. use Test\TestCase;
  21. class FactoryTest extends TestCase {
  22. /** @var IConfig|MockObject */
  23. protected $config;
  24. /** @var IRequest|MockObject */
  25. protected $request;
  26. /** @var IUserSession|MockObject */
  27. protected $userSession;
  28. /** @var ICacheFactory|MockObject */
  29. protected $cacheFactory;
  30. /** @var string */
  31. protected $serverRoot;
  32. /** @var IAppManager|MockObject */
  33. protected IAppManager $appManager;
  34. protected function setUp(): void {
  35. parent::setUp();
  36. $this->config = $this->createMock(IConfig::class);
  37. $this->request = $this->createMock(IRequest::class);
  38. $this->userSession = $this->createMock(IUserSession::class);
  39. $this->cacheFactory = $this->createMock(ICacheFactory::class);
  40. $this->appManager = $this->createMock(IAppManager::class);
  41. $this->serverRoot = \OC::$SERVERROOT;
  42. $this->config
  43. ->method('getSystemValueBool')
  44. ->willReturnMap([
  45. ['installed', false, true],
  46. ]);
  47. }
  48. /**
  49. * @param string[] $methods
  50. * @param bool $mockRequestGetHeaderMethod
  51. *
  52. * @return Factory|MockObject
  53. */
  54. protected function getFactory(array $methods = [], $mockRequestGetHeaderMethod = false) {
  55. if ($mockRequestGetHeaderMethod) {
  56. $this->request->expects(self::any())
  57. ->method('getHeader')
  58. ->willReturn('');
  59. }
  60. if (!empty($methods)) {
  61. return $this->getMockBuilder(Factory::class)
  62. ->setConstructorArgs([
  63. $this->config,
  64. $this->request,
  65. $this->userSession,
  66. $this->cacheFactory,
  67. $this->serverRoot,
  68. $this->appManager,
  69. ])
  70. ->setMethods($methods)
  71. ->getMock();
  72. }
  73. return new Factory($this->config, $this->request, $this->userSession, $this->cacheFactory, $this->serverRoot, $this->appManager);
  74. }
  75. public function dataFindAvailableLanguages(): array {
  76. return [
  77. [null],
  78. ['files'],
  79. ];
  80. }
  81. public function testFindLanguageWithExistingRequestLanguageAndNoApp(): void {
  82. $factory = $this->getFactory(['languageExists']);
  83. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  84. $factory->expects(self::once())
  85. ->method('languageExists')
  86. ->with(null, 'de')
  87. ->willReturn(true);
  88. self::assertSame('de', $factory->findLanguage());
  89. }
  90. public function testFindLanguageWithExistingRequestLanguageAndApp(): void {
  91. $factory = $this->getFactory(['languageExists']);
  92. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  93. $factory->expects(self::once())
  94. ->method('languageExists')
  95. ->with('MyApp', 'de')
  96. ->willReturn(true);
  97. self::assertSame('de', $factory->findLanguage('MyApp'));
  98. }
  99. public function testFindLanguageWithNotExistingRequestLanguageAndExistingStoredUserLanguage(): void {
  100. $factory = $this->getFactory(['languageExists']);
  101. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  102. $factory->expects($this->exactly(2))
  103. ->method('languageExists')
  104. ->withConsecutive(
  105. ['MyApp', 'de'],
  106. ['MyApp', 'jp'],
  107. )
  108. ->willReturnOnConsecutiveCalls(
  109. false,
  110. true,
  111. );
  112. $this->config
  113. ->expects($this->exactly(1))
  114. ->method('getSystemValue')
  115. ->withConsecutive(
  116. ['force_language', false],
  117. )->willReturnOnConsecutiveCalls(
  118. false,
  119. );
  120. $user = $this->getMockBuilder(IUser::class)
  121. ->getMock();
  122. $user->expects(self::once())
  123. ->method('getUID')
  124. ->willReturn('MyUserUid');
  125. $this->userSession
  126. ->expects(self::exactly(2))
  127. ->method('getUser')
  128. ->willReturn($user);
  129. $this->config
  130. ->expects(self::once())
  131. ->method('getUserValue')
  132. ->with('MyUserUid', 'core', 'lang', null)
  133. ->willReturn('jp');
  134. self::assertSame('jp', $factory->findLanguage('MyApp'));
  135. }
  136. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguage(): void {
  137. $factory = $this->getFactory(['languageExists'], true);
  138. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  139. $factory->expects($this->exactly(3))
  140. ->method('languageExists')
  141. ->willReturnMap([
  142. ['MyApp', 'de', false],
  143. ['MyApp', 'jp', false],
  144. ['MyApp', 'es', true],
  145. ]);
  146. $this->config
  147. ->expects($this->exactly(2))
  148. ->method('getSystemValue')
  149. ->willReturnMap([
  150. ['force_language', false, false],
  151. ['default_language', false, 'es']
  152. ]);
  153. $user = $this->getMockBuilder(IUser::class)
  154. ->getMock();
  155. $user->expects(self::once())
  156. ->method('getUID')
  157. ->willReturn('MyUserUid');
  158. $this->userSession
  159. ->expects(self::exactly(2))
  160. ->method('getUser')
  161. ->willReturn($user);
  162. $this->config
  163. ->expects(self::once())
  164. ->method('getUserValue')
  165. ->with('MyUserUid', 'core', 'lang', null)
  166. ->willReturn('jp');
  167. self::assertSame('es', $factory->findLanguage('MyApp'));
  168. }
  169. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefault(): void {
  170. $factory = $this->getFactory(['languageExists'], true);
  171. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  172. $factory->expects($this->exactly(3))
  173. ->method('languageExists')
  174. ->willReturnMap([
  175. ['MyApp', 'de', false],
  176. ['MyApp', 'jp', false],
  177. ['MyApp', 'es', false],
  178. ]);
  179. $this->config
  180. ->expects($this->exactly(2))
  181. ->method('getSystemValue')
  182. ->willReturnMap([
  183. ['force_language', false, false],
  184. ['default_language', false, 'es']
  185. ]);
  186. $user = $this->getMockBuilder(IUser::class)
  187. ->getMock();
  188. $user->expects(self::once())
  189. ->method('getUID')
  190. ->willReturn('MyUserUid');
  191. $this->userSession
  192. ->expects(self::exactly(2))
  193. ->method('getUser')
  194. ->willReturn($user);
  195. $this->config
  196. ->expects(self::once())
  197. ->method('getUserValue')
  198. ->with('MyUserUid', 'core', 'lang', null)
  199. ->willReturn('jp');
  200. $this->config
  201. ->expects(self::never())
  202. ->method('setUserValue');
  203. self::assertSame('en', $factory->findLanguage('MyApp'));
  204. }
  205. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefaultAndNoAppInScope(): void {
  206. $factory = $this->getFactory(['languageExists'], true);
  207. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  208. $factory->expects($this->exactly(3))
  209. ->method('languageExists')
  210. ->willReturnMap([
  211. ['MyApp', 'de', false],
  212. ['MyApp', 'jp', false],
  213. ['MyApp', 'es', false],
  214. ]);
  215. $this->config
  216. ->expects($this->exactly(2))
  217. ->method('getSystemValue')
  218. ->willReturnMap([
  219. ['force_language', false, false],
  220. ['default_language', false, 'es']
  221. ]);
  222. $user = $this->getMockBuilder(IUser::class)
  223. ->getMock();
  224. $user->expects(self::once())
  225. ->method('getUID')
  226. ->willReturn('MyUserUid');
  227. $this->userSession
  228. ->expects(self::exactly(2))
  229. ->method('getUser')
  230. ->willReturn($user);
  231. $this->config
  232. ->expects(self::once())
  233. ->method('getUserValue')
  234. ->with('MyUserUid', 'core', 'lang', null)
  235. ->willReturn('jp');
  236. $this->config
  237. ->expects(self::never())
  238. ->method('setUserValue')
  239. ->with('MyUserUid', 'core', 'lang', 'en');
  240. self::assertSame('en', $factory->findLanguage('MyApp'));
  241. }
  242. public function testFindLanguageWithForcedLanguage(): void {
  243. $factory = $this->getFactory(['languageExists']);
  244. $this->config
  245. ->expects($this->once())
  246. ->method('getSystemValue')
  247. ->with('force_language', false)
  248. ->willReturn('de');
  249. $factory->expects($this->once())
  250. ->method('languageExists')
  251. ->with('MyApp', 'de')
  252. ->willReturn(true);
  253. self::assertSame('de', $factory->findLanguage('MyApp'));
  254. }
  255. /**
  256. * @dataProvider dataFindAvailableLanguages
  257. *
  258. * @param string|null $app
  259. */
  260. public function testFindAvailableLanguages($app): void {
  261. $factory = $this->getFactory(['findL10nDir']);
  262. $factory->expects(self::once())
  263. ->method('findL10nDir')
  264. ->with($app)
  265. ->willReturn(\OC::$SERVERROOT . '/tests/data/l10n/');
  266. self::assertEqualsCanonicalizing(['cs', 'de', 'en', 'ru'], $factory->findAvailableLanguages($app));
  267. }
  268. public function dataLanguageExists(): array {
  269. return [
  270. [null, 'en', [], true],
  271. [null, 'de', [], false],
  272. [null, 'de', ['ru'], false],
  273. [null, 'de', ['ru', 'de'], true],
  274. ['files', 'en', [], true],
  275. ['files', 'de', [], false],
  276. ['files', 'de', ['ru'], false],
  277. ['files', 'de', ['de', 'ru'], true],
  278. ];
  279. }
  280. public function testFindAvailableLanguagesWithThemes(): void {
  281. $this->serverRoot .= '/tests/data';
  282. $app = 'files';
  283. $factory = $this->getFactory(['findL10nDir']);
  284. $factory->expects(self::once())
  285. ->method('findL10nDir')
  286. ->with($app)
  287. ->willReturn($this->serverRoot . '/apps/files/l10n/');
  288. $this->config
  289. ->expects(self::once())
  290. ->method('getSystemValueString')
  291. ->with('theme')
  292. ->willReturn('abc');
  293. self::assertEqualsCanonicalizing(['en', 'zz'], $factory->findAvailableLanguages($app));
  294. }
  295. /**
  296. * @dataProvider dataLanguageExists
  297. *
  298. * @param string|null $app
  299. * @param string $lang
  300. * @param string[] $availableLanguages
  301. * @param string $expected
  302. */
  303. public function testLanguageExists($app, $lang, array $availableLanguages, $expected): void {
  304. $factory = $this->getFactory(['findAvailableLanguages']);
  305. $factory->expects(($lang === 'en') ? self::never() : self::once())
  306. ->method('findAvailableLanguages')
  307. ->with($app)
  308. ->willReturn($availableLanguages);
  309. self::assertSame($expected, $factory->languageExists($app, $lang));
  310. }
  311. public function dataSetLanguageFromRequest(): array {
  312. return [
  313. // Language is available
  314. [null, 'de', ['de'], 'de'],
  315. [null, 'de,en', ['de'], 'de'],
  316. [null, 'de-DE,en-US;q=0.8,en;q=0.6', ['de'], 'de'],
  317. // Language is not available
  318. [null, 'de', ['ru'], new LanguageNotFoundException()],
  319. [null, 'de,en', ['ru', 'en'], 'en'],
  320. [null, 'de-DE,en-US;q=0.8,en;q=0.6', ['ru', 'en'], 'en'],
  321. // Language for app
  322. ['files_pdfviewer', 'de', ['de'], 'de'],
  323. ['files_pdfviewer', 'de,en', ['de'], 'de'],
  324. ['files_pdfviewer', 'de-DE,en-US;q=0.8,en;q=0.6', ['de'], 'de'],
  325. // Language for app is not available
  326. ['files_pdfviewer', 'de', ['ru'], new LanguageNotFoundException()],
  327. ['files_pdfviewer', 'de,en', ['ru', 'en'], 'en'],
  328. ['files_pdfviewer', 'de-DE,en-US;q=0.8,en;q=0.6', ['ru', 'en'], 'en'],
  329. ];
  330. }
  331. /**
  332. * @dataProvider dataSetLanguageFromRequest
  333. *
  334. * @param string|null $app
  335. * @param string $header
  336. * @param string[] $availableLanguages
  337. * @param string $expected
  338. */
  339. public function testGetLanguageFromRequest($app, $header, array $availableLanguages, $expected): void {
  340. $factory = $this->getFactory(['findAvailableLanguages', 'respectDefaultLanguage']);
  341. $factory->expects(self::once())
  342. ->method('findAvailableLanguages')
  343. ->with($app)
  344. ->willReturn($availableLanguages);
  345. $factory->expects(self::any())
  346. ->method('respectDefaultLanguage')->willReturnCallback(function ($app, $lang) {
  347. return $lang;
  348. });
  349. $this->request->expects(self::once())
  350. ->method('getHeader')
  351. ->with('ACCEPT_LANGUAGE')
  352. ->willReturn($header);
  353. if ($expected instanceof LanguageNotFoundException) {
  354. $this->expectException(LanguageNotFoundException::class);
  355. self::invokePrivate($factory, 'getLanguageFromRequest', [$app]);
  356. } else {
  357. self::assertSame($expected, self::invokePrivate($factory, 'getLanguageFromRequest', [$app]), 'Asserting returned language');
  358. }
  359. }
  360. public function dataGetL10nFilesForApp(): array {
  361. return [
  362. ['', 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
  363. ['core', 'ru', [\OC::$SERVERROOT . '/core/l10n/ru.json']],
  364. ['lib', 'ru', [\OC::$SERVERROOT . '/lib/l10n/ru.json']],
  365. ['settings', 'de', [\OC::$SERVERROOT . '/apps/settings/l10n/de.json']],
  366. ['files', 'de', [\OC::$SERVERROOT . '/apps/files/l10n/de.json']],
  367. ['files', '_lang_never_exists_', []],
  368. ['_app_never_exists_', 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
  369. ];
  370. }
  371. /**
  372. * @dataProvider dataGetL10nFilesForApp
  373. *
  374. * @param string $app
  375. * @param string $expected
  376. */
  377. public function testGetL10nFilesForApp($app, $lang, $expected): void {
  378. $factory = $this->getFactory();
  379. if (in_array($app, ['settings','files'])) {
  380. $this->appManager
  381. ->method('getAppPath')
  382. ->with($app)
  383. ->willReturn(\OC::$SERVERROOT . '/apps/' . $app);
  384. } else {
  385. $this->appManager
  386. ->method('getAppPath')
  387. ->with($app)
  388. ->willThrowException(new AppPathNotFoundException());
  389. }
  390. self::assertSame($expected, $this->invokePrivate($factory, 'getL10nFilesForApp', [$app, $lang]));
  391. }
  392. public function dataFindL10NDir(): array {
  393. return [
  394. ['', \OC::$SERVERROOT . '/core/l10n/'],
  395. ['core', \OC::$SERVERROOT . '/core/l10n/'],
  396. ['lib', \OC::$SERVERROOT . '/lib/l10n/'],
  397. ['settings', \OC::$SERVERROOT . '/apps/settings/l10n/'],
  398. ['files', \OC::$SERVERROOT . '/apps/files/l10n/'],
  399. ['_app_never_exists_', \OC::$SERVERROOT . '/core/l10n/'],
  400. ];
  401. }
  402. /**
  403. * @dataProvider dataFindL10NDir
  404. *
  405. * @param string $app
  406. * @param string $expected
  407. */
  408. public function testFindL10NDir($app, $expected): void {
  409. $factory = $this->getFactory();
  410. if (in_array($app, ['settings','files'])) {
  411. $this->appManager
  412. ->method('getAppPath')
  413. ->with($app)
  414. ->willReturn(\OC::$SERVERROOT . '/apps/' . $app);
  415. } else {
  416. $this->appManager
  417. ->method('getAppPath')
  418. ->with($app)
  419. ->willThrowException(new AppPathNotFoundException());
  420. }
  421. self::assertSame($expected, $this->invokePrivate($factory, 'findL10nDir', [$app]));
  422. }
  423. public function dataFindLanguage(): array {
  424. return [
  425. // Not logged in
  426. [false, [], 'en'],
  427. [false, ['fr'], 'fr'],
  428. [false, ['de', 'fr'], 'de'],
  429. [false, ['nl', 'de', 'fr'], 'de'],
  430. [true, [], 'en'],
  431. [true, ['fr'], 'fr'],
  432. [true, ['de', 'fr'], 'de'],
  433. [true, ['nl', 'de', 'fr'], 'nl'],
  434. ];
  435. }
  436. /**
  437. * @dataProvider dataFindLanguage
  438. *
  439. * @param bool $loggedIn
  440. * @param array $availableLang
  441. * @param string $expected
  442. */
  443. public function testFindLanguage($loggedIn, $availableLang, $expected): void {
  444. $userLang = 'nl';
  445. $browserLang = 'de';
  446. $defaultLang = 'fr';
  447. $this->config->expects(self::any())
  448. ->method('getSystemValue')
  449. ->willReturnCallback(function ($var, $default) use ($defaultLang) {
  450. if ($var === 'default_language') {
  451. return $defaultLang;
  452. } else {
  453. return $default;
  454. }
  455. });
  456. if ($loggedIn) {
  457. $user = $this->getMockBuilder(IUser::class)
  458. ->getMock();
  459. $user->expects(self::any())
  460. ->method('getUID')
  461. ->willReturn('MyUserUid');
  462. $this->userSession
  463. ->expects(self::any())
  464. ->method('getUser')
  465. ->willReturn($user);
  466. $this->config->expects(self::any())
  467. ->method('getUserValue')
  468. ->with('MyUserUid', 'core', 'lang', null)
  469. ->willReturn($userLang);
  470. } else {
  471. $this->userSession
  472. ->expects(self::any())
  473. ->method('getUser')
  474. ->willReturn(null);
  475. }
  476. $this->request->expects(self::any())
  477. ->method('getHeader')
  478. ->with($this->equalTo('ACCEPT_LANGUAGE'))
  479. ->willReturn($browserLang);
  480. $factory = $this->getFactory(['languageExists', 'findAvailableLanguages', 'respectDefaultLanguage']);
  481. $factory->expects(self::any())
  482. ->method('languageExists')
  483. ->willReturnCallback(function ($app, $lang) use ($availableLang) {
  484. return in_array($lang, $availableLang);
  485. });
  486. $factory->expects(self::any())
  487. ->method('findAvailableLanguages')
  488. ->willReturnCallback(function ($app) use ($availableLang) {
  489. return $availableLang;
  490. });
  491. $factory->expects(self::any())
  492. ->method('respectDefaultLanguage')->willReturnCallback(function ($app, $lang) {
  493. return $lang;
  494. });
  495. $lang = $factory->findLanguage();
  496. self::assertSame($expected, $lang);
  497. }
  498. public function testFindGenericLanguageByEnforcedLanguage(): void {
  499. $factory = $this->getFactory();
  500. $this->config->expects(self::once())
  501. ->method('getSystemValue')
  502. ->with('force_language', false)
  503. ->willReturn('cz');
  504. $lang = $factory->findGenericLanguage();
  505. self::assertSame('cz', $lang);
  506. }
  507. public function testFindGenericLanguageByDefaultLanguage(): void {
  508. $factory = $this->getFactory(['languageExists']);
  509. $this->config->expects(self::exactly(2))
  510. ->method('getSystemValue')
  511. ->willReturnMap([
  512. ['force_language', false, false,],
  513. ['default_language', false, 'cz',],
  514. ]);
  515. $factory->expects(self::once())
  516. ->method('languageExists')
  517. ->with(null, 'cz')
  518. ->willReturn(true);
  519. $lang = $factory->findGenericLanguage();
  520. self::assertSame('cz', $lang);
  521. }
  522. public function testFindGenericLanguageByUserLanguage(): void {
  523. $factory = $this->getFactory();
  524. $this->config->expects(self::exactly(2))
  525. ->method('getSystemValue')
  526. ->willReturnMap([
  527. ['force_language', false, false,],
  528. ['default_language', false, false,],
  529. ]);
  530. $user = $this->createMock(IUser::class);
  531. $this->userSession->expects(self::once())
  532. ->method('getUser')
  533. ->willReturn($user);
  534. $user->method('getUID')->willReturn('user123');
  535. $this->config->expects(self::once())
  536. ->method('getUserValue')
  537. ->with('user123', 'core', 'lang', null)
  538. ->willReturn('cz');
  539. $lang = $factory->findGenericLanguage();
  540. self::assertSame('cz', $lang);
  541. }
  542. public function testFindGenericLanguageByRequestLanguage(): void {
  543. $factory = $this->getFactory(['findAvailableLanguages', 'languageExists']);
  544. $this->config->method('getSystemValue')
  545. ->willReturnMap([
  546. ['force_language', false, false,],
  547. ['default_language', false, false,],
  548. ]);
  549. $user = $this->createMock(IUser::class);
  550. $this->userSession->expects(self::once())
  551. ->method('getUser')
  552. ->willReturn($user);
  553. $user->method('getUID')->willReturn('user123');
  554. $this->config->expects(self::once())
  555. ->method('getUserValue')
  556. ->with('user123', 'core', 'lang', null)
  557. ->willReturn(null);
  558. $this->request->expects(self::once())
  559. ->method('getHeader')
  560. ->with('ACCEPT_LANGUAGE')
  561. ->willReturn('cz');
  562. $factory->expects(self::once())
  563. ->method('findAvailableLanguages')
  564. ->with(null)
  565. ->willReturn(['cz']);
  566. $lang = $factory->findGenericLanguage();
  567. self::assertSame('cz', $lang);
  568. }
  569. public function testFindGenericLanguageFallback(): void {
  570. $factory = $this->getFactory(['findAvailableLanguages', 'languageExists']);
  571. $this->config->method('getSystemValue')
  572. ->willReturnMap([
  573. ['force_language', false, false,],
  574. ['default_language', false, false,],
  575. ]);
  576. $user = $this->createMock(IUser::class);
  577. $this->userSession->expects(self::once())
  578. ->method('getUser')
  579. ->willReturn($user);
  580. $user->method('getUID')->willReturn('user123');
  581. $this->config->expects(self::once())
  582. ->method('getUserValue')
  583. ->with('user123', 'core', 'lang', null)
  584. ->willReturn(null);
  585. $this->request->expects(self::once())
  586. ->method('getHeader')
  587. ->with('ACCEPT_LANGUAGE')
  588. ->willReturn('');
  589. $factory->expects(self::never())
  590. ->method('findAvailableLanguages');
  591. $factory->expects(self::never())
  592. ->method('languageExists');
  593. $lang = $factory->findGenericLanguage();
  594. self::assertSame('en', $lang);
  595. }
  596. public function dataTestRespectDefaultLanguage(): array {
  597. return [
  598. ['de', 'de_DE', true, 'de_DE'],
  599. ['de', 'de', true, 'de'],
  600. ['de', false, true, 'de'],
  601. ['fr', 'de_DE', true, 'fr'],
  602. ];
  603. }
  604. /**
  605. * test if we respect default language if possible
  606. *
  607. * @dataProvider dataTestRespectDefaultLanguage
  608. *
  609. * @param string $lang
  610. * @param string $defaultLanguage
  611. * @param bool $langExists
  612. * @param string $expected
  613. */
  614. public function testRespectDefaultLanguage($lang, $defaultLanguage, $langExists, $expected): void {
  615. $factory = $this->getFactory(['languageExists']);
  616. $factory->expects(self::any())
  617. ->method('languageExists')->willReturn($langExists);
  618. $this->config->expects(self::any())
  619. ->method('getSystemValue')->with('default_language', false)->willReturn($defaultLanguage);
  620. $result = $this->invokePrivate($factory, 'respectDefaultLanguage', ['app', $lang]);
  621. self::assertSame($expected, $result);
  622. }
  623. public static function dataTestReduceToLanguages(): array {
  624. return [
  625. ['en', ['en', 'de', 'fr', 'it', 'es'], ['en', 'fr', 'de'], ['en', 'fr', 'de']],
  626. ['en', ['en', 'de', 'fr', 'it', 'es'], ['en', 'de'], ['en', 'de']],
  627. ['en', ['en', 'de', 'fr', 'it', 'es'], [], ['de', 'en', 'es', 'fr', 'it']],
  628. ];
  629. }
  630. /**
  631. * test
  632. * - if available languages set can be reduced by configuration
  633. * - if available languages set is not reduced to an empty set if
  634. * the reduce config is an empty set
  635. *
  636. * @dataProvider dataTestReduceToLanguages
  637. *
  638. * @param string $lang
  639. * @param array $availableLanguages
  640. * @param array $reducedLanguageSet
  641. * @param array $expected
  642. */
  643. public function testReduceLanguagesByConfiguration(string $lang, array $availableLanguages, array $reducedLanguageSet, array $expected): void {
  644. $factory = $this->getFactory(['findAvailableLanguages', 'languageExists']);
  645. $factory->expects(self::any())
  646. ->method('languageExists')->willReturn(true);
  647. $factory->expects(self::any())
  648. ->method('findAvailableLanguages')
  649. ->willReturnCallback(function ($app) use ($availableLanguages) {
  650. return $availableLanguages;
  651. });
  652. $this->config
  653. ->method('getSystemValue')
  654. ->willReturnMap([
  655. ['force_language', false, false],
  656. ['default_language', false, $lang],
  657. ['reduce_to_languages', [], $reducedLanguageSet]
  658. ]);
  659. $result = $this->invokePrivate($factory, 'getLanguages');
  660. $commonLanguagesCodes = array_map(function ($lang) {
  661. return $lang['code'];
  662. }, $result['commonLanguages']);
  663. self::assertEqualsCanonicalizing($expected, $commonLanguagesCodes);
  664. }
  665. public function languageIteratorRequestProvider():array {
  666. return [
  667. [ true, $this->createMock(IUser::class)],
  668. [ false, $this->createMock(IUser::class)],
  669. [ false, null]
  670. ];
  671. }
  672. /**
  673. * @dataProvider languageIteratorRequestProvider
  674. */
  675. public function testGetLanguageIterator(bool $hasSession, ?IUser $iUserMock = null): void {
  676. $factory = $this->getFactory();
  677. if ($iUserMock === null) {
  678. $matcher = $this->userSession->expects(self::once())
  679. ->method('getUser');
  680. if ($hasSession) {
  681. $matcher->willReturn($this->createMock(IUser::class));
  682. } else {
  683. $this->expectException(\RuntimeException::class);
  684. }
  685. }
  686. $iterator = $factory->getLanguageIterator($iUserMock);
  687. self::assertInstanceOf(ILanguageIterator::class, $iterator);
  688. }
  689. public static function dataGetLanguageDirection(): array {
  690. return [
  691. ['en', 'ltr'],
  692. ['de', 'ltr'],
  693. ['fa', 'rtl'],
  694. ['ar', 'rtl']
  695. ];
  696. }
  697. /**
  698. * @dataProvider dataGetLanguageDirection
  699. */
  700. public function testGetLanguageDirection(string $language, string $expectedDirection) {
  701. $factory = $this->getFactory();
  702. self::assertEquals($expectedDirection, $factory->getLanguageDirection($language));
  703. }
  704. }