You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
12 KiB

10 years ago
10 years ago
12 years ago
12 years ago
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Lukas Reschke <lukas@statuscode.ch>
  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;
  9. use OC_Util;
  10. /**
  11. * Class UtilTest
  12. *
  13. * @package Test
  14. * @group DB
  15. */
  16. class UtilTest extends \Test\TestCase {
  17. public function testGetVersion() {
  18. $version = \OCP\Util::getVersion();
  19. $this->assertTrue(is_array($version));
  20. foreach ($version as $num) {
  21. $this->assertTrue(is_int($num));
  22. }
  23. }
  24. public function testGetVersionString() {
  25. $version = \OC_Util::getVersionString();
  26. $this->assertTrue(is_string($version));
  27. }
  28. public function testGetEditionString() {
  29. $edition = \OC_Util::getEditionString();
  30. $this->assertTrue(is_string($edition));
  31. }
  32. public function testSanitizeHTML() {
  33. $badArray = [
  34. 'While it is unusual to pass an array',
  35. 'this function actually <blink>supports</blink> it.',
  36. 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!',
  37. [
  38. 'And It Even May <strong>Nest</strong>',
  39. ],
  40. ];
  41. $goodArray = [
  42. 'While it is unusual to pass an array',
  43. 'this function actually &lt;blink&gt;supports&lt;/blink&gt; it.',
  44. 'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!',
  45. [
  46. 'And It Even May &lt;strong&gt;Nest&lt;/strong&gt;'
  47. ],
  48. ];
  49. $result = OC_Util::sanitizeHTML($badArray);
  50. $this->assertEquals($goodArray, $result);
  51. $badString = '<img onload="alert(1)" />';
  52. $result = OC_Util::sanitizeHTML($badString);
  53. $this->assertEquals('&lt;img onload=&quot;alert(1)&quot; /&gt;', $result);
  54. $badString = "<script>alert('Hacked!');</script>";
  55. $result = OC_Util::sanitizeHTML($badString);
  56. $this->assertEquals('&lt;script&gt;alert(&#039;Hacked!&#039;);&lt;/script&gt;', $result);
  57. $goodString = 'This is a good string without HTML.';
  58. $result = OC_Util::sanitizeHTML($goodString);
  59. $this->assertEquals('This is a good string without HTML.', $result);
  60. }
  61. public function testEncodePath() {
  62. $component = '/§#@test%&^ä/-child';
  63. $result = OC_Util::encodePath($component);
  64. $this->assertEquals("/%C2%A7%23%40test%25%26%5E%C3%A4/-child", $result);
  65. }
  66. public function testIsNonUTF8Locale() {
  67. // OC_Util::isNonUTF8Locale() assumes escapeshellcmd('§') returns '' with non-UTF-8 locale.
  68. $locale = setlocale(LC_CTYPE, 0);
  69. setlocale(LC_CTYPE, 'C');
  70. $this->assertEquals('', escapeshellcmd('§'));
  71. $this->assertEquals('\'\'', escapeshellarg('§'));
  72. setlocale(LC_CTYPE, 'C.UTF-8');
  73. $this->assertEquals('§', escapeshellcmd('§'));
  74. $this->assertEquals('\'§\'', escapeshellarg('§'));
  75. setlocale(LC_CTYPE, $locale);
  76. }
  77. public function testFileInfoLoaded() {
  78. $expected = function_exists('finfo_open');
  79. $this->assertEquals($expected, \OC_Util::fileInfoLoaded());
  80. }
  81. public function testGetDefaultEmailAddress() {
  82. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  83. $this->assertEquals('no-reply@localhost', $email);
  84. }
  85. public function testGetDefaultEmailAddressFromConfig() {
  86. $config = \OC::$server->getConfig();
  87. $config->setSystemValue('mail_domain', 'example.com');
  88. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  89. $this->assertEquals('no-reply@example.com', $email);
  90. $config->deleteSystemValue('mail_domain');
  91. }
  92. public function testGetConfiguredEmailAddressFromConfig() {
  93. $config = \OC::$server->getConfig();
  94. $config->setSystemValue('mail_domain', 'example.com');
  95. $config->setSystemValue('mail_from_address', 'owncloud');
  96. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  97. $this->assertEquals('owncloud@example.com', $email);
  98. $config->deleteSystemValue('mail_domain');
  99. $config->deleteSystemValue('mail_from_address');
  100. }
  101. public function testGetInstanceIdGeneratesValidId() {
  102. \OC::$server->getConfig()->deleteSystemValue('instanceid');
  103. $instanceId = OC_Util::getInstanceId();
  104. $this->assertStringStartsWith('oc', $instanceId);
  105. $matchesRegex = preg_match('/^[a-z0-9]+$/', $instanceId);
  106. $this->assertSame(1, $matchesRegex);
  107. }
  108. /**
  109. * @dataProvider filenameValidationProvider
  110. */
  111. public function testFilenameValidation($file, $valid) {
  112. // private API
  113. $this->assertEquals($valid, \OC_Util::isValidFileName($file));
  114. // public API
  115. $this->assertEquals($valid, \OCP\Util::isValidFileName($file));
  116. }
  117. public function filenameValidationProvider() {
  118. return [
  119. // valid names
  120. ['boringname', true],
  121. ['something.with.extension', true],
  122. ['now with spaces', true],
  123. ['.a', true],
  124. ['..a', true],
  125. ['.dotfile', true],
  126. ['single\'quote', true],
  127. [' spaces before', true],
  128. ['spaces after ', true],
  129. ['allowed chars including the crazy ones $%&_-^@!,()[]{}=;#', true],
  130. ['汉字也能用', true],
  131. ['und Ümläüte sind auch willkommen', true],
  132. // disallowed names
  133. ['', false],
  134. [' ', false],
  135. ['.', false],
  136. ['..', false],
  137. ['back\\slash', false],
  138. ['sl/ash', false],
  139. ['lt<lt', true],
  140. ['gt>gt', true],
  141. ['col:on', true],
  142. ['double"quote', true],
  143. ['pi|pe', true],
  144. ['dont?ask?questions?', true],
  145. ['super*star', true],
  146. ['new\nline', false],
  147. // better disallow these to avoid unexpected trimming to have side effects
  148. [' ..', false],
  149. ['.. ', false],
  150. ['. ', false],
  151. [' .', false],
  152. // part files not allowed
  153. ['.part', false],
  154. ['notallowed.part', false],
  155. ['neither.filepart', false],
  156. // part in the middle is ok
  157. ['super movie part one.mkv', true],
  158. ['super.movie.part.mkv', true],
  159. ];
  160. }
  161. /**
  162. * Test needUpgrade() when the core version is increased
  163. */
  164. public function testNeedUpgradeCore() {
  165. $config = \OC::$server->getConfig();
  166. $oldConfigVersion = $config->getSystemValue('version', '0.0.0');
  167. $oldSessionVersion = \OC::$server->getSession()->get('OC_Version');
  168. $this->assertFalse(\OCP\Util::needUpgrade());
  169. $config->setSystemValue('version', '7.0.0.0');
  170. \OC::$server->getSession()->set('OC_Version', [7, 0, 0, 1]);
  171. self::invokePrivate(new \OCP\Util, 'needUpgradeCache', [null]);
  172. $this->assertTrue(\OCP\Util::needUpgrade());
  173. $config->setSystemValue('version', $oldConfigVersion);
  174. \OC::$server->getSession()->set('OC_Version', $oldSessionVersion);
  175. self::invokePrivate(new \OCP\Util, 'needUpgradeCache', [null]);
  176. $this->assertFalse(\OCP\Util::needUpgrade());
  177. }
  178. public function testCheckDataDirectoryValidity() {
  179. $dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
  180. touch($dataDir . '/.ocdata');
  181. $errors = \OC_Util::checkDataDirectoryValidity($dataDir);
  182. $this->assertEmpty($errors);
  183. \OCP\Files::rmdirr($dataDir);
  184. $dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
  185. // no touch
  186. $errors = \OC_Util::checkDataDirectoryValidity($dataDir);
  187. $this->assertNotEmpty($errors);
  188. \OCP\Files::rmdirr($dataDir);
  189. $errors = \OC_Util::checkDataDirectoryValidity('relative/path');
  190. $this->assertNotEmpty($errors);
  191. }
  192. protected function setUp(): void {
  193. parent::setUp();
  194. \OC_Util::$scripts = [];
  195. \OC_Util::$styles = [];
  196. self::invokePrivate(\OCP\Util::class, 'scripts', [[]]);
  197. self::invokePrivate(\OCP\Util::class, 'scriptDeps', [[]]);
  198. }
  199. protected function tearDown(): void {
  200. parent::tearDown();
  201. \OC_Util::$scripts = [];
  202. \OC_Util::$styles = [];
  203. self::invokePrivate(\OCP\Util::class, 'scripts', [[]]);
  204. self::invokePrivate(\OCP\Util::class, 'scriptDeps', [[]]);
  205. }
  206. public function testAddScript() {
  207. \OCP\Util::addScript('first', 'myFirstJSFile');
  208. \OCP\Util::addScript('core', 'myFancyJSFile1');
  209. \OCP\Util::addScript('files', 'myFancyJSFile2', 'core');
  210. \OCP\Util::addScript('myApp5', 'myApp5JSFile', 'myApp2');
  211. \OCP\Util::addScript('myApp', 'myFancyJSFile3');
  212. \OCP\Util::addScript('core', 'myFancyJSFile4');
  213. // after itself
  214. \OCP\Util::addScript('core', 'myFancyJSFile5', 'core');
  215. // add duplicate
  216. \OCP\Util::addScript('core', 'myFancyJSFile1');
  217. // dependency chain
  218. \OCP\Util::addScript('myApp4', 'myApp4JSFile', 'myApp3');
  219. \OCP\Util::addScript('myApp3', 'myApp3JSFile', 'myApp2');
  220. \OCP\Util::addScript('myApp2', 'myApp2JSFile', 'myApp');
  221. $scripts = \OCP\Util::getScripts();
  222. // Core should appear first
  223. $this->assertEquals(
  224. 0,
  225. array_search('core/js/myFancyJSFile1', $scripts, true)
  226. );
  227. $this->assertEquals(
  228. 1,
  229. array_search('core/js/myFancyJSFile4', $scripts, true)
  230. );
  231. // Dependencies should appear before their children
  232. $this->assertLessThan(
  233. array_search('files/js/myFancyJSFile2', $scripts, true),
  234. array_search('core/js/myFancyJSFile3', $scripts, true)
  235. );
  236. $this->assertLessThan(
  237. array_search('myApp2/js/myApp2JSFile', $scripts, true),
  238. array_search('myApp/js/myFancyJSFile3', $scripts, true)
  239. );
  240. $this->assertLessThan(
  241. array_search('myApp3/js/myApp3JSFile', $scripts, true),
  242. array_search('myApp2/js/myApp2JSFile', $scripts, true)
  243. );
  244. $this->assertLessThan(
  245. array_search('myApp4/js/myApp4JSFile', $scripts, true),
  246. array_search('myApp3/js/myApp3JSFile', $scripts, true)
  247. );
  248. $this->assertLessThan(
  249. array_search('myApp5/js/myApp5JSFile', $scripts, true),
  250. array_search('myApp2/js/myApp2JSFile', $scripts, true)
  251. );
  252. // No duplicates
  253. $this->assertEquals(
  254. $scripts,
  255. array_unique($scripts)
  256. );
  257. // All scripts still there
  258. $scripts = [
  259. 'core/js/myFancyJSFile1',
  260. 'core/js/myFancyJSFile4',
  261. 'files/js/myFancyJSFile2',
  262. 'core/js/myFancyJSFile5',
  263. 'myApp/js/myFancyJSFile3',
  264. 'myApp2/js/myApp2JSFile',
  265. 'myApp3/js/myApp3JSFile',
  266. 'myApp4/js/myApp4JSFile',
  267. ];
  268. foreach ($scripts as $script) {
  269. $this->assertContains($script, $scripts);
  270. }
  271. }
  272. public function testAddScriptCircularDependency() {
  273. \OCP\Util::addScript('circular', 'file1', 'dependency');
  274. \OCP\Util::addScript('dependency', 'file2', 'circular');
  275. $scripts = \OCP\Util::getScripts();
  276. $this->assertContains('circular/js/file1', $scripts);
  277. $this->assertContains('dependency/js/file2', $scripts);
  278. }
  279. public function testAddVendorScript() {
  280. \OC_Util::addVendorScript('core', 'myFancyJSFile1');
  281. \OC_Util::addVendorScript('myApp', 'myFancyJSFile2');
  282. \OC_Util::addVendorScript('core', 'myFancyJSFile0', true);
  283. \OC_Util::addVendorScript('core', 'myFancyJSFile10', true);
  284. // add duplicate
  285. \OC_Util::addVendorScript('core', 'myFancyJSFile1');
  286. $this->assertEquals([
  287. 'core/vendor/myFancyJSFile10',
  288. 'core/vendor/myFancyJSFile0',
  289. 'core/vendor/myFancyJSFile1',
  290. 'myApp/vendor/myFancyJSFile2',
  291. ], \OC_Util::$scripts);
  292. $this->assertEquals([], \OC_Util::$styles);
  293. }
  294. public function testAddTranslations() {
  295. \OC_Util::addTranslations('appId', 'de');
  296. $this->assertEquals([
  297. 'appId/l10n/de'
  298. ], \OC_Util::$scripts);
  299. $this->assertEquals([], \OC_Util::$styles);
  300. }
  301. public function testAddStyle() {
  302. \OC_Util::addStyle('core', 'myFancyCSSFile1');
  303. \OC_Util::addStyle('myApp', 'myFancyCSSFile2');
  304. \OC_Util::addStyle('core', 'myFancyCSSFile0', true);
  305. \OC_Util::addStyle('core', 'myFancyCSSFile10', true);
  306. // add duplicate
  307. \OC_Util::addStyle('core', 'myFancyCSSFile1');
  308. $this->assertEquals([], \OC_Util::$scripts);
  309. $this->assertEquals([
  310. 'core/css/myFancyCSSFile10',
  311. 'core/css/myFancyCSSFile0',
  312. 'core/css/myFancyCSSFile1',
  313. 'myApp/css/myFancyCSSFile2',
  314. ], \OC_Util::$styles);
  315. }
  316. public function testAddVendorStyle() {
  317. \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
  318. \OC_Util::addVendorStyle('myApp', 'myFancyCSSFile2');
  319. \OC_Util::addVendorStyle('core', 'myFancyCSSFile0', true);
  320. \OC_Util::addVendorStyle('core', 'myFancyCSSFile10', true);
  321. // add duplicate
  322. \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
  323. $this->assertEquals([], \OC_Util::$scripts);
  324. $this->assertEquals([
  325. 'core/vendor/myFancyCSSFile10',
  326. 'core/vendor/myFancyCSSFile0',
  327. 'core/vendor/myFancyCSSFile1',
  328. 'myApp/vendor/myFancyCSSFile2',
  329. ], \OC_Util::$styles);
  330. }
  331. public function testShortenMultibyteString() {
  332. $this->assertEquals('Short nuff', \OCP\Util::shortenMultibyteString('Short nuff', 255));
  333. $this->assertEquals('ABC', \OCP\Util::shortenMultibyteString('ABCDEF', 3));
  334. // each of the characters is 12 bytes
  335. $this->assertEquals('🙈', \OCP\Util::shortenMultibyteString('🙈🙊🙉', 16, 2));
  336. }
  337. }