asar-spec.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514
  1. const chai = require('chai');
  2. const dirtyChai = require('dirty-chai');
  3. const ChildProcess = require('child_process');
  4. const fs = require('fs');
  5. const path = require('path');
  6. const temp = require('temp').track();
  7. const util = require('util');
  8. const nativeImage = require('electron').nativeImage;
  9. const features = process.electronBinding('features');
  10. const { expect } = chai;
  11. chai.use(dirtyChai);
  12. async function expectToThrowErrorWithCode (func, code) {
  13. let error;
  14. try {
  15. await func();
  16. } catch (e) {
  17. error = e;
  18. }
  19. expect(error).is.an('Error');
  20. expect(error).to.have.property('code').which.equals(code);
  21. }
  22. describe('asar package', function () {
  23. const fixtures = path.join(__dirname, 'fixtures');
  24. const asarDir = path.join(fixtures, 'test.asar');
  25. describe('node api', function () {
  26. it('supports paths specified as a Buffer', function () {
  27. const file = Buffer.from(path.join(asarDir, 'a.asar', 'file1'));
  28. expect(fs.existsSync(file)).to.be.true();
  29. });
  30. describe('fs.readFileSync', function () {
  31. it('does not leak fd', function () {
  32. let readCalls = 1;
  33. while (readCalls <= 10000) {
  34. fs.readFileSync(path.join(process.resourcesPath, 'default_app.asar', 'main.js'));
  35. readCalls++;
  36. }
  37. });
  38. it('reads a normal file', function () {
  39. const file1 = path.join(asarDir, 'a.asar', 'file1');
  40. expect(fs.readFileSync(file1).toString().trim()).to.equal('file1');
  41. const file2 = path.join(asarDir, 'a.asar', 'file2');
  42. expect(fs.readFileSync(file2).toString().trim()).to.equal('file2');
  43. const file3 = path.join(asarDir, 'a.asar', 'file3');
  44. expect(fs.readFileSync(file3).toString().trim()).to.equal('file3');
  45. });
  46. it('reads from a empty file', function () {
  47. const file = path.join(asarDir, 'empty.asar', 'file1');
  48. const buffer = fs.readFileSync(file);
  49. expect(buffer).to.be.empty();
  50. expect(buffer.toString()).to.equal('');
  51. });
  52. it('reads a linked file', function () {
  53. const p = path.join(asarDir, 'a.asar', 'link1');
  54. expect(fs.readFileSync(p).toString().trim()).to.equal('file1');
  55. });
  56. it('reads a file from linked directory', function () {
  57. const p1 = path.join(asarDir, 'a.asar', 'link2', 'file1');
  58. expect(fs.readFileSync(p1).toString().trim()).to.equal('file1');
  59. const p2 = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  60. expect(fs.readFileSync(p2).toString().trim()).to.equal('file1');
  61. });
  62. it('throws ENOENT error when can not find file', function () {
  63. const p = path.join(asarDir, 'a.asar', 'not-exist');
  64. expect(() => {
  65. fs.readFileSync(p);
  66. }).to.throw(/ENOENT/);
  67. });
  68. it('passes ENOENT error to callback when can not find file', function () {
  69. const p = path.join(asarDir, 'a.asar', 'not-exist');
  70. let async = false;
  71. fs.readFile(p, function (error) {
  72. expect(async).to.be.true();
  73. expect(error).to.match(/ENOENT/);
  74. });
  75. async = true;
  76. });
  77. it('reads a normal file with unpacked files', function () {
  78. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  79. expect(fs.readFileSync(p).toString().trim()).to.equal('a');
  80. });
  81. it('reads a file in filesystem', function () {
  82. const p = path.resolve(asarDir, 'file');
  83. expect(fs.readFileSync(p).toString().trim()).to.equal('file');
  84. });
  85. });
  86. describe('fs.readFile', function () {
  87. it('reads a normal file', function (done) {
  88. const p = path.join(asarDir, 'a.asar', 'file1');
  89. fs.readFile(p, function (err, content) {
  90. expect(err).to.be.null();
  91. expect(String(content).trim()).to.equal('file1');
  92. done();
  93. });
  94. });
  95. it('reads from a empty file', function (done) {
  96. const p = path.join(asarDir, 'empty.asar', 'file1');
  97. fs.readFile(p, function (err, content) {
  98. expect(err).to.be.null();
  99. expect(String(content)).to.equal('');
  100. done();
  101. });
  102. });
  103. it('reads from a empty file with encoding', function (done) {
  104. const p = path.join(asarDir, 'empty.asar', 'file1');
  105. fs.readFile(p, 'utf8', function (err, content) {
  106. expect(err).to.be.null();
  107. expect(content).to.equal('');
  108. done();
  109. });
  110. });
  111. it('reads a linked file', function (done) {
  112. const p = path.join(asarDir, 'a.asar', 'link1');
  113. fs.readFile(p, function (err, content) {
  114. expect(err).to.be.null();
  115. expect(String(content).trim()).to.equal('file1');
  116. done();
  117. });
  118. });
  119. it('reads a file from linked directory', function (done) {
  120. const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  121. fs.readFile(p, function (err, content) {
  122. expect(err).to.be.null();
  123. expect(String(content).trim()).to.equal('file1');
  124. done();
  125. });
  126. });
  127. it('throws ENOENT error when can not find file', function (done) {
  128. const p = path.join(asarDir, 'a.asar', 'not-exist');
  129. fs.readFile(p, function (err) {
  130. expect(err.code).to.equal('ENOENT');
  131. done();
  132. });
  133. });
  134. });
  135. describe('fs.promises.readFile', function () {
  136. it('reads a normal file', async function () {
  137. const p = path.join(asarDir, 'a.asar', 'file1');
  138. const content = await fs.promises.readFile(p);
  139. expect(String(content).trim()).to.equal('file1');
  140. });
  141. it('reads from a empty file', async function () {
  142. const p = path.join(asarDir, 'empty.asar', 'file1');
  143. const content = await fs.promises.readFile(p);
  144. expect(String(content)).to.equal('');
  145. });
  146. it('reads from a empty file with encoding', async function () {
  147. const p = path.join(asarDir, 'empty.asar', 'file1');
  148. const content = await fs.promises.readFile(p, 'utf8');
  149. expect(content).to.equal('');
  150. });
  151. it('reads a linked file', async function () {
  152. const p = path.join(asarDir, 'a.asar', 'link1');
  153. const content = await fs.promises.readFile(p);
  154. expect(String(content).trim()).to.equal('file1');
  155. });
  156. it('reads a file from linked directory', async function () {
  157. const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  158. const content = await fs.promises.readFile(p);
  159. expect(String(content).trim()).to.equal('file1');
  160. });
  161. it('throws ENOENT error when can not find file', async function () {
  162. const p = path.join(asarDir, 'a.asar', 'not-exist');
  163. await expectToThrowErrorWithCode(() => fs.promises.readFile(p), 'ENOENT');
  164. });
  165. });
  166. describe('fs.copyFile', function () {
  167. it('copies a normal file', function (done) {
  168. const p = path.join(asarDir, 'a.asar', 'file1');
  169. const dest = temp.path();
  170. fs.copyFile(p, dest, function (err) {
  171. expect(err).to.be.null();
  172. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  173. done();
  174. });
  175. });
  176. it('copies a unpacked file', function (done) {
  177. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  178. const dest = temp.path();
  179. fs.copyFile(p, dest, function (err) {
  180. expect(err).to.be.null();
  181. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  182. done();
  183. });
  184. });
  185. });
  186. describe('fs.promises.copyFile', function () {
  187. it('copies a normal file', async function () {
  188. const p = path.join(asarDir, 'a.asar', 'file1');
  189. const dest = temp.path();
  190. await fs.promises.copyFile(p, dest);
  191. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  192. });
  193. it('copies a unpacked file', async function () {
  194. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  195. const dest = temp.path();
  196. await fs.promises.copyFile(p, dest);
  197. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  198. });
  199. });
  200. describe('fs.copyFileSync', function () {
  201. it('copies a normal file', function () {
  202. const p = path.join(asarDir, 'a.asar', 'file1');
  203. const dest = temp.path();
  204. fs.copyFileSync(p, dest);
  205. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  206. });
  207. it('copies a unpacked file', function () {
  208. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  209. const dest = temp.path();
  210. fs.copyFileSync(p, dest);
  211. expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
  212. });
  213. });
  214. describe('fs.lstatSync', function () {
  215. it('handles path with trailing slash correctly', function () {
  216. const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  217. fs.lstatSync(p);
  218. fs.lstatSync(p + '/');
  219. });
  220. it('returns information of root', function () {
  221. const p = path.join(asarDir, 'a.asar');
  222. const stats = fs.lstatSync(p);
  223. expect(stats.isFile()).to.be.false();
  224. expect(stats.isDirectory()).to.be.true();
  225. expect(stats.isSymbolicLink()).to.be.false();
  226. expect(stats.size).to.equal(0);
  227. });
  228. it('returns information of root with stats as bigint', function () {
  229. const p = path.join(asarDir, 'a.asar');
  230. const stats = fs.lstatSync(p, { bigint: false });
  231. expect(stats.isFile()).to.be.false();
  232. expect(stats.isDirectory()).to.be.true();
  233. expect(stats.isSymbolicLink()).to.be.false();
  234. expect(stats.size).to.equal(0);
  235. });
  236. it('returns information of a normal file', function () {
  237. const ref2 = ['file1', 'file2', 'file3', path.join('dir1', 'file1'), path.join('link2', 'file1')];
  238. for (let j = 0, len = ref2.length; j < len; j++) {
  239. const file = ref2[j];
  240. const p = path.join(asarDir, 'a.asar', file);
  241. const stats = fs.lstatSync(p);
  242. expect(stats.isFile()).to.be.true();
  243. expect(stats.isDirectory()).to.be.false();
  244. expect(stats.isSymbolicLink()).to.be.false();
  245. expect(stats.size).to.equal(6);
  246. }
  247. });
  248. it('returns information of a normal directory', function () {
  249. const ref2 = ['dir1', 'dir2', 'dir3'];
  250. for (let j = 0, len = ref2.length; j < len; j++) {
  251. const file = ref2[j];
  252. const p = path.join(asarDir, 'a.asar', file);
  253. const stats = fs.lstatSync(p);
  254. expect(stats.isFile()).to.be.false();
  255. expect(stats.isDirectory()).to.be.true();
  256. expect(stats.isSymbolicLink()).to.be.false();
  257. expect(stats.size).to.equal(0);
  258. }
  259. });
  260. it('returns information of a linked file', function () {
  261. const ref2 = ['link1', path.join('dir1', 'link1'), path.join('link2', 'link2')];
  262. for (let j = 0, len = ref2.length; j < len; j++) {
  263. const file = ref2[j];
  264. const p = path.join(asarDir, 'a.asar', file);
  265. const stats = fs.lstatSync(p);
  266. expect(stats.isFile()).to.be.false();
  267. expect(stats.isDirectory()).to.be.false();
  268. expect(stats.isSymbolicLink()).to.be.true();
  269. expect(stats.size).to.equal(0);
  270. }
  271. });
  272. it('returns information of a linked directory', function () {
  273. const ref2 = ['link2', path.join('dir1', 'link2'), path.join('link2', 'link2')];
  274. for (let j = 0, len = ref2.length; j < len; j++) {
  275. const file = ref2[j];
  276. const p = path.join(asarDir, 'a.asar', file);
  277. const stats = fs.lstatSync(p);
  278. expect(stats.isFile()).to.be.false();
  279. expect(stats.isDirectory()).to.be.false();
  280. expect(stats.isSymbolicLink()).to.be.true();
  281. expect(stats.size).to.equal(0);
  282. }
  283. });
  284. it('throws ENOENT error when can not find file', function () {
  285. const ref2 = ['file4', 'file5', path.join('dir1', 'file4')];
  286. for (let j = 0, len = ref2.length; j < len; j++) {
  287. const file = ref2[j];
  288. const p = path.join(asarDir, 'a.asar', file);
  289. expect(() => {
  290. fs.lstatSync(p);
  291. }).to.throw(/ENOENT/);
  292. }
  293. });
  294. });
  295. describe('fs.lstat', function () {
  296. it('handles path with trailing slash correctly', function (done) {
  297. const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  298. fs.lstat(p + '/', done);
  299. });
  300. it('returns information of root', function (done) {
  301. const p = path.join(asarDir, 'a.asar');
  302. fs.lstat(p, function (err, stats) {
  303. expect(err).to.be.null();
  304. expect(stats.isFile()).to.be.false();
  305. expect(stats.isDirectory()).to.be.true();
  306. expect(stats.isSymbolicLink()).to.be.false();
  307. expect(stats.size).to.equal(0);
  308. done();
  309. });
  310. });
  311. it('returns information of root with stats as bigint', function (done) {
  312. const p = path.join(asarDir, 'a.asar');
  313. fs.lstat(p, { bigint: false }, function (err, stats) {
  314. expect(err).to.be.null();
  315. expect(stats.isFile()).to.be.false();
  316. expect(stats.isDirectory()).to.be.true();
  317. expect(stats.isSymbolicLink()).to.be.false();
  318. expect(stats.size).to.equal(0);
  319. done();
  320. });
  321. });
  322. it('returns information of a normal file', function (done) {
  323. const p = path.join(asarDir, 'a.asar', 'link2', 'file1');
  324. fs.lstat(p, function (err, stats) {
  325. expect(err).to.be.null();
  326. expect(stats.isFile()).to.be.true();
  327. expect(stats.isDirectory()).to.be.false();
  328. expect(stats.isSymbolicLink()).to.be.false();
  329. expect(stats.size).to.equal(6);
  330. done();
  331. });
  332. });
  333. it('returns information of a normal directory', function (done) {
  334. const p = path.join(asarDir, 'a.asar', 'dir1');
  335. fs.lstat(p, function (err, stats) {
  336. expect(err).to.be.null();
  337. expect(stats.isFile()).to.be.false();
  338. expect(stats.isDirectory()).to.be.true();
  339. expect(stats.isSymbolicLink()).to.be.false();
  340. expect(stats.size).to.equal(0);
  341. done();
  342. });
  343. });
  344. it('returns information of a linked file', function (done) {
  345. const p = path.join(asarDir, 'a.asar', 'link2', 'link1');
  346. fs.lstat(p, function (err, stats) {
  347. expect(err).to.be.null();
  348. expect(stats.isFile()).to.be.false();
  349. expect(stats.isDirectory()).to.be.false();
  350. expect(stats.isSymbolicLink()).to.be.true();
  351. expect(stats.size).to.equal(0);
  352. done();
  353. });
  354. });
  355. it('returns information of a linked directory', function (done) {
  356. const p = path.join(asarDir, 'a.asar', 'link2', 'link2');
  357. fs.lstat(p, function (err, stats) {
  358. expect(err).to.be.null();
  359. expect(stats.isFile()).to.be.false();
  360. expect(stats.isDirectory()).to.be.false();
  361. expect(stats.isSymbolicLink()).to.be.true();
  362. expect(stats.size).to.equal(0);
  363. done();
  364. });
  365. });
  366. it('throws ENOENT error when can not find file', function (done) {
  367. const p = path.join(asarDir, 'a.asar', 'file4');
  368. fs.lstat(p, function (err) {
  369. expect(err.code).to.equal('ENOENT');
  370. done();
  371. });
  372. });
  373. });
  374. describe('fs.promises.lstat', function () {
  375. it('handles path with trailing slash correctly', async function () {
  376. const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');
  377. await fs.promises.lstat(p + '/');
  378. });
  379. it('returns information of root', async function () {
  380. const p = path.join(asarDir, 'a.asar');
  381. const stats = await fs.promises.lstat(p);
  382. expect(stats.isFile()).to.be.false();
  383. expect(stats.isDirectory()).to.be.true();
  384. expect(stats.isSymbolicLink()).to.be.false();
  385. expect(stats.size).to.equal(0);
  386. });
  387. it('returns information of root with stats as bigint', async function () {
  388. const p = path.join(asarDir, 'a.asar');
  389. const stats = await fs.promises.lstat(p, { bigint: false });
  390. expect(stats.isFile()).to.be.false();
  391. expect(stats.isDirectory()).to.be.true();
  392. expect(stats.isSymbolicLink()).to.be.false();
  393. expect(stats.size).to.equal(0);
  394. });
  395. it('returns information of a normal file', async function () {
  396. const p = path.join(asarDir, 'a.asar', 'link2', 'file1');
  397. const stats = await fs.promises.lstat(p);
  398. expect(stats.isFile()).to.be.true();
  399. expect(stats.isDirectory()).to.be.false();
  400. expect(stats.isSymbolicLink()).to.be.false();
  401. expect(stats.size).to.equal(6);
  402. });
  403. it('returns information of a normal directory', async function () {
  404. const p = path.join(asarDir, 'a.asar', 'dir1');
  405. const stats = await fs.promises.lstat(p);
  406. expect(stats.isFile()).to.be.false();
  407. expect(stats.isDirectory()).to.be.true();
  408. expect(stats.isSymbolicLink()).to.be.false();
  409. expect(stats.size).to.equal(0);
  410. });
  411. it('returns information of a linked file', async function () {
  412. const p = path.join(asarDir, 'a.asar', 'link2', 'link1');
  413. const stats = await fs.promises.lstat(p);
  414. expect(stats.isFile()).to.be.false();
  415. expect(stats.isDirectory()).to.be.false();
  416. expect(stats.isSymbolicLink()).to.be.true();
  417. expect(stats.size).to.equal(0);
  418. });
  419. it('returns information of a linked directory', async function () {
  420. const p = path.join(asarDir, 'a.asar', 'link2', 'link2');
  421. const stats = await fs.promises.lstat(p);
  422. expect(stats.isFile()).to.be.false();
  423. expect(stats.isDirectory()).to.be.false();
  424. expect(stats.isSymbolicLink()).to.be.true();
  425. expect(stats.size).to.equal(0);
  426. });
  427. it('throws ENOENT error when can not find file', async function () {
  428. const p = path.join(asarDir, 'a.asar', 'file4');
  429. await expectToThrowErrorWithCode(() => fs.promises.lstat(p), 'ENOENT');
  430. });
  431. });
  432. describe('fs.realpathSync', () => {
  433. it('returns real path root', () => {
  434. const parent = fs.realpathSync(asarDir);
  435. const p = 'a.asar';
  436. const r = fs.realpathSync(path.join(parent, p));
  437. expect(r).to.equal(path.join(parent, p));
  438. });
  439. it('returns real path of a normal file', () => {
  440. const parent = fs.realpathSync(asarDir);
  441. const p = path.join('a.asar', 'file1');
  442. const r = fs.realpathSync(path.join(parent, p));
  443. expect(r).to.equal(path.join(parent, p));
  444. });
  445. it('returns real path of a normal directory', () => {
  446. const parent = fs.realpathSync(asarDir);
  447. const p = path.join('a.asar', 'dir1');
  448. const r = fs.realpathSync(path.join(parent, p));
  449. expect(r).to.equal(path.join(parent, p));
  450. });
  451. it('returns real path of a linked file', () => {
  452. const parent = fs.realpathSync(asarDir);
  453. const p = path.join('a.asar', 'link2', 'link1');
  454. const r = fs.realpathSync(path.join(parent, p));
  455. expect(r).to.equal(path.join(parent, 'a.asar', 'file1'));
  456. });
  457. it('returns real path of a linked directory', () => {
  458. const parent = fs.realpathSync(asarDir);
  459. const p = path.join('a.asar', 'link2', 'link2');
  460. const r = fs.realpathSync(path.join(parent, p));
  461. expect(r).to.equal(path.join(parent, 'a.asar', 'dir1'));
  462. });
  463. it('returns real path of an unpacked file', () => {
  464. const parent = fs.realpathSync(asarDir);
  465. const p = path.join('unpack.asar', 'a.txt');
  466. const r = fs.realpathSync(path.join(parent, p));
  467. expect(r).to.equal(path.join(parent, p));
  468. });
  469. it('throws ENOENT error when can not find file', () => {
  470. const parent = fs.realpathSync(asarDir);
  471. const p = path.join('a.asar', 'not-exist');
  472. expect(() => {
  473. fs.realpathSync(path.join(parent, p));
  474. }).to.throw(/ENOENT/);
  475. });
  476. });
  477. describe('fs.realpathSync.native', () => {
  478. it('returns real path root', () => {
  479. const parent = fs.realpathSync.native(asarDir);
  480. const p = 'a.asar';
  481. const r = fs.realpathSync.native(path.join(parent, p));
  482. expect(r).to.equal(path.join(parent, p));
  483. });
  484. it('returns real path of a normal file', () => {
  485. const parent = fs.realpathSync.native(asarDir);
  486. const p = path.join('a.asar', 'file1');
  487. const r = fs.realpathSync.native(path.join(parent, p));
  488. expect(r).to.equal(path.join(parent, p));
  489. });
  490. it('returns real path of a normal directory', () => {
  491. const parent = fs.realpathSync.native(asarDir);
  492. const p = path.join('a.asar', 'dir1');
  493. const r = fs.realpathSync.native(path.join(parent, p));
  494. expect(r).to.equal(path.join(parent, p));
  495. });
  496. it('returns real path of a linked file', () => {
  497. const parent = fs.realpathSync.native(asarDir);
  498. const p = path.join('a.asar', 'link2', 'link1');
  499. const r = fs.realpathSync.native(path.join(parent, p));
  500. expect(r).to.equal(path.join(parent, 'a.asar', 'file1'));
  501. });
  502. it('returns real path of a linked directory', () => {
  503. const parent = fs.realpathSync.native(asarDir);
  504. const p = path.join('a.asar', 'link2', 'link2');
  505. const r = fs.realpathSync.native(path.join(parent, p));
  506. expect(r).to.equal(path.join(parent, 'a.asar', 'dir1'));
  507. });
  508. it('returns real path of an unpacked file', () => {
  509. const parent = fs.realpathSync.native(asarDir);
  510. const p = path.join('unpack.asar', 'a.txt');
  511. const r = fs.realpathSync.native(path.join(parent, p));
  512. expect(r).to.equal(path.join(parent, p));
  513. });
  514. it('throws ENOENT error when can not find file', () => {
  515. const parent = fs.realpathSync.native(asarDir);
  516. const p = path.join('a.asar', 'not-exist');
  517. expect(() => {
  518. fs.realpathSync.native(path.join(parent, p));
  519. }).to.throw(/ENOENT/);
  520. });
  521. });
  522. describe('fs.realpath', () => {
  523. it('returns real path root', done => {
  524. const parent = fs.realpathSync(asarDir);
  525. const p = 'a.asar';
  526. fs.realpath(path.join(parent, p), (err, r) => {
  527. expect(err).to.be.null();
  528. expect(r).to.equal(path.join(parent, p));
  529. done();
  530. });
  531. });
  532. it('returns real path of a normal file', done => {
  533. const parent = fs.realpathSync(asarDir);
  534. const p = path.join('a.asar', 'file1');
  535. fs.realpath(path.join(parent, p), (err, r) => {
  536. expect(err).to.be.null();
  537. expect(r).to.equal(path.join(parent, p));
  538. done();
  539. });
  540. });
  541. it('returns real path of a normal directory', done => {
  542. const parent = fs.realpathSync(asarDir);
  543. const p = path.join('a.asar', 'dir1');
  544. fs.realpath(path.join(parent, p), (err, r) => {
  545. expect(err).to.be.null();
  546. expect(r).to.equal(path.join(parent, p));
  547. done();
  548. });
  549. });
  550. it('returns real path of a linked file', done => {
  551. const parent = fs.realpathSync(asarDir);
  552. const p = path.join('a.asar', 'link2', 'link1');
  553. fs.realpath(path.join(parent, p), (err, r) => {
  554. expect(err).to.be.null();
  555. expect(r).to.equal(path.join(parent, 'a.asar', 'file1'));
  556. done();
  557. });
  558. });
  559. it('returns real path of a linked directory', done => {
  560. const parent = fs.realpathSync(asarDir);
  561. const p = path.join('a.asar', 'link2', 'link2');
  562. fs.realpath(path.join(parent, p), (err, r) => {
  563. expect(err).to.be.null();
  564. expect(r).to.equal(path.join(parent, 'a.asar', 'dir1'));
  565. done();
  566. });
  567. });
  568. it('returns real path of an unpacked file', done => {
  569. const parent = fs.realpathSync(asarDir);
  570. const p = path.join('unpack.asar', 'a.txt');
  571. fs.realpath(path.join(parent, p), (err, r) => {
  572. expect(err).to.be.null();
  573. expect(r).to.equal(path.join(parent, p));
  574. done();
  575. });
  576. });
  577. it('throws ENOENT error when can not find file', done => {
  578. const parent = fs.realpathSync(asarDir);
  579. const p = path.join('a.asar', 'not-exist');
  580. fs.realpath(path.join(parent, p), err => {
  581. expect(err.code).to.equal('ENOENT');
  582. done();
  583. });
  584. });
  585. });
  586. describe('fs.promises.realpath', () => {
  587. it('returns real path root', async () => {
  588. const parent = fs.realpathSync(asarDir);
  589. const p = 'a.asar';
  590. const r = await fs.promises.realpath(path.join(parent, p));
  591. expect(r).to.equal(path.join(parent, p));
  592. });
  593. it('returns real path of a normal file', async () => {
  594. const parent = fs.realpathSync(asarDir);
  595. const p = path.join('a.asar', 'file1');
  596. const r = await fs.promises.realpath(path.join(parent, p));
  597. expect(r).to.equal(path.join(parent, p));
  598. });
  599. it('returns real path of a normal directory', async () => {
  600. const parent = fs.realpathSync(asarDir);
  601. const p = path.join('a.asar', 'dir1');
  602. const r = await fs.promises.realpath(path.join(parent, p));
  603. expect(r).to.equal(path.join(parent, p));
  604. });
  605. it('returns real path of a linked file', async () => {
  606. const parent = fs.realpathSync(asarDir);
  607. const p = path.join('a.asar', 'link2', 'link1');
  608. const r = await fs.promises.realpath(path.join(parent, p));
  609. expect(r).to.equal(path.join(parent, 'a.asar', 'file1'));
  610. });
  611. it('returns real path of a linked directory', async () => {
  612. const parent = fs.realpathSync(asarDir);
  613. const p = path.join('a.asar', 'link2', 'link2');
  614. const r = await fs.promises.realpath(path.join(parent, p));
  615. expect(r).to.equal(path.join(parent, 'a.asar', 'dir1'));
  616. });
  617. it('returns real path of an unpacked file', async () => {
  618. const parent = fs.realpathSync(asarDir);
  619. const p = path.join('unpack.asar', 'a.txt');
  620. const r = await fs.promises.realpath(path.join(parent, p));
  621. expect(r).to.equal(path.join(parent, p));
  622. });
  623. it('throws ENOENT error when can not find file', async () => {
  624. const parent = fs.realpathSync(asarDir);
  625. const p = path.join('a.asar', 'not-exist');
  626. await expectToThrowErrorWithCode(() => fs.promises.realpath(path.join(parent, p)), 'ENOENT');
  627. });
  628. });
  629. describe('fs.realpath.native', () => {
  630. it('returns real path root', done => {
  631. const parent = fs.realpathSync.native(asarDir);
  632. const p = 'a.asar';
  633. fs.realpath.native(path.join(parent, p), (err, r) => {
  634. expect(err).to.be.null();
  635. expect(r).to.equal(path.join(parent, p));
  636. done();
  637. });
  638. });
  639. it('returns real path of a normal file', done => {
  640. const parent = fs.realpathSync.native(asarDir);
  641. const p = path.join('a.asar', 'file1');
  642. fs.realpath.native(path.join(parent, p), (err, r) => {
  643. expect(err).to.be.null();
  644. expect(r).to.equal(path.join(parent, p));
  645. done();
  646. });
  647. });
  648. it('returns real path of a normal directory', done => {
  649. const parent = fs.realpathSync.native(asarDir);
  650. const p = path.join('a.asar', 'dir1');
  651. fs.realpath.native(path.join(parent, p), (err, r) => {
  652. expect(err).to.be.null();
  653. expect(r).to.equal(path.join(parent, p));
  654. done();
  655. });
  656. });
  657. it('returns real path of a linked file', done => {
  658. const parent = fs.realpathSync.native(asarDir);
  659. const p = path.join('a.asar', 'link2', 'link1');
  660. fs.realpath.native(path.join(parent, p), (err, r) => {
  661. expect(err).to.be.null();
  662. expect(r).to.equal(path.join(parent, 'a.asar', 'file1'));
  663. done();
  664. });
  665. });
  666. it('returns real path of a linked directory', done => {
  667. const parent = fs.realpathSync.native(asarDir);
  668. const p = path.join('a.asar', 'link2', 'link2');
  669. fs.realpath.native(path.join(parent, p), (err, r) => {
  670. expect(err).to.be.null();
  671. expect(r).to.equal(path.join(parent, 'a.asar', 'dir1'));
  672. done();
  673. });
  674. });
  675. it('returns real path of an unpacked file', done => {
  676. const parent = fs.realpathSync.native(asarDir);
  677. const p = path.join('unpack.asar', 'a.txt');
  678. fs.realpath.native(path.join(parent, p), (err, r) => {
  679. expect(err).to.be.null();
  680. expect(r).to.equal(path.join(parent, p));
  681. done();
  682. });
  683. });
  684. it('throws ENOENT error when can not find file', done => {
  685. const parent = fs.realpathSync.native(asarDir);
  686. const p = path.join('a.asar', 'not-exist');
  687. fs.realpath.native(path.join(parent, p), err => {
  688. expect(err.code).to.equal('ENOENT');
  689. done();
  690. });
  691. });
  692. });
  693. describe('fs.readdirSync', function () {
  694. it('reads dirs from root', function () {
  695. const p = path.join(asarDir, 'a.asar');
  696. const dirs = fs.readdirSync(p);
  697. expect(dirs).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  698. });
  699. it('reads dirs from a normal dir', function () {
  700. const p = path.join(asarDir, 'a.asar', 'dir1');
  701. const dirs = fs.readdirSync(p);
  702. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  703. });
  704. it('supports withFileTypes', function () {
  705. const p = path.join(asarDir, 'a.asar');
  706. const dirs = fs.readdirSync(p, { withFileTypes: true });
  707. for (const dir of dirs) {
  708. expect(dir instanceof fs.Dirent).to.be.true();
  709. }
  710. const names = dirs.map(a => a.name);
  711. expect(names).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  712. });
  713. it('reads dirs from a linked dir', function () {
  714. const p = path.join(asarDir, 'a.asar', 'link2', 'link2');
  715. const dirs = fs.readdirSync(p);
  716. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  717. });
  718. it('throws ENOENT error when can not find file', function () {
  719. const p = path.join(asarDir, 'a.asar', 'not-exist');
  720. expect(() => {
  721. fs.readdirSync(p);
  722. }).to.throw(/ENOENT/);
  723. });
  724. });
  725. describe('fs.readdir', function () {
  726. it('reads dirs from root', function (done) {
  727. const p = path.join(asarDir, 'a.asar');
  728. fs.readdir(p, function (err, dirs) {
  729. expect(err).to.be.null();
  730. expect(dirs).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  731. done();
  732. });
  733. });
  734. it('supports withFileTypes', function (done) {
  735. const p = path.join(asarDir, 'a.asar');
  736. fs.readdir(p, { withFileTypes: true }, (err, dirs) => {
  737. expect(err).to.be.null();
  738. for (const dir of dirs) {
  739. expect(dir instanceof fs.Dirent).to.be.true();
  740. }
  741. const names = dirs.map(a => a.name);
  742. expect(names).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  743. done();
  744. });
  745. });
  746. it('reads dirs from a normal dir', function (done) {
  747. const p = path.join(asarDir, 'a.asar', 'dir1');
  748. fs.readdir(p, function (err, dirs) {
  749. expect(err).to.be.null();
  750. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  751. done();
  752. });
  753. });
  754. it('reads dirs from a linked dir', function (done) {
  755. const p = path.join(asarDir, 'a.asar', 'link2', 'link2');
  756. fs.readdir(p, function (err, dirs) {
  757. expect(err).to.be.null();
  758. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  759. done();
  760. });
  761. });
  762. it('throws ENOENT error when can not find file', function (done) {
  763. const p = path.join(asarDir, 'a.asar', 'not-exist');
  764. fs.readdir(p, function (err) {
  765. expect(err.code).to.equal('ENOENT');
  766. done();
  767. });
  768. });
  769. });
  770. describe('fs.promises.readdir', function () {
  771. it('reads dirs from root', async function () {
  772. const p = path.join(asarDir, 'a.asar');
  773. const dirs = await fs.promises.readdir(p);
  774. expect(dirs).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  775. });
  776. it('supports withFileTypes', async function () {
  777. const p = path.join(asarDir, 'a.asar');
  778. const dirs = await fs.promises.readdir(p, { withFileTypes: true });
  779. for (const dir of dirs) {
  780. expect(dir instanceof fs.Dirent).to.be.true();
  781. }
  782. const names = dirs.map(a => a.name);
  783. expect(names).to.deep.equal(['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']);
  784. });
  785. it('reads dirs from a normal dir', async function () {
  786. const p = path.join(asarDir, 'a.asar', 'dir1');
  787. const dirs = await fs.promises.readdir(p);
  788. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  789. });
  790. it('reads dirs from a linked dir', async function () {
  791. const p = path.join(asarDir, 'a.asar', 'link2', 'link2');
  792. const dirs = await fs.promises.readdir(p);
  793. expect(dirs).to.deep.equal(['file1', 'file2', 'file3', 'link1', 'link2']);
  794. });
  795. it('throws ENOENT error when can not find file', async function () {
  796. const p = path.join(asarDir, 'a.asar', 'not-exist');
  797. await expectToThrowErrorWithCode(() => fs.promises.readdir(p), 'ENOENT');
  798. });
  799. });
  800. describe('fs.openSync', function () {
  801. it('opens a normal/linked/under-linked-directory file', function () {
  802. const ref2 = ['file1', 'link1', path.join('link2', 'file1')];
  803. for (let j = 0, len = ref2.length; j < len; j++) {
  804. const file = ref2[j];
  805. const p = path.join(asarDir, 'a.asar', file);
  806. const fd = fs.openSync(p, 'r');
  807. const buffer = Buffer.alloc(6);
  808. fs.readSync(fd, buffer, 0, 6, 0);
  809. expect(String(buffer).trim()).to.equal('file1');
  810. fs.closeSync(fd);
  811. }
  812. });
  813. it('throws ENOENT error when can not find file', function () {
  814. const p = path.join(asarDir, 'a.asar', 'not-exist');
  815. expect(() => {
  816. fs.openSync(p);
  817. }).to.throw(/ENOENT/);
  818. });
  819. });
  820. describe('fs.open', function () {
  821. it('opens a normal file', function (done) {
  822. const p = path.join(asarDir, 'a.asar', 'file1');
  823. fs.open(p, 'r', function (err, fd) {
  824. expect(err).to.be.null();
  825. const buffer = Buffer.alloc(6);
  826. fs.read(fd, buffer, 0, 6, 0, function (err) {
  827. expect(err).to.be.null();
  828. expect(String(buffer).trim()).to.equal('file1');
  829. fs.close(fd, done);
  830. });
  831. });
  832. });
  833. it('throws ENOENT error when can not find file', function (done) {
  834. const p = path.join(asarDir, 'a.asar', 'not-exist');
  835. fs.open(p, 'r', function (err) {
  836. expect(err.code).to.equal('ENOENT');
  837. done();
  838. });
  839. });
  840. });
  841. describe('fs.promises.open', function () {
  842. it('opens a normal file', async function () {
  843. const p = path.join(asarDir, 'a.asar', 'file1');
  844. const fh = await fs.promises.open(p, 'r');
  845. const buffer = Buffer.alloc(6);
  846. await fh.read(buffer, 0, 6, 0);
  847. expect(String(buffer).trim()).to.equal('file1');
  848. await fh.close();
  849. });
  850. it('throws ENOENT error when can not find file', async function () {
  851. const p = path.join(asarDir, 'a.asar', 'not-exist');
  852. await expectToThrowErrorWithCode(() => fs.promises.open(p, 'r'), 'ENOENT');
  853. });
  854. });
  855. describe('fs.mkdir', function () {
  856. it('throws error when calling inside asar archive', function (done) {
  857. const p = path.join(asarDir, 'a.asar', 'not-exist');
  858. fs.mkdir(p, function (err) {
  859. expect(err.code).to.equal('ENOTDIR');
  860. done();
  861. });
  862. });
  863. });
  864. describe('fs.promises.mkdir', function () {
  865. it('throws error when calling inside asar archive', async function () {
  866. const p = path.join(asarDir, 'a.asar', 'not-exist');
  867. await expectToThrowErrorWithCode(() => fs.promises.mkdir(p), 'ENOTDIR');
  868. });
  869. });
  870. describe('fs.mkdirSync', function () {
  871. it('throws error when calling inside asar archive', function () {
  872. const p = path.join(asarDir, 'a.asar', 'not-exist');
  873. expect(() => {
  874. fs.mkdirSync(p);
  875. }).to.throw(/ENOTDIR/);
  876. });
  877. });
  878. describe('fs.exists', function () {
  879. it('handles an existing file', function (done) {
  880. const p = path.join(asarDir, 'a.asar', 'file1');
  881. // eslint-disable-next-line
  882. fs.exists(p, function (exists) {
  883. expect(exists).to.be.true();
  884. done();
  885. });
  886. });
  887. it('handles a non-existent file', function (done) {
  888. const p = path.join(asarDir, 'a.asar', 'not-exist');
  889. // eslint-disable-next-line
  890. fs.exists(p, function (exists) {
  891. expect(exists).to.be.false();
  892. done();
  893. });
  894. });
  895. it('promisified version handles an existing file', (done) => {
  896. const p = path.join(asarDir, 'a.asar', 'file1');
  897. // eslint-disable-next-line
  898. util.promisify(fs.exists)(p).then(exists => {
  899. expect(exists).to.be.true();
  900. done();
  901. });
  902. });
  903. it('promisified version handles a non-existent file', function (done) {
  904. const p = path.join(asarDir, 'a.asar', 'not-exist');
  905. // eslint-disable-next-line
  906. util.promisify(fs.exists)(p).then(exists => {
  907. expect(exists).to.be.false();
  908. done();
  909. });
  910. });
  911. });
  912. describe('fs.existsSync', function () {
  913. it('handles an existing file', function () {
  914. const p = path.join(asarDir, 'a.asar', 'file1');
  915. expect(fs.existsSync(p)).to.be.true();
  916. });
  917. it('handles a non-existent file', function () {
  918. const p = path.join(asarDir, 'a.asar', 'not-exist');
  919. expect(fs.existsSync(p)).to.be.false();
  920. });
  921. });
  922. describe('fs.access', function () {
  923. it('accesses a normal file', function (done) {
  924. const p = path.join(asarDir, 'a.asar', 'file1');
  925. fs.access(p, function (err) {
  926. expect(err).to.be.undefined();
  927. done();
  928. });
  929. });
  930. it('throws an error when called with write mode', function (done) {
  931. const p = path.join(asarDir, 'a.asar', 'file1');
  932. fs.access(p, fs.constants.R_OK | fs.constants.W_OK, function (err) {
  933. expect(err.code).to.equal('EACCES');
  934. done();
  935. });
  936. });
  937. it('throws an error when called on non-existent file', function (done) {
  938. const p = path.join(asarDir, 'a.asar', 'not-exist');
  939. fs.access(p, function (err) {
  940. expect(err.code).to.equal('ENOENT');
  941. done();
  942. });
  943. });
  944. it('allows write mode for unpacked files', function (done) {
  945. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  946. fs.access(p, fs.constants.R_OK | fs.constants.W_OK, function (err) {
  947. expect(err).to.be.null();
  948. done();
  949. });
  950. });
  951. });
  952. describe('fs.promises.access', function () {
  953. it('accesses a normal file', async function () {
  954. const p = path.join(asarDir, 'a.asar', 'file1');
  955. await fs.promises.access(p);
  956. });
  957. it('throws an error when called with write mode', async function () {
  958. const p = path.join(asarDir, 'a.asar', 'file1');
  959. await expectToThrowErrorWithCode(() => fs.promises.access(p, fs.constants.R_OK | fs.constants.W_OK), 'EACCES');
  960. });
  961. it('throws an error when called on non-existent file', async function () {
  962. const p = path.join(asarDir, 'a.asar', 'not-exist');
  963. await expectToThrowErrorWithCode(() => fs.promises.access(p), 'ENOENT');
  964. });
  965. it('allows write mode for unpacked files', async function () {
  966. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  967. await fs.promises.access(p, fs.constants.R_OK | fs.constants.W_OK);
  968. });
  969. });
  970. describe('fs.accessSync', function () {
  971. it('accesses a normal file', function () {
  972. const p = path.join(asarDir, 'a.asar', 'file1');
  973. expect(() => {
  974. fs.accessSync(p);
  975. }).to.not.throw();
  976. });
  977. it('throws an error when called with write mode', function () {
  978. const p = path.join(asarDir, 'a.asar', 'file1');
  979. expect(() => {
  980. fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK);
  981. }).to.throw(/EACCES/);
  982. });
  983. it('throws an error when called on non-existent file', function () {
  984. const p = path.join(asarDir, 'a.asar', 'not-exist');
  985. expect(() => {
  986. fs.accessSync(p);
  987. }).to.throw(/ENOENT/);
  988. });
  989. it('allows write mode for unpacked files', function () {
  990. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  991. expect(() => {
  992. fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK);
  993. }).to.not.throw();
  994. });
  995. });
  996. describe('child_process.fork', function () {
  997. before(function () {
  998. if (!features.isRunAsNodeEnabled()) {
  999. this.skip();
  1000. }
  1001. });
  1002. it('opens a normal js file', function (done) {
  1003. const child = ChildProcess.fork(path.join(asarDir, 'a.asar', 'ping.js'));
  1004. child.on('message', function (msg) {
  1005. expect(msg).to.equal('message');
  1006. done();
  1007. });
  1008. child.send('message');
  1009. });
  1010. it('supports asar in the forked js', function (done) {
  1011. const file = path.join(asarDir, 'a.asar', 'file1');
  1012. const child = ChildProcess.fork(path.join(fixtures, 'module', 'asar.js'));
  1013. child.on('message', function (content) {
  1014. expect(content).to.equal(fs.readFileSync(file).toString());
  1015. done();
  1016. });
  1017. child.send(file);
  1018. });
  1019. });
  1020. describe('child_process.exec', function () {
  1021. const echo = path.join(asarDir, 'echo.asar', 'echo');
  1022. it('should not try to extract the command if there is a reference to a file inside an .asar', function (done) {
  1023. ChildProcess.exec('echo ' + echo + ' foo bar', function (error, stdout) {
  1024. expect(error).to.be.null();
  1025. expect(stdout.toString().replace(/\r/g, '')).to.equal(echo + ' foo bar\n');
  1026. done();
  1027. });
  1028. });
  1029. it('can be promisified', () => {
  1030. return util.promisify(ChildProcess.exec)('echo ' + echo + ' foo bar').then(({ stdout }) => {
  1031. expect(stdout.toString().replace(/\r/g, '')).to.equal(echo + ' foo bar\n');
  1032. });
  1033. });
  1034. });
  1035. describe('child_process.execSync', function () {
  1036. const echo = path.join(asarDir, 'echo.asar', 'echo');
  1037. it('should not try to extract the command if there is a reference to a file inside an .asar', function (done) {
  1038. const stdout = ChildProcess.execSync('echo ' + echo + ' foo bar');
  1039. expect(stdout.toString().replace(/\r/g, '')).to.equal(echo + ' foo bar\n');
  1040. done();
  1041. });
  1042. });
  1043. describe('child_process.execFile', function () {
  1044. const execFile = ChildProcess.execFile;
  1045. const execFileSync = ChildProcess.execFileSync;
  1046. const echo = path.join(asarDir, 'echo.asar', 'echo');
  1047. before(function () {
  1048. if (process.platform !== 'darwin') {
  1049. this.skip();
  1050. }
  1051. });
  1052. it('executes binaries', function (done) {
  1053. execFile(echo, ['test'], function (error, stdout) {
  1054. expect(error).to.be.null();
  1055. expect(stdout).to.equal('test\n');
  1056. done();
  1057. });
  1058. });
  1059. it('executes binaries without callback', function (done) {
  1060. const process = execFile(echo, ['test']);
  1061. process.on('close', function (code) {
  1062. expect(code).to.equal(0);
  1063. done();
  1064. });
  1065. process.on('error', function () {
  1066. expect.fail();
  1067. done();
  1068. });
  1069. });
  1070. it('execFileSync executes binaries', function () {
  1071. const output = execFileSync(echo, ['test']);
  1072. expect(String(output)).to.equal('test\n');
  1073. });
  1074. it('can be promisified', () => {
  1075. return util.promisify(ChildProcess.execFile)(echo, ['test']).then(({ stdout }) => {
  1076. expect(stdout).to.equal('test\n');
  1077. });
  1078. });
  1079. });
  1080. describe('internalModuleReadJSON', function () {
  1081. const internalModuleReadJSON = process.binding('fs').internalModuleReadJSON;
  1082. it('read a normal file', function () {
  1083. const file1 = path.join(asarDir, 'a.asar', 'file1');
  1084. expect(internalModuleReadJSON(file1).toString().trim()).to.equal('file1');
  1085. const file2 = path.join(asarDir, 'a.asar', 'file2');
  1086. expect(internalModuleReadJSON(file2).toString().trim()).to.equal('file2');
  1087. const file3 = path.join(asarDir, 'a.asar', 'file3');
  1088. expect(internalModuleReadJSON(file3).toString().trim()).to.equal('file3');
  1089. });
  1090. it('reads a normal file with unpacked files', function () {
  1091. const p = path.join(asarDir, 'unpack.asar', 'a.txt');
  1092. expect(internalModuleReadJSON(p).toString().trim()).to.equal('a');
  1093. });
  1094. });
  1095. describe('util.promisify', function () {
  1096. it('can promisify all fs functions', function () {
  1097. const originalFs = require('original-fs');
  1098. const { hasOwnProperty } = Object.prototype;
  1099. for (const [propertyName, originalValue] of Object.entries(originalFs)) {
  1100. // Some properties exist but have a value of `undefined` on some platforms.
  1101. // E.g. `fs.lchmod`, which in only available on MacOS, see
  1102. // https://nodejs.org/docs/latest-v10.x/api/fs.html#fs_fs_lchmod_path_mode_callback
  1103. // Also check for `null`s, `hasOwnProperty()` can't handle them.
  1104. if (typeof originalValue === 'undefined' || originalValue === null) continue;
  1105. if (hasOwnProperty.call(originalValue, util.promisify.custom)) {
  1106. expect(fs).to.have.own.property(propertyName)
  1107. .that.has.own.property(util.promisify.custom);
  1108. }
  1109. }
  1110. });
  1111. });
  1112. describe('process.noAsar', function () {
  1113. const errorName = process.platform === 'win32' ? 'ENOENT' : 'ENOTDIR';
  1114. beforeEach(function () {
  1115. process.noAsar = true;
  1116. });
  1117. afterEach(function () {
  1118. process.noAsar = false;
  1119. });
  1120. it('disables asar support in sync API', function () {
  1121. const file = path.join(asarDir, 'a.asar', 'file1');
  1122. const dir = path.join(asarDir, 'a.asar', 'dir1');
  1123. expect(() => {
  1124. fs.readFileSync(file);
  1125. }).to.throw(new RegExp(errorName));
  1126. expect(() => {
  1127. fs.lstatSync(file);
  1128. }).to.throw(new RegExp(errorName));
  1129. expect(() => {
  1130. fs.realpathSync(file);
  1131. }).to.throw(new RegExp(errorName));
  1132. expect(() => {
  1133. fs.readdirSync(dir);
  1134. }).to.throw(new RegExp(errorName));
  1135. });
  1136. it('disables asar support in async API', function (done) {
  1137. const file = path.join(asarDir, 'a.asar', 'file1');
  1138. const dir = path.join(asarDir, 'a.asar', 'dir1');
  1139. fs.readFile(file, function (error) {
  1140. expect(error.code).to.equal(errorName);
  1141. fs.lstat(file, function (error) {
  1142. expect(error.code).to.equal(errorName);
  1143. fs.realpath(file, function (error) {
  1144. expect(error.code).to.equal(errorName);
  1145. fs.readdir(dir, function (error) {
  1146. expect(error.code).to.equal(errorName);
  1147. done();
  1148. });
  1149. });
  1150. });
  1151. });
  1152. });
  1153. it('disables asar support in promises API', async function () {
  1154. const file = path.join(asarDir, 'a.asar', 'file1');
  1155. const dir = path.join(asarDir, 'a.asar', 'dir1');
  1156. await expect(fs.promises.readFile(file)).to.be.eventually.rejectedWith(Error, new RegExp(errorName));
  1157. await expect(fs.promises.lstat(file)).to.be.eventually.rejectedWith(Error, new RegExp(errorName));
  1158. await expect(fs.promises.realpath(file)).to.be.eventually.rejectedWith(Error, new RegExp(errorName));
  1159. await expect(fs.promises.readdir(dir)).to.be.eventually.rejectedWith(Error, new RegExp(errorName));
  1160. });
  1161. it('treats *.asar as normal file', function () {
  1162. const originalFs = require('original-fs');
  1163. const asar = path.join(asarDir, 'a.asar');
  1164. const content1 = fs.readFileSync(asar);
  1165. const content2 = originalFs.readFileSync(asar);
  1166. expect(content1.compare(content2)).to.equal(0);
  1167. expect(() => {
  1168. fs.readdirSync(asar);
  1169. }).to.throw(/ENOTDIR/);
  1170. });
  1171. it('is reset to its original value when execSync throws an error', function () {
  1172. process.noAsar = false;
  1173. expect(() => {
  1174. ChildProcess.execSync(path.join(__dirname, 'does-not-exist.txt'));
  1175. }).to.throw();
  1176. expect(process.noAsar).to.be.false();
  1177. });
  1178. });
  1179. describe('process.env.ELECTRON_NO_ASAR', function () {
  1180. before(function () {
  1181. if (!features.isRunAsNodeEnabled()) {
  1182. this.skip();
  1183. }
  1184. });
  1185. it('disables asar support in forked processes', function (done) {
  1186. const forked = ChildProcess.fork(path.join(__dirname, 'fixtures', 'module', 'no-asar.js'), [], {
  1187. env: {
  1188. ELECTRON_NO_ASAR: true
  1189. }
  1190. });
  1191. forked.on('message', function (stats) {
  1192. expect(stats.isFile).to.be.true();
  1193. expect(stats.size).to.equal(778);
  1194. done();
  1195. });
  1196. });
  1197. it('disables asar support in spawned processes', function (done) {
  1198. const spawned = ChildProcess.spawn(process.execPath, [path.join(__dirname, 'fixtures', 'module', 'no-asar.js')], {
  1199. env: {
  1200. ELECTRON_NO_ASAR: true,
  1201. ELECTRON_RUN_AS_NODE: true
  1202. }
  1203. });
  1204. let output = '';
  1205. spawned.stdout.on('data', function (data) {
  1206. output += data;
  1207. });
  1208. spawned.stdout.on('close', function () {
  1209. const stats = JSON.parse(output);
  1210. expect(stats.isFile).to.be.true();
  1211. expect(stats.size).to.equal(778);
  1212. done();
  1213. });
  1214. });
  1215. });
  1216. });
  1217. describe('asar protocol', function () {
  1218. it('can request a file in package', function (done) {
  1219. const p = path.resolve(asarDir, 'a.asar', 'file1');
  1220. $.get('file://' + p, function (data) {
  1221. expect(data.trim()).to.equal('file1');
  1222. done();
  1223. });
  1224. });
  1225. it('can request a file in package with unpacked files', function (done) {
  1226. const p = path.resolve(asarDir, 'unpack.asar', 'a.txt');
  1227. $.get('file://' + p, function (data) {
  1228. expect(data.trim()).to.equal('a');
  1229. done();
  1230. });
  1231. });
  1232. it('can request a linked file in package', function (done) {
  1233. const p = path.resolve(asarDir, 'a.asar', 'link2', 'link1');
  1234. $.get('file://' + p, function (data) {
  1235. expect(data.trim()).to.equal('file1');
  1236. done();
  1237. });
  1238. });
  1239. it('can request a file in filesystem', function (done) {
  1240. const p = path.resolve(asarDir, 'file');
  1241. $.get('file://' + p, function (data) {
  1242. expect(data.trim()).to.equal('file');
  1243. done();
  1244. });
  1245. });
  1246. it('gets 404 when file is not found', function (done) {
  1247. const p = path.resolve(asarDir, 'a.asar', 'no-exist');
  1248. $.ajax({
  1249. url: 'file://' + p,
  1250. error: function (err) {
  1251. expect(err.status).to.equal(404);
  1252. done();
  1253. }
  1254. });
  1255. });
  1256. });
  1257. describe('original-fs module', function () {
  1258. const originalFs = require('original-fs');
  1259. it('treats .asar as file', function () {
  1260. const file = path.join(asarDir, 'a.asar');
  1261. const stats = originalFs.statSync(file);
  1262. expect(stats.isFile()).to.be.true();
  1263. });
  1264. it('is available in forked scripts', function (done) {
  1265. if (!features.isRunAsNodeEnabled()) {
  1266. this.skip();
  1267. done();
  1268. }
  1269. const child = ChildProcess.fork(path.join(fixtures, 'module', 'original-fs.js'));
  1270. child.on('message', function (msg) {
  1271. expect(msg).to.equal('object');
  1272. done();
  1273. });
  1274. child.send('message');
  1275. });
  1276. it('can be used with streams', () => {
  1277. originalFs.createReadStream(path.join(asarDir, 'a.asar'));
  1278. });
  1279. it('can recursively delete a directory with an asar file in it', () => {
  1280. const deleteDir = path.join(asarDir, 'deleteme');
  1281. originalFs.rmdirSync(deleteDir, { recursive: true });
  1282. expect(fs.existsSync(deleteDir)).to.be.false();
  1283. });
  1284. it('has the same APIs as fs', function () {
  1285. expect(Object.keys(require('fs'))).to.deep.equal(Object.keys(require('original-fs')));
  1286. expect(Object.keys(require('fs').promises)).to.deep.equal(Object.keys(require('original-fs').promises));
  1287. });
  1288. });
  1289. describe('graceful-fs module', function () {
  1290. const gfs = require('graceful-fs');
  1291. it('recognize asar archvies', function () {
  1292. const p = path.join(asarDir, 'a.asar', 'link1');
  1293. expect(gfs.readFileSync(p).toString().trim()).to.equal('file1');
  1294. });
  1295. it('does not touch global fs object', function () {
  1296. expect(fs.readdir).to.not.equal(gfs.readdir);
  1297. });
  1298. });
  1299. describe('mkdirp module', function () {
  1300. const mkdirp = require('mkdirp');
  1301. it('throws error when calling inside asar archive', function () {
  1302. const p = path.join(asarDir, 'a.asar', 'not-exist');
  1303. expect(() => {
  1304. mkdirp.sync(p);
  1305. }).to.throw(/ENOTDIR/);
  1306. });
  1307. });
  1308. describe('native-image', function () {
  1309. it('reads image from asar archive', function () {
  1310. const p = path.join(asarDir, 'logo.asar', 'logo.png');
  1311. const logo = nativeImage.createFromPath(p);
  1312. expect(logo.getSize()).to.deep.equal({
  1313. width: 55,
  1314. height: 55
  1315. });
  1316. });
  1317. it('reads image from asar archive with unpacked files', function () {
  1318. const p = path.join(asarDir, 'unpack.asar', 'atom.png');
  1319. const logo = nativeImage.createFromPath(p);
  1320. expect(logo.getSize()).to.deep.equal({
  1321. width: 1024,
  1322. height: 1024
  1323. });
  1324. });
  1325. });
  1326. });