test-fs.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const { pathFor, platform } = require("sdk/system");
  6. const fs = require("sdk/io/fs");
  7. const url = require("sdk/url");
  8. const path = require("sdk/fs/path");
  9. const { defer } = require("sdk/core/promise");
  10. const { Buffer } = require("sdk/io/buffer");
  11. const { is } = require("sdk/system/xul-app");
  12. // Use profile directory to list / read / write files.
  13. const profilePath = pathFor("ProfD");
  14. const fileNameInProfile = "compatibility.ini";
  15. const dirNameInProfile = "extensions";
  16. const filePathInProfile = path.join(profilePath, fileNameInProfile);
  17. const dirPathInProfile = path.join(profilePath, dirNameInProfile);
  18. const mkdirPath = path.join(profilePath, "sdk-fixture-mkdir");
  19. const writePath = path.join(profilePath, "sdk-fixture-writeFile");
  20. const unlinkPath = path.join(profilePath, "sdk-fixture-unlink");
  21. const truncatePath = path.join(profilePath, "sdk-fixture-truncate");
  22. const renameFromPath = path.join(profilePath, "sdk-fixture-rename-from");
  23. const renameToPath = path.join(profilePath, "sdk-fixture-rename-to");
  24. const chmodPath = path.join(profilePath, "sdk-fixture-chmod");
  25. const profileEntries = [
  26. "compatibility.ini",
  27. "extensions",
  28. "prefs.js"
  29. // There are likely to be a lot more files but we can"t really
  30. // on consistent list so we limit to this.
  31. ];
  32. const isWindows = platform.indexOf('win') === 0;
  33. exports["test readdir"] = function(assert, end) {
  34. var async = false;
  35. fs.readdir(profilePath, function(error, entries) {
  36. assert.ok(async, "readdir is async");
  37. assert.ok(!error, "there is no error when reading directory");
  38. assert.ok(profileEntries.length <= entries.length,
  39. "got at least number of entries we expect");
  40. assert.ok(profileEntries.every(function(entry) {
  41. return entries.indexOf(entry) >= 0;
  42. }), "all profiles are present");
  43. end();
  44. });
  45. async = true;
  46. };
  47. exports["test readdir error"] = function(assert, end) {
  48. var async = false;
  49. var path = profilePath + "-does-not-exists";
  50. fs.readdir(path, function(error, entries) {
  51. assert.ok(async, "readdir is async");
  52. assert.equal(error.message, "ENOENT, readdir " + path);
  53. assert.equal(error.code, "ENOENT", "error has a code");
  54. assert.equal(error.path, path, "error has a path");
  55. assert.equal(error.errno, 34, "error has a errno");
  56. end();
  57. });
  58. async = true;
  59. };
  60. exports["test readdirSync"] = function(assert) {
  61. var async = false;
  62. var entries = fs.readdirSync(profilePath);
  63. assert.ok(profileEntries.length <= entries.length,
  64. "got at least number of entries we expect");
  65. assert.ok(profileEntries.every(function(entry) {
  66. return entries.indexOf(entry) >= 0;
  67. }), "all profiles are present");
  68. };
  69. exports["test readdirSync error"] = function(assert) {
  70. var async = false;
  71. var path = profilePath + "-does-not-exists";
  72. try {
  73. fs.readdirSync(path);
  74. assert.fail(Error("No error was thrown"));
  75. } catch (error) {
  76. assert.equal(error.message, "ENOENT, readdir " + path);
  77. assert.equal(error.code, "ENOENT", "error has a code");
  78. assert.equal(error.path, path, "error has a path");
  79. assert.equal(error.errno, 34, "error has a errno");
  80. }
  81. };
  82. exports["test readFile"] = function(assert, end) {
  83. let async = false;
  84. fs.readFile(filePathInProfile, function(error, content) {
  85. assert.ok(async, "readFile is async");
  86. assert.ok(!error, "error is falsy");
  87. assert.ok(Buffer.isBuffer(content), "readFile returns buffer");
  88. assert.ok(typeof(content.length) === "number", "buffer has length");
  89. assert.ok(content.toString().indexOf("[Compatibility]") >= 0,
  90. "content contains expected data");
  91. end();
  92. });
  93. async = true;
  94. };
  95. exports["test readFile error"] = function(assert, end) {
  96. let async = false;
  97. let path = filePathInProfile + "-does-not-exists";
  98. fs.readFile(path, function(error, content) {
  99. assert.ok(async, "readFile is async");
  100. assert.equal(error.message, "ENOENT, open " + path);
  101. assert.equal(error.code, "ENOENT", "error has a code");
  102. assert.equal(error.path, path, "error has a path");
  103. assert.equal(error.errno, 34, "error has a errno");
  104. end();
  105. });
  106. async = true;
  107. };
  108. exports["test readFileSync not implemented"] = function(assert) {
  109. let buffer = fs.readFileSync(filePathInProfile);
  110. assert.ok(buffer.toString().indexOf("[Compatibility]") >= 0,
  111. "read content");
  112. };
  113. exports["test fs.stat file"] = function(assert, end) {
  114. let async = false;
  115. let path = filePathInProfile;
  116. fs.stat(path, function(error, stat) {
  117. assert.ok(async, "fs.stat is async");
  118. assert.ok(!error, "error is falsy");
  119. assert.ok(!stat.isDirectory(), "not a dir");
  120. assert.ok(stat.isFile(), "is a file");
  121. assert.ok(!stat.isSymbolicLink(), "isn't a symlink");
  122. assert.ok(typeof(stat.size) === "number", "size is a number");
  123. assert.ok(stat.exists === true, "file exists");
  124. assert.ok(typeof(stat.isBlockDevice()) === "boolean");
  125. assert.ok(typeof(stat.isCharacterDevice()) === "boolean");
  126. assert.ok(typeof(stat.isFIFO()) === "boolean");
  127. assert.ok(typeof(stat.isSocket()) === "boolean");
  128. assert.ok(typeof(stat.hidden) === "boolean");
  129. assert.ok(typeof(stat.writable) === "boolean")
  130. assert.ok(stat.readable === true);
  131. end();
  132. });
  133. async = true;
  134. };
  135. exports["test fs.stat dir"] = function(assert, end) {
  136. let async = false;
  137. let path = dirPathInProfile;
  138. fs.stat(path, function(error, stat) {
  139. assert.ok(async, "fs.stat is async");
  140. assert.ok(!error, "error is falsy");
  141. assert.ok(stat.isDirectory(), "is a dir");
  142. assert.ok(!stat.isFile(), "not a file");
  143. assert.ok(!stat.isSymbolicLink(), "isn't a symlink");
  144. assert.ok(typeof(stat.size) === "number", "size is a number");
  145. assert.ok(stat.exists === true, "file exists");
  146. assert.ok(typeof(stat.isBlockDevice()) === "boolean");
  147. assert.ok(typeof(stat.isCharacterDevice()) === "boolean");
  148. assert.ok(typeof(stat.isFIFO()) === "boolean");
  149. assert.ok(typeof(stat.isSocket()) === "boolean");
  150. assert.ok(typeof(stat.hidden) === "boolean");
  151. assert.ok(typeof(stat.writable) === "boolean")
  152. assert.ok(typeof(stat.readable) === "boolean");
  153. end();
  154. });
  155. async = true;
  156. };
  157. exports["test fs.stat error"] = function(assert, end) {
  158. let async = false;
  159. let path = filePathInProfile + "-does-not-exists";
  160. fs.stat(path, function(error, stat) {
  161. assert.ok(async, "fs.stat is async");
  162. assert.equal(error.message, "ENOENT, stat " + path);
  163. assert.equal(error.code, "ENOENT", "error has a code");
  164. assert.equal(error.path, path, "error has a path");
  165. assert.equal(error.errno, 34, "error has a errno");
  166. end();
  167. });
  168. async = true;
  169. };
  170. exports["test fs.exists NO"] = function(assert, end) {
  171. let async = false
  172. let path = filePathInProfile + "-does-not-exists";
  173. fs.exists(path, function(error, value) {
  174. assert.ok(async, "fs.exists is async");
  175. assert.ok(!error, "error is falsy");
  176. assert.ok(!value, "file does not exists");
  177. end();
  178. });
  179. async = true;
  180. };
  181. exports["test fs.exists YES"] = function(assert, end) {
  182. let async = false
  183. let path = filePathInProfile
  184. fs.exists(path, function(error, value) {
  185. assert.ok(async, "fs.exists is async");
  186. assert.ok(!error, "error is falsy");
  187. assert.ok(value, "file exists");
  188. end();
  189. });
  190. async = true;
  191. };
  192. exports["test fs.exists NO"] = function(assert, end) {
  193. let async = false
  194. let path = filePathInProfile + "-does-not-exists";
  195. fs.exists(path, function(error, value) {
  196. assert.ok(async, "fs.exists is async");
  197. assert.ok(!error, "error is falsy");
  198. assert.ok(!value, "file does not exists");
  199. end();
  200. });
  201. async = true;
  202. };
  203. exports["test fs.existsSync"] = function(assert) {
  204. let path = filePathInProfile
  205. assert.equal(fs.existsSync(path), true, "exists");
  206. assert.equal(fs.existsSync(path + "-does-not-exists"), false, "exists");
  207. };
  208. exports["test fs.mkdirSync fs.rmdirSync"] = function(assert) {
  209. let path = mkdirPath;
  210. assert.equal(fs.existsSync(path), false, "does not exists");
  211. fs.mkdirSync(path);
  212. assert.equal(fs.existsSync(path), true, "dir was created");
  213. try {
  214. fs.mkdirSync(path);
  215. assert.fail(Error("mkdir on existing should throw"));
  216. } catch (error) {
  217. assert.equal(error.message, "EEXIST, mkdir " + path);
  218. assert.equal(error.code, "EEXIST", "error has a code");
  219. assert.equal(error.path, path, "error has a path");
  220. assert.equal(error.errno, 47, "error has a errno");
  221. }
  222. fs.rmdirSync(path);
  223. assert.equal(fs.existsSync(path), false, "dir was removed");
  224. };
  225. exports["test fs.mkdir"] = function(assert, end) {
  226. let path = mkdirPath;
  227. if (!fs.existsSync(path)) {
  228. let async = false;
  229. fs.mkdir(path, function(error) {
  230. assert.ok(async, "mkdir is async");
  231. assert.ok(!error, "no error");
  232. assert.equal(fs.existsSync(path), true, "dir was created");
  233. fs.rmdirSync(path);
  234. assert.equal(fs.existsSync(path), false, "dir was removed");
  235. end();
  236. });
  237. async = true;
  238. }
  239. };
  240. exports["test fs.mkdir error"] = function(assert, end) {
  241. let path = mkdirPath;
  242. if (!fs.existsSync(path)) {
  243. fs.mkdirSync(path);
  244. let async = false;
  245. fs.mkdir(path, function(error) {
  246. assert.ok(async, "mkdir is async");
  247. assert.equal(error.message, "EEXIST, mkdir " + path);
  248. assert.equal(error.code, "EEXIST", "error has a code");
  249. assert.equal(error.path, path, "error has a path");
  250. assert.equal(error.errno, 47, "error has a errno");
  251. fs.rmdirSync(path);
  252. assert.equal(fs.existsSync(path), false, "dir was removed");
  253. end();
  254. });
  255. async = true;
  256. }
  257. };
  258. exports["test fs.rmdir"] = function(assert, end) {
  259. let path = mkdirPath;
  260. if (!fs.existsSync(path)) {
  261. fs.mkdirSync(path);
  262. assert.equal(fs.existsSync(path), true, "dir exists");
  263. let async = false;
  264. fs.rmdir(path, function(error) {
  265. assert.ok(async, "mkdir is async");
  266. assert.ok(!error, "no error");
  267. assert.equal(fs.existsSync(path), false, "dir was removed");
  268. end();
  269. });
  270. async = true;
  271. }
  272. };
  273. exports["test fs.rmdir error"] = function(assert, end) {
  274. let path = mkdirPath;
  275. if (!fs.existsSync(path)) {
  276. assert.equal(fs.existsSync(path), false, "dir doesn't exists");
  277. let async = false;
  278. fs.rmdir(path, function(error) {
  279. assert.ok(async, "mkdir is async");
  280. assert.equal(error.message, "ENOENT, remove " + path);
  281. assert.equal(error.code, "ENOENT", "error has a code");
  282. assert.equal(error.path, path, "error has a path");
  283. assert.equal(error.errno, 34, "error has a errno");
  284. assert.equal(fs.existsSync(path), false, "dir is removed");
  285. end();
  286. });
  287. async = true;
  288. }
  289. };
  290. exports["test fs.truncateSync fs.unlinkSync"] = function(assert) {
  291. let path = truncatePath;
  292. assert.equal(fs.existsSync(path), false, "does not exists");
  293. fs.truncateSync(path);
  294. assert.equal(fs.existsSync(path), true, "file was created");
  295. fs.truncateSync(path);
  296. fs.unlinkSync(path);
  297. assert.equal(fs.existsSync(path), false, "file was removed");
  298. };
  299. exports["test fs.truncate"] = function(assert, end) {
  300. let path = truncatePath;
  301. if (!fs.existsSync(path)) {
  302. let async = false;
  303. fs.truncate(path, 0, function(error) {
  304. assert.ok(async, "truncate is async");
  305. assert.ok(!error, "no error");
  306. assert.equal(fs.existsSync(path), true, "file was created");
  307. fs.unlinkSync(path);
  308. assert.equal(fs.existsSync(path), false, "file was removed");
  309. end();
  310. })
  311. async = true;
  312. }
  313. };
  314. exports["test fs.unlink"] = function(assert, end) {
  315. let path = unlinkPath;
  316. let async = false;
  317. assert.ok(!fs.existsSync(path), "file doesn't exists yet");
  318. fs.truncateSync(path, 0);
  319. assert.ok(fs.existsSync(path), "file was created");
  320. fs.unlink(path, function(error) {
  321. assert.ok(async, "fs.unlink is async");
  322. assert.ok(!error, "error is falsy");
  323. assert.ok(!fs.existsSync(path), "file was removed");
  324. end();
  325. });
  326. async = true;
  327. };
  328. exports["test fs.unlink error"] = function(assert, end) {
  329. let path = unlinkPath;
  330. let async = false;
  331. assert.ok(!fs.existsSync(path), "file doesn't exists yet");
  332. fs.unlink(path, function(error) {
  333. assert.ok(async, "fs.unlink is async");
  334. assert.equal(error.message, "ENOENT, remove " + path);
  335. assert.equal(error.code, "ENOENT", "error has a code");
  336. assert.equal(error.path, path, "error has a path");
  337. assert.equal(error.errno, 34, "error has a errno");
  338. end();
  339. });
  340. async = true;
  341. };
  342. exports["test fs.rename"] = function(assert, end) {
  343. let fromPath = renameFromPath;
  344. let toPath = renameToPath;
  345. fs.truncateSync(fromPath);
  346. assert.ok(fs.existsSync(fromPath), "source file exists");
  347. assert.ok(!fs.existsSync(toPath), "destination doesn't exists");
  348. var async = false;
  349. fs.rename(fromPath, toPath, function(error) {
  350. assert.ok(async, "fs.rename is async");
  351. assert.ok(!error, "error is falsy");
  352. assert.ok(!fs.existsSync(fromPath), "source path no longer exists");
  353. assert.ok(fs.existsSync(toPath), "destination file exists");
  354. fs.unlinkSync(toPath);
  355. assert.ok(!fs.existsSync(toPath), "cleaned up properly");
  356. end();
  357. });
  358. async = true;
  359. };
  360. exports["test fs.rename (missing source file)"] = function(assert, end) {
  361. let fromPath = renameFromPath;
  362. let toPath = renameToPath;
  363. assert.ok(!fs.existsSync(fromPath), "source file doesn't exists");
  364. assert.ok(!fs.existsSync(toPath), "destination doesn't exists");
  365. var async = false;
  366. fs.rename(fromPath, toPath, function(error) {
  367. assert.ok(async, "fs.rename is async");
  368. assert.equal(error.message, "ENOENT, rename " + fromPath);
  369. assert.equal(error.code, "ENOENT", "error has a code");
  370. assert.equal(error.path, fromPath, "error has a path");
  371. assert.equal(error.errno, 34, "error has a errno");
  372. end();
  373. });
  374. async = true;
  375. };
  376. exports["test fs.rename (existing target file)"] = function(assert, end) {
  377. let fromPath = renameFromPath;
  378. let toPath = renameToPath;
  379. fs.truncateSync(fromPath);
  380. fs.truncateSync(toPath);
  381. assert.ok(fs.existsSync(fromPath), "source file exists");
  382. assert.ok(fs.existsSync(toPath), "destination file exists");
  383. var async = false;
  384. fs.rename(fromPath, toPath, function(error) {
  385. assert.ok(async, "fs.rename is async");
  386. assert.ok(!error, "error is falsy");
  387. assert.ok(!fs.existsSync(fromPath), "source path no longer exists");
  388. assert.ok(fs.existsSync(toPath), "destination file exists");
  389. fs.unlinkSync(toPath);
  390. assert.ok(!fs.existsSync(toPath), "cleaned up properly");
  391. end();
  392. });
  393. async = true;
  394. };
  395. exports["test fs.writeFile"] = function(assert, end) {
  396. let path = writePath;
  397. let content = ["hello world",
  398. "this is some text"].join("\n");
  399. var async = false;
  400. fs.writeFile(path, content, function(error) {
  401. assert.ok(async, "fs write is async");
  402. assert.ok(!error, "error is falsy");
  403. assert.ok(fs.existsSync(path), "file was created");
  404. assert.equal(fs.readFileSync(path).toString(),
  405. content,
  406. "contet was written");
  407. fs.unlinkSync(path);
  408. assert.ok(!fs.exists(path), "file was removed");
  409. end();
  410. });
  411. async = true;
  412. };
  413. exports["test fs.writeFile (with large files)"] = function(assert, end) {
  414. let path = writePath;
  415. let content = "";
  416. for (var i = 0; i < 100000; i++) {
  417. content += "buffer\n";
  418. }
  419. var async = false;
  420. fs.writeFile(path, content, function(error) {
  421. assert.ok(async, "fs write is async");
  422. assert.ok(!error, "error is falsy");
  423. assert.ok(fs.existsSync(path), "file was created");
  424. assert.equal(fs.readFileSync(path).toString(),
  425. content,
  426. "contet was written");
  427. fs.unlinkSync(path);
  428. assert.ok(!fs.exists(path), "file was removed");
  429. end();
  430. });
  431. async = true;
  432. };
  433. exports["test fs.writeFile error"] = function (assert, done) {
  434. try {
  435. fs.writeFile({}, 'content', function (err) {
  436. assert.fail('Error thrown from TypeError should not be caught');
  437. });
  438. } catch (e) {
  439. assert.ok(e,
  440. 'writeFile with a non-string error should not be caught');
  441. assert.equal(e.name, 'TypeError', 'error should be TypeError');
  442. }
  443. fs.writeFile('not/a/valid/path', 'content', function (err) {
  444. assert.ok(err, 'error caught and handled in callback');
  445. done();
  446. });
  447. };
  448. exports["test fs.chmod"] = function (assert, done) {
  449. let content = ["hej från sverige"];
  450. fs.writeFile(chmodPath, content, function (err) {
  451. testPerm("0755")()
  452. .then(testPerm("0777"))
  453. .then(testPerm("0666"))
  454. .then(testPerm(parseInt("0511", 8)))
  455. .then(testPerm(parseInt("0200", 8)))
  456. .then(testPerm("0040"))
  457. .then(testPerm("0000"))
  458. .then(testPermSync(parseInt("0777", 8)))
  459. .then(testPermSync(parseInt("0666", 8)))
  460. .then(testPermSync("0511"))
  461. .then(testPermSync("0200"))
  462. .then(testPermSync("0040"))
  463. .then(testPermSync("0000"))
  464. .then(() => {
  465. assert.pass("Successful chmod passes");
  466. }, assert.fail)
  467. // Test invalid paths
  468. .then(() => chmod("not-a-valid-file", parseInt("0755", 8)))
  469. .then(assert.fail, (err) => {
  470. checkPermError(err, "not-a-valid-file");
  471. })
  472. .then(() => chmod("not-a-valid-file", parseInt("0755", 8), "sync"))
  473. .then(assert.fail, (err) => {
  474. checkPermError(err, "not-a-valid-file");
  475. })
  476. // Test invalid files
  477. .then(() => chmod("resource://not-a-real-file", parseInt("0755", 8)))
  478. .then(assert.fail, (err) => {
  479. checkPermError(err, "resource://not-a-real-file");
  480. })
  481. .then(() => chmod("resource://not-a-real-file", parseInt("0755", 8), 'sync'))
  482. .then(assert.fail, (err) => {
  483. checkPermError(err, "resource://not-a-real-file");
  484. })
  485. .then(done, assert.fail);
  486. });
  487. function checkPermError (err, path) {
  488. assert.equal(err.message, "ENOENT, chmod " + path);
  489. assert.equal(err.code, "ENOENT", "error has a code");
  490. assert.equal(err.path, path, "error has a path");
  491. assert.equal(err.errno, 34, "error has a errno");
  492. }
  493. function chmod (path, mode, sync) {
  494. let { promise, resolve, reject } = defer();
  495. if (!sync) {
  496. fs.chmod(path, mode, (err) => {
  497. if (err) reject(err);
  498. else resolve();
  499. });
  500. } else {
  501. fs.chmodSync(path, mode);
  502. resolve();
  503. }
  504. return promise;
  505. }
  506. function testPerm (mode, sync) {
  507. return function () {
  508. return chmod(chmodPath, mode, sync)
  509. .then(() => getPerm(chmodPath))
  510. .then(perm => {
  511. let nMode = normalizeMode(mode);
  512. if (isWindows)
  513. assert.equal(perm, nMode,
  514. "mode correctly set to " + mode + " (" + nMode + " on windows)");
  515. else
  516. assert.equal(perm, nMode, "mode correctly set to " + nMode);
  517. });
  518. };
  519. }
  520. function testPermSync (mode) {
  521. return testPerm(mode, true);
  522. }
  523. function getPerm (path) {
  524. let { promise, resolve, reject } = defer();
  525. fs.stat(path, function (err, stat) {
  526. if (err) reject(err);
  527. else resolve(stat.mode);
  528. });
  529. return promise;
  530. }
  531. /*
  532. * Converts a unix mode `0755` into a Windows version of unix permissions
  533. */
  534. function normalizeMode (mode) {
  535. if (typeof mode === "string")
  536. mode = parseInt(mode, 8);
  537. if (!isWindows)
  538. return mode;
  539. var ANY_READ = parseInt("0444", 8);
  540. var ANY_WRITE = parseInt("0222", 8);
  541. var winMode = 0;
  542. // On Windows, if WRITE is true, then READ is also true
  543. if (mode & ANY_WRITE)
  544. winMode |= ANY_WRITE | ANY_READ;
  545. // Minimum permissions are READ for Windows
  546. else
  547. winMode |= ANY_READ;
  548. return winMode;
  549. }
  550. };
  551. require("test").run(exports);