FactoryTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <?php
  2. /**
  3. * Copyright (c) 2016 Joas Schilling <nickvergessen@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace Test\L10N;
  9. use OC\L10N\Factory;
  10. use OC\L10N\LanguageNotFoundException;
  11. use OCP\IConfig;
  12. use OCP\IRequest;
  13. use OCP\IUser;
  14. use OCP\IUserSession;
  15. use OCP\L10N\ILanguageIterator;
  16. use Test\TestCase;
  17. /**
  18. * Class FactoryTest
  19. *
  20. * @package Test\L10N
  21. */
  22. class FactoryTest extends TestCase {
  23. /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
  24. protected $config;
  25. /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
  26. protected $request;
  27. /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
  28. protected $userSession;
  29. /** @var string */
  30. protected $serverRoot;
  31. protected function setUp(): void {
  32. parent::setUp();
  33. $this->config = $this->getMockBuilder(IConfig::class)
  34. ->disableOriginalConstructor()
  35. ->getMock();
  36. $this->request = $this->getMockBuilder(IRequest::class)
  37. ->disableOriginalConstructor()
  38. ->getMock();
  39. $this->userSession = $this->getMockBuilder(IUserSession::class)
  40. ->disableOriginalConstructor()
  41. ->getMock();
  42. $this->serverRoot = \OC::$SERVERROOT;
  43. }
  44. /**
  45. * @param array $methods
  46. * @param bool $mockRequestGetHeaderMethod
  47. * @return Factory|\PHPUnit\Framework\MockObject\MockObject
  48. */
  49. protected function getFactory(array $methods = [], $mockRequestGetHeaderMethod = false) {
  50. if ($mockRequestGetHeaderMethod) {
  51. $this->request->expects($this->any())
  52. ->method('getHeader')
  53. ->willReturn('');
  54. }
  55. if (!empty($methods)) {
  56. return $this->getMockBuilder(Factory::class)
  57. ->setConstructorArgs([
  58. $this->config,
  59. $this->request,
  60. $this->userSession,
  61. $this->serverRoot,
  62. ])
  63. ->setMethods($methods)
  64. ->getMock();
  65. } else {
  66. return new Factory($this->config, $this->request, $this->userSession, $this->serverRoot);
  67. }
  68. }
  69. public function dataFindAvailableLanguages() {
  70. return [
  71. [null],
  72. ['files'],
  73. ];
  74. }
  75. public function testFindLanguageWithExistingRequestLanguageAndNoApp() {
  76. $factory = $this->getFactory(['languageExists']);
  77. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  78. $factory->expects($this->once())
  79. ->method('languageExists')
  80. ->with(null, 'de')
  81. ->willReturn(true);
  82. $this->assertSame('de', $factory->findLanguage());
  83. }
  84. public function testFindLanguageWithExistingRequestLanguageAndApp() {
  85. $factory = $this->getFactory(['languageExists']);
  86. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  87. $factory->expects($this->once())
  88. ->method('languageExists')
  89. ->with('MyApp', 'de')
  90. ->willReturn(true);
  91. $this->assertSame('de', $factory->findLanguage('MyApp'));
  92. }
  93. public function testFindLanguageWithNotExistingRequestLanguageAndExistingStoredUserLanguage() {
  94. $factory = $this->getFactory(['languageExists']);
  95. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  96. $factory->expects($this->at(0))
  97. ->method('languageExists')
  98. ->with('MyApp', 'de')
  99. ->willReturn(false);
  100. $this->config
  101. ->expects($this->at(0))
  102. ->method('getSystemValue')
  103. ->with('force_language', false)
  104. ->willReturn(false);
  105. $this->config
  106. ->expects($this->at(1))
  107. ->method('getSystemValue')
  108. ->with('installed', false)
  109. ->willReturn(true);
  110. $user = $this->getMockBuilder(IUser::class)
  111. ->getMock();
  112. $user->expects($this->once())
  113. ->method('getUID')
  114. ->willReturn('MyUserUid');
  115. $this->userSession
  116. ->expects($this->exactly(2))
  117. ->method('getUser')
  118. ->willReturn($user);
  119. $this->config
  120. ->expects($this->once())
  121. ->method('getUserValue')
  122. ->with('MyUserUid', 'core', 'lang', null)
  123. ->willReturn('jp');
  124. $factory->expects($this->at(1))
  125. ->method('languageExists')
  126. ->with('MyApp', 'jp')
  127. ->willReturn(true);
  128. $this->assertSame('jp', $factory->findLanguage('MyApp'));
  129. }
  130. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguage() {
  131. $factory = $this->getFactory(['languageExists'], true);
  132. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  133. $factory->expects($this->at(0))
  134. ->method('languageExists')
  135. ->with('MyApp', 'de')
  136. ->willReturn(false);
  137. $this->config
  138. ->expects($this->at(0))
  139. ->method('getSystemValue')
  140. ->with('force_language', false)
  141. ->willReturn(false);
  142. $this->config
  143. ->expects($this->at(1))
  144. ->method('getSystemValue')
  145. ->with('installed', false)
  146. ->willReturn(true);
  147. $user = $this->getMockBuilder(IUser::class)
  148. ->getMock();
  149. $user->expects($this->once())
  150. ->method('getUID')
  151. ->willReturn('MyUserUid');
  152. $this->userSession
  153. ->expects($this->exactly(2))
  154. ->method('getUser')
  155. ->willReturn($user);
  156. $this->config
  157. ->expects($this->once())
  158. ->method('getUserValue')
  159. ->with('MyUserUid', 'core', 'lang', null)
  160. ->willReturn('jp');
  161. $factory->expects($this->at(1))
  162. ->method('languageExists')
  163. ->with('MyApp', 'jp')
  164. ->willReturn(false);
  165. $this->config
  166. ->expects($this->at(3))
  167. ->method('getSystemValue')
  168. ->with('default_language', false)
  169. ->willReturn('es');
  170. $factory->expects($this->at(2))
  171. ->method('languageExists')
  172. ->with('MyApp', 'es')
  173. ->willReturn(true);
  174. $this->assertSame('es', $factory->findLanguage('MyApp'));
  175. }
  176. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefault() {
  177. $factory = $this->getFactory(['languageExists'], true);
  178. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  179. $factory->expects($this->at(0))
  180. ->method('languageExists')
  181. ->with('MyApp', 'de')
  182. ->willReturn(false);
  183. $this->config
  184. ->expects($this->at(0))
  185. ->method('getSystemValue')
  186. ->with('force_language', false)
  187. ->willReturn(false);
  188. $this->config
  189. ->expects($this->at(1))
  190. ->method('getSystemValue')
  191. ->with('installed', false)
  192. ->willReturn(true);
  193. $user = $this->getMockBuilder(IUser::class)
  194. ->getMock();
  195. $user->expects($this->once())
  196. ->method('getUID')
  197. ->willReturn('MyUserUid');
  198. $this->userSession
  199. ->expects($this->exactly(2))
  200. ->method('getUser')
  201. ->willReturn($user);
  202. $this->config
  203. ->expects($this->once())
  204. ->method('getUserValue')
  205. ->with('MyUserUid', 'core', 'lang', null)
  206. ->willReturn('jp');
  207. $factory->expects($this->at(1))
  208. ->method('languageExists')
  209. ->with('MyApp', 'jp')
  210. ->willReturn(false);
  211. $this->config
  212. ->expects($this->at(3))
  213. ->method('getSystemValue')
  214. ->with('default_language', false)
  215. ->willReturn('es');
  216. $factory->expects($this->at(2))
  217. ->method('languageExists')
  218. ->with('MyApp', 'es')
  219. ->willReturn(false);
  220. $this->config
  221. ->expects($this->never())
  222. ->method('setUserValue');
  223. $this->assertSame('en', $factory->findLanguage('MyApp'));
  224. }
  225. public function testFindLanguageWithNotExistingRequestLanguageAndNotExistingStoredUserLanguageAndNotExistingDefaultAndNoAppInScope() {
  226. $factory = $this->getFactory(['languageExists'], true);
  227. $this->invokePrivate($factory, 'requestLanguage', ['de']);
  228. $factory->expects($this->at(0))
  229. ->method('languageExists')
  230. ->with('MyApp', 'de')
  231. ->willReturn(false);
  232. $this->config
  233. ->expects($this->at(0))
  234. ->method('getSystemValue')
  235. ->with('force_language', false)
  236. ->willReturn(false);
  237. $this->config
  238. ->expects($this->at(1))
  239. ->method('getSystemValue')
  240. ->with('installed', false)
  241. ->willReturn(true);
  242. $user = $this->getMockBuilder(IUser::class)
  243. ->getMock();
  244. $user->expects($this->once())
  245. ->method('getUID')
  246. ->willReturn('MyUserUid');
  247. $this->userSession
  248. ->expects($this->exactly(2))
  249. ->method('getUser')
  250. ->willReturn($user);
  251. $this->config
  252. ->expects($this->once())
  253. ->method('getUserValue')
  254. ->with('MyUserUid', 'core', 'lang', null)
  255. ->willReturn('jp');
  256. $factory->expects($this->at(1))
  257. ->method('languageExists')
  258. ->with('MyApp', 'jp')
  259. ->willReturn(false);
  260. $this->config
  261. ->expects($this->at(3))
  262. ->method('getSystemValue')
  263. ->with('default_language', false)
  264. ->willReturn('es');
  265. $factory->expects($this->at(2))
  266. ->method('languageExists')
  267. ->with('MyApp', 'es')
  268. ->willReturn(false);
  269. $this->config
  270. ->expects($this->never())
  271. ->method('setUserValue')
  272. ->with('MyUserUid', 'core', 'lang', 'en');
  273. $this->assertSame('en', $factory->findLanguage('MyApp'));
  274. }
  275. public function testFindLanguageWithForcedLanguage() {
  276. $factory = $this->getFactory(['languageExists']);
  277. $this->config
  278. ->expects($this->at(0))
  279. ->method('getSystemValue')
  280. ->with('force_language', false)
  281. ->willReturn('de');
  282. $factory->expects($this->once())
  283. ->method('languageExists')
  284. ->with('MyApp', 'de')
  285. ->willReturn(true);
  286. $this->assertSame('de', $factory->findLanguage('MyApp'));
  287. }
  288. /**
  289. * @dataProvider dataFindAvailableLanguages
  290. *
  291. * @param string|null $app
  292. */
  293. public function testFindAvailableLanguages($app) {
  294. $factory = $this->getFactory(['findL10nDir']);
  295. $factory->expects($this->once())
  296. ->method('findL10nDir')
  297. ->with($app)
  298. ->willReturn(\OC::$SERVERROOT . '/tests/data/l10n/');
  299. $this->assertEqualsCanonicalizing(['cs', 'de', 'en', 'ru'], $factory->findAvailableLanguages($app));
  300. }
  301. public function dataLanguageExists() {
  302. return [
  303. [null, 'en', [], true],
  304. [null, 'de', [], false],
  305. [null, 'de', ['ru'], false],
  306. [null, 'de', ['ru', 'de'], true],
  307. ['files', 'en', [], true],
  308. ['files', 'de', [], false],
  309. ['files', 'de', ['ru'], false],
  310. ['files', 'de', ['de', 'ru'], true],
  311. ];
  312. }
  313. public function testFindAvailableLanguagesWithThemes() {
  314. $this->serverRoot .= '/tests/data';
  315. $app = 'files';
  316. $factory = $this->getFactory(['findL10nDir']);
  317. $factory->expects($this->once())
  318. ->method('findL10nDir')
  319. ->with($app)
  320. ->willReturn($this->serverRoot . '/apps/files/l10n/');
  321. $this->config
  322. ->expects($this->once())
  323. ->method('getSystemValue')
  324. ->with('theme')
  325. ->willReturn('abc');
  326. $this->assertEqualsCanonicalizing(['en', 'zz'], $factory->findAvailableLanguages($app));
  327. }
  328. /**
  329. * @dataProvider dataLanguageExists
  330. *
  331. * @param string|null $app
  332. * @param string $lang
  333. * @param string[] $availableLanguages
  334. * @param string $expected
  335. */
  336. public function testLanguageExists($app, $lang, array $availableLanguages, $expected) {
  337. $factory = $this->getFactory(['findAvailableLanguages']);
  338. $factory->expects(($lang === 'en') ? $this->never() : $this->once())
  339. ->method('findAvailableLanguages')
  340. ->with($app)
  341. ->willReturn($availableLanguages);
  342. $this->assertSame($expected, $factory->languageExists($app, $lang));
  343. }
  344. public function dataSetLanguageFromRequest() {
  345. return [
  346. // Language is available
  347. [null, 'de', ['de'], 'de'],
  348. [null, 'de,en', ['de'], 'de'],
  349. [null, 'de-DE,en-US;q=0.8,en;q=0.6', ['de'], 'de'],
  350. // Language is not available
  351. [null, 'de', ['ru'], new LanguageNotFoundException()],
  352. [null, 'de,en', ['ru', 'en'], 'en'],
  353. [null, 'de-DE,en-US;q=0.8,en;q=0.6', ['ru', 'en'], 'en'],
  354. // Language for app
  355. ['files_pdfviewer', 'de', ['de'], 'de'],
  356. ['files_pdfviewer', 'de,en', ['de'], 'de'],
  357. ['files_pdfviewer', 'de-DE,en-US;q=0.8,en;q=0.6', ['de'], 'de'],
  358. // Language for app is not available
  359. ['files_pdfviewer', 'de', ['ru'], new LanguageNotFoundException()],
  360. ['files_pdfviewer', 'de,en', ['ru', 'en'], 'en'],
  361. ['files_pdfviewer', 'de-DE,en-US;q=0.8,en;q=0.6', ['ru', 'en'], 'en'],
  362. ];
  363. }
  364. /**
  365. * @dataProvider dataSetLanguageFromRequest
  366. *
  367. * @param string|null $app
  368. * @param string $header
  369. * @param string[] $availableLanguages
  370. * @param string $expected
  371. */
  372. public function testGetLanguageFromRequest($app, $header, array $availableLanguages, $expected) {
  373. $factory = $this->getFactory(['findAvailableLanguages', 'respectDefaultLanguage']);
  374. $factory->expects($this->once())
  375. ->method('findAvailableLanguages')
  376. ->with($app)
  377. ->willReturn($availableLanguages);
  378. $factory->expects($this->any())
  379. ->method('respectDefaultLanguage')->willReturnCallback(function ($app, $lang) {
  380. return $lang;
  381. });
  382. $this->request->expects($this->once())
  383. ->method('getHeader')
  384. ->with('ACCEPT_LANGUAGE')
  385. ->willReturn($header);
  386. if ($expected instanceof LanguageNotFoundException) {
  387. $this->expectException(LanguageNotFoundException::class);
  388. self::invokePrivate($factory, 'getLanguageFromRequest', [$app]);
  389. } else {
  390. $this->assertSame($expected, self::invokePrivate($factory, 'getLanguageFromRequest', [$app]), 'Asserting returned language');
  391. }
  392. }
  393. public function dataGetL10nFilesForApp() {
  394. return [
  395. [null, 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
  396. ['core', 'ru', [\OC::$SERVERROOT . '/core/l10n/ru.json']],
  397. ['lib', 'ru', [\OC::$SERVERROOT . '/lib/l10n/ru.json']],
  398. ['settings', 'de', [\OC::$SERVERROOT . '/apps/settings/l10n/de.json']],
  399. ['files', 'de', [\OC::$SERVERROOT . '/apps/files/l10n/de.json']],
  400. ['files', '_lang_never_exists_', []],
  401. ['_app_never_exists_', 'de', [\OC::$SERVERROOT . '/core/l10n/de.json']],
  402. ];
  403. }
  404. /**
  405. * @dataProvider dataGetL10nFilesForApp
  406. *
  407. * @param string|null $app
  408. * @param string $expected
  409. */
  410. public function testGetL10nFilesForApp($app, $lang, $expected) {
  411. $factory = $this->getFactory();
  412. $this->assertSame($expected, $this->invokePrivate($factory, 'getL10nFilesForApp', [$app, $lang]));
  413. }
  414. public function dataFindL10NDir() {
  415. return [
  416. [null, \OC::$SERVERROOT . '/core/l10n/'],
  417. ['core', \OC::$SERVERROOT . '/core/l10n/'],
  418. ['lib', \OC::$SERVERROOT . '/lib/l10n/'],
  419. ['settings', \OC::$SERVERROOT . '/apps/settings/l10n/'],
  420. ['files', \OC::$SERVERROOT . '/apps/files/l10n/'],
  421. ['_app_never_exists_', \OC::$SERVERROOT . '/core/l10n/'],
  422. ];
  423. }
  424. /**
  425. * @dataProvider dataFindL10NDir
  426. *
  427. * @param string|null $app
  428. * @param string $expected
  429. */
  430. public function testFindL10NDir($app, $expected) {
  431. $factory = $this->getFactory();
  432. $this->assertSame($expected, $this->invokePrivate($factory, 'findL10nDir', [$app]));
  433. }
  434. public function dataFindLanguage() {
  435. return [
  436. // Not logged in
  437. [false, [], 'en'],
  438. [false, ['fr'], 'fr'],
  439. [false, ['de', 'fr'], 'de'],
  440. [false, ['nl', 'de', 'fr'], 'de'],
  441. [true, [], 'en'],
  442. [true, ['fr'], 'fr'],
  443. [true, ['de', 'fr'], 'de'],
  444. [true, ['nl', 'de', 'fr'], 'nl'],
  445. ];
  446. }
  447. /**
  448. * @dataProvider dataFindLanguage
  449. *
  450. * @param bool $loggedIn
  451. * @param array $availableLang
  452. * @param string $expected
  453. */
  454. public function testFindLanguage($loggedIn, $availableLang, $expected) {
  455. $userLang = 'nl';
  456. $browserLang = 'de';
  457. $defaultLang = 'fr';
  458. $this->config->expects($this->any())
  459. ->method('getSystemValue')
  460. ->willReturnCallback(function ($var, $default) use ($defaultLang) {
  461. if ($var === 'installed') {
  462. return true;
  463. } elseif ($var === 'default_language') {
  464. return $defaultLang;
  465. } else {
  466. return $default;
  467. }
  468. });
  469. if ($loggedIn) {
  470. $user = $this->getMockBuilder(IUser::class)
  471. ->getMock();
  472. $user->expects($this->any())
  473. ->method('getUID')
  474. ->willReturn('MyUserUid');
  475. $this->userSession
  476. ->expects($this->any())
  477. ->method('getUser')
  478. ->willReturn($user);
  479. $this->config->expects($this->any())
  480. ->method('getUserValue')
  481. ->with('MyUserUid', 'core', 'lang', null)
  482. ->willReturn($userLang);
  483. } else {
  484. $this->userSession
  485. ->expects($this->any())
  486. ->method('getUser')
  487. ->willReturn(null);
  488. }
  489. $this->request->expects($this->any())
  490. ->method('getHeader')
  491. ->with($this->equalTo('ACCEPT_LANGUAGE'))
  492. ->willReturn($browserLang);
  493. $factory = $this->getFactory(['languageExists', 'findAvailableLanguages', 'respectDefaultLanguage']);
  494. $factory->expects($this->any())
  495. ->method('languageExists')
  496. ->willReturnCallback(function ($app, $lang) use ($availableLang) {
  497. return in_array($lang, $availableLang);
  498. });
  499. $factory->expects($this->any())
  500. ->method('findAvailableLanguages')
  501. ->willReturnCallback(function ($app) use ($availableLang) {
  502. return $availableLang;
  503. });
  504. $factory->expects($this->any())
  505. ->method('respectDefaultLanguage')->willReturnCallback(function ($app, $lang) {
  506. return $lang;
  507. });
  508. $lang = $factory->findLanguage(null);
  509. $this->assertSame($expected, $lang);
  510. }
  511. public function dataTestRespectDefaultLanguage() {
  512. return [
  513. ['de', 'de_DE', true, 'de_DE'],
  514. ['de', 'de', true, 'de'],
  515. ['de', false, true, 'de'],
  516. ['fr', 'de_DE', true, 'fr'],
  517. ];
  518. }
  519. /**
  520. * test if we respect default language if possible
  521. *
  522. * @dataProvider dataTestRespectDefaultLanguage
  523. *
  524. * @param string $lang
  525. * @param string $defaultLanguage
  526. * @param bool $langExists
  527. * @param string $expected
  528. */
  529. public function testRespectDefaultLanguage($lang, $defaultLanguage, $langExists, $expected) {
  530. $factory = $this->getFactory(['languageExists']);
  531. $factory->expects($this->any())
  532. ->method('languageExists')->willReturn($langExists);
  533. $this->config->expects($this->any())
  534. ->method('getSystemValue')->with('default_language', false)->willReturn($defaultLanguage);
  535. $result = $this->invokePrivate($factory, 'respectDefaultLanguage', ['app', $lang]);
  536. $this->assertSame($expected, $result);
  537. }
  538. public function languageIteratorRequestProvider():array {
  539. return [
  540. [ true, $this->createMock(IUser::class)],
  541. [ false, $this->createMock(IUser::class)],
  542. [ false, null]
  543. ];
  544. }
  545. /**
  546. * @dataProvider languageIteratorRequestProvider
  547. */
  548. public function testGetLanguageIterator(bool $hasSession, IUser $iUserMock = null) {
  549. $factory = $this->getFactory();
  550. if ($iUserMock === null) {
  551. $matcher = $this->userSession->expects($this->once())
  552. ->method('getUser');
  553. if ($hasSession) {
  554. $matcher->willReturn($this->createMock(IUser::class));
  555. } else {
  556. $this->expectException(\RuntimeException::class);
  557. }
  558. }
  559. $iterator = $factory->getLanguageIterator($iUserMock);
  560. $this->assertInstanceOf(ILanguageIterator::class, $iterator);
  561. }
  562. }