SourceCodeReader.spec.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. import * as fs from 'fs';
  2. import * as mkdirp from 'mkdirp';
  3. import * as rimraf from 'rimraf';
  4. import { assert } from 'chai';
  5. import * as sinon from 'sinon';
  6. import { IFileData } from '../../../../src/interfaces/cli/IFileData';
  7. import { SourceCodeReader } from '../../../../src/cli/utils/SourceCodeReader';
  8. describe('SourceCodeReader', () => {
  9. const expectedError: RegExp = /Given input path must be a valid/;
  10. const fileContent: string = 'test';
  11. const tmpDirectoryPath: string = 'test/tmp';
  12. before(() => {
  13. mkdirp.sync(tmpDirectoryPath);
  14. });
  15. describe('readSourceCode', () => {
  16. describe('Variant #1: input path is a file path', () => {
  17. describe('Variant #1: `inputPath` is a valid path', () => {
  18. const tmpFileName: string = 'test.js';
  19. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  20. const expectedFilesData: IFileData[] = [{
  21. content: fileContent,
  22. filePath: inputPath
  23. }];
  24. let filesData: IFileData[];
  25. before(() => {
  26. fs.writeFileSync(inputPath, fileContent);
  27. filesData = new SourceCodeReader(inputPath, {}).readSourceCode();
  28. });
  29. it('should return valid files data', () => {
  30. assert.deepEqual(filesData, expectedFilesData);
  31. });
  32. after(() => {
  33. fs.unlinkSync(inputPath);
  34. });
  35. });
  36. describe('Variant #2: `inputPath` is not a valid path', () => {
  37. const tmpFileName: string = 'test.js';
  38. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  39. let testFunc: () => void;
  40. before(() => {
  41. testFunc = () => new SourceCodeReader(inputPath, {}).readSourceCode();
  42. });
  43. it('should throw an error if `inputPath` is not a valid path', () => {
  44. assert.throws(testFunc, expectedError);
  45. });
  46. });
  47. describe('Variant #3: `inputPath` has invalid extension', () => {
  48. const tmpFileName: string = 'test.ts';
  49. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  50. let testFunc: () => void;
  51. before(() => {
  52. fs.writeFileSync(inputPath, fileContent);
  53. testFunc = () => new SourceCodeReader(inputPath, {}).readSourceCode();
  54. });
  55. it('should throw an error if `inputPath` has invalid extension', () => {
  56. assert.throws(testFunc, expectedError);
  57. });
  58. after(() => {
  59. fs.unlinkSync(inputPath);
  60. });
  61. });
  62. describe('Variant #4: `exclude` option', () => {
  63. describe('Variant #1: `inputPath` isn\'t excluded path', () => {
  64. const tmpFileName: string = 'test.js';
  65. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  66. const expectedFilesData: IFileData[] = [{
  67. content: fileContent,
  68. filePath: inputPath
  69. }];
  70. let filesData: IFileData[];
  71. before(() => {
  72. fs.writeFileSync(inputPath, fileContent);
  73. filesData = new SourceCodeReader(
  74. inputPath,
  75. {
  76. exclude: ['**/foo.js']
  77. }
  78. ).readSourceCode();
  79. });
  80. it('should return valid files data', () => {
  81. assert.deepEqual(filesData, expectedFilesData);
  82. });
  83. after(() => {
  84. fs.unlinkSync(inputPath);
  85. });
  86. });
  87. describe('Variant #2: `inputPath` is excluded path', () => {
  88. describe('Variant #1: exclude by `glob` pattern', () => {
  89. const tmpFileName: string = 'test.js';
  90. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  91. let testFunc: () => void;
  92. before(() => {
  93. fs.writeFileSync(inputPath, fileContent);
  94. testFunc = () => new SourceCodeReader(
  95. inputPath,
  96. {
  97. exclude: [`**/${tmpFileName}`]
  98. }
  99. ).readSourceCode();
  100. });
  101. it('should throw an error if `inputPath` is the excluded file path', () => {
  102. assert.throws(testFunc, expectedError);
  103. });
  104. after(() => {
  105. fs.unlinkSync(inputPath);
  106. });
  107. });
  108. describe('Variant #2: exclude by file name', () => {
  109. const tmpFileName: string = 'test.js';
  110. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  111. let testFunc: () => void;
  112. before(() => {
  113. fs.writeFileSync(inputPath, fileContent);
  114. testFunc = () => new SourceCodeReader(
  115. inputPath,
  116. {
  117. exclude: [tmpFileName]
  118. }
  119. ).readSourceCode();
  120. });
  121. it('should throw an error if `inputPath` is the excluded file path', () => {
  122. assert.throws(testFunc, expectedError);
  123. });
  124. after(() => {
  125. fs.unlinkSync(inputPath);
  126. });
  127. });
  128. describe('Variant #3: exclude by file path', () => {
  129. const tmpFileName: string = 'test.js';
  130. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  131. let testFunc: () => void;
  132. before(() => {
  133. fs.writeFileSync(inputPath, fileContent);
  134. testFunc = () => new SourceCodeReader(
  135. inputPath,
  136. {
  137. exclude: [inputPath]
  138. }
  139. ).readSourceCode();
  140. });
  141. it('should throw an error if `inputPath` is the excluded file path', () => {
  142. assert.throws(testFunc, expectedError);
  143. });
  144. after(() => {
  145. fs.unlinkSync(inputPath);
  146. });
  147. });
  148. });
  149. });
  150. });
  151. describe('Variant #2: input path is a directory path', () => {
  152. describe('Variant #1: `inputPath` is a valid path', () => {
  153. const tmpFileName1: string = 'foo.js';
  154. const tmpFileName2: string = 'bar.js';
  155. const tmpFileName3: string = 'baz.png';
  156. const tmpFileName4: string = 'bark-obfuscated.js';
  157. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  158. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  159. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  160. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  161. const expectedResult: IFileData[] = [
  162. {
  163. filePath: filePath2,
  164. content: fileContent
  165. },
  166. {
  167. filePath: filePath1,
  168. content: fileContent
  169. }
  170. ];
  171. let result: IFileData[];
  172. before(() => {
  173. fs.writeFileSync(filePath1, fileContent);
  174. fs.writeFileSync(filePath2, fileContent);
  175. fs.writeFileSync(filePath3, fileContent);
  176. fs.writeFileSync(filePath4, fileContent);
  177. result = new SourceCodeReader(tmpDirectoryPath, {}).readSourceCode();
  178. });
  179. it('should return files data', () => {
  180. assert.deepEqual(result, expectedResult);
  181. });
  182. after(() => {
  183. fs.unlinkSync(filePath1);
  184. fs.unlinkSync(filePath2);
  185. fs.unlinkSync(filePath3);
  186. fs.unlinkSync(filePath4);
  187. });
  188. });
  189. describe('Variant #2: `inputPath` is not a valid path', () => {
  190. const inputPath: string = 'abc';
  191. let testFunc: () => void;
  192. before(() => {
  193. testFunc = () => new SourceCodeReader(inputPath, {}).readSourceCode();
  194. });
  195. it('should throw an error if `inputPath` is not a valid path', () => {
  196. assert.throws(testFunc, expectedError);
  197. });
  198. });
  199. describe('Variant #3: `inputPath` is a directory with sub-directories', () => {
  200. const parentDirectoryName1: string = 'parent1';
  201. const parentDirectoryName2: string = 'parent';
  202. const parentDirectoryPath1: string = `${tmpDirectoryPath}/${parentDirectoryName1}`;
  203. const parentDirectoryPath2: string = `${tmpDirectoryPath}/${parentDirectoryName2}`;
  204. const tmpFileName1: string = 'foo.js';
  205. const tmpFileName2: string = 'bar.js';
  206. const tmpFileName3: string = 'baz.js';
  207. const tmpFileName4: string = 'bark.js';
  208. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  209. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  210. const filePath3: string = `${parentDirectoryPath1}/${tmpFileName3}`;
  211. const filePath4: string = `${parentDirectoryPath2}/${tmpFileName4}`;
  212. const expectedResult: IFileData[] = [
  213. {
  214. filePath: filePath2,
  215. content: fileContent
  216. },
  217. {
  218. filePath: filePath1,
  219. content: fileContent
  220. },
  221. {
  222. filePath: filePath4,
  223. content: fileContent
  224. },
  225. {
  226. filePath: filePath3,
  227. content: fileContent
  228. }
  229. ];
  230. let result: IFileData[];
  231. before(() => {
  232. mkdirp.sync(parentDirectoryPath1);
  233. mkdirp.sync(parentDirectoryPath2);
  234. fs.writeFileSync(filePath1, fileContent);
  235. fs.writeFileSync(filePath2, fileContent);
  236. fs.writeFileSync(filePath3, fileContent);
  237. fs.writeFileSync(filePath4, fileContent);
  238. result = new SourceCodeReader(tmpDirectoryPath, {}).readSourceCode();
  239. });
  240. it('should return files data', () => {
  241. assert.deepEqual(result, expectedResult);
  242. });
  243. after(() => {
  244. fs.unlinkSync(filePath1);
  245. fs.unlinkSync(filePath2);
  246. fs.unlinkSync(filePath3);
  247. fs.unlinkSync(filePath4);
  248. rimraf.sync(parentDirectoryPath1);
  249. rimraf.sync(parentDirectoryPath2);
  250. });
  251. });
  252. describe('Variant #4: `exclude` option', () => {
  253. describe('Variant #1: `inputPath` isn\'t excluded path', () => {
  254. const tmpFileName1: string = 'foo.js';
  255. const tmpFileName2: string = 'bar.js';
  256. const tmpFileName3: string = 'baz.png';
  257. const tmpFileName4: string = 'bark-obfuscated.js';
  258. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  259. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  260. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  261. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  262. const expectedResult: IFileData[] = [
  263. {
  264. filePath: filePath2,
  265. content: fileContent
  266. },
  267. {
  268. filePath: filePath1,
  269. content: fileContent
  270. }
  271. ];
  272. let result: IFileData[];
  273. before(() => {
  274. fs.writeFileSync(filePath1, fileContent);
  275. fs.writeFileSync(filePath2, fileContent);
  276. fs.writeFileSync(filePath3, fileContent);
  277. fs.writeFileSync(filePath4, fileContent);
  278. result = new SourceCodeReader(
  279. tmpDirectoryPath,
  280. {
  281. exclude: ['**/hawk.js']
  282. }
  283. ).readSourceCode();
  284. });
  285. it('should return files data', () => {
  286. assert.deepEqual(result, expectedResult);
  287. });
  288. after(() => {
  289. fs.unlinkSync(filePath1);
  290. fs.unlinkSync(filePath2);
  291. fs.unlinkSync(filePath3);
  292. fs.unlinkSync(filePath4);
  293. });
  294. });
  295. describe('Variant #2: `inputPath` is excluded path', () => {
  296. describe('Variant #1: exclude by `glob` pattern', () => {
  297. const tmpFileName1: string = 'foo.js';
  298. const tmpFileName2: string = 'bar.js';
  299. const tmpFileName3: string = 'baz.js';
  300. const tmpFileName4: string = 'bark.js';
  301. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  302. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  303. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  304. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  305. const expectedResult: IFileData[] = [
  306. {
  307. filePath: filePath3,
  308. content: fileContent
  309. },
  310. {
  311. filePath: filePath1,
  312. content: fileContent
  313. }
  314. ];
  315. let result: IFileData[];
  316. before(() => {
  317. fs.writeFileSync(filePath1, fileContent);
  318. fs.writeFileSync(filePath2, fileContent);
  319. fs.writeFileSync(filePath3, fileContent);
  320. fs.writeFileSync(filePath4, fileContent);
  321. result = new SourceCodeReader(
  322. tmpDirectoryPath,
  323. {
  324. exclude: [
  325. `**/${tmpFileName2}`,
  326. `**/${tmpFileName4}`
  327. ]
  328. }
  329. ).readSourceCode();
  330. });
  331. it('should return files data', () => {
  332. assert.deepEqual(result, expectedResult);
  333. });
  334. after(() => {
  335. fs.unlinkSync(filePath1);
  336. fs.unlinkSync(filePath2);
  337. fs.unlinkSync(filePath3);
  338. fs.unlinkSync(filePath4);
  339. });
  340. });
  341. describe('Variant #2: exclude by file name', () => {
  342. const tmpFileName1: string = 'foo.js';
  343. const tmpFileName2: string = 'bar.js';
  344. const tmpFileName3: string = 'baz.js';
  345. const tmpFileName4: string = 'bark.js';
  346. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  347. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  348. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  349. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  350. const expectedResult: IFileData[] = [
  351. {
  352. filePath: filePath3,
  353. content: fileContent
  354. },
  355. {
  356. filePath: filePath1,
  357. content: fileContent
  358. }
  359. ];
  360. let result: IFileData[];
  361. before(() => {
  362. fs.writeFileSync(filePath1, fileContent);
  363. fs.writeFileSync(filePath2, fileContent);
  364. fs.writeFileSync(filePath3, fileContent);
  365. fs.writeFileSync(filePath4, fileContent);
  366. result = new SourceCodeReader(
  367. tmpDirectoryPath,
  368. {
  369. exclude: [
  370. tmpFileName2,
  371. tmpFileName4
  372. ]
  373. }
  374. ).readSourceCode();
  375. });
  376. it('should return files data', () => {
  377. assert.deepEqual(result, expectedResult);
  378. });
  379. after(() => {
  380. fs.unlinkSync(filePath1);
  381. fs.unlinkSync(filePath2);
  382. fs.unlinkSync(filePath3);
  383. fs.unlinkSync(filePath4);
  384. });
  385. });
  386. describe('Variant #3: exclude by file path', () => {
  387. const tmpFileName1: string = 'foo.js';
  388. const tmpFileName2: string = 'bar.js';
  389. const tmpFileName3: string = 'baz.js';
  390. const tmpFileName4: string = 'bark.js';
  391. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  392. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  393. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  394. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  395. const expectedResult: IFileData[] = [
  396. {
  397. filePath: filePath3,
  398. content: fileContent
  399. },
  400. {
  401. filePath: filePath1,
  402. content: fileContent
  403. }
  404. ];
  405. let result: IFileData[];
  406. before(() => {
  407. fs.writeFileSync(filePath1, fileContent);
  408. fs.writeFileSync(filePath2, fileContent);
  409. fs.writeFileSync(filePath3, fileContent);
  410. fs.writeFileSync(filePath4, fileContent);
  411. result = new SourceCodeReader(
  412. tmpDirectoryPath,
  413. {
  414. exclude: [
  415. filePath2,
  416. filePath4
  417. ]
  418. }
  419. ).readSourceCode();
  420. });
  421. it('should return files data', () => {
  422. assert.deepEqual(result, expectedResult);
  423. });
  424. after(() => {
  425. fs.unlinkSync(filePath1);
  426. fs.unlinkSync(filePath2);
  427. fs.unlinkSync(filePath3);
  428. fs.unlinkSync(filePath4);
  429. });
  430. });
  431. describe('Variant #4: exclude whole directory', () => {
  432. const tmpFileName1: string = 'foo.js';
  433. const tmpFileName2: string = 'bar.js';
  434. const tmpFileName3: string = 'baz.js';
  435. const tmpFileName4: string = 'bark.js';
  436. const filePath1: string = `${tmpDirectoryPath}/${tmpFileName1}`;
  437. const filePath2: string = `${tmpDirectoryPath}/${tmpFileName2}`;
  438. const filePath3: string = `${tmpDirectoryPath}/${tmpFileName3}`;
  439. const filePath4: string = `${tmpDirectoryPath}/${tmpFileName4}`;
  440. let testFunc: () => void;
  441. before(() => {
  442. fs.writeFileSync(filePath1, fileContent);
  443. fs.writeFileSync(filePath2, fileContent);
  444. fs.writeFileSync(filePath3, fileContent);
  445. fs.writeFileSync(filePath4, fileContent);
  446. testFunc = () => new SourceCodeReader(
  447. tmpDirectoryPath,
  448. {
  449. exclude: [tmpDirectoryPath]
  450. }
  451. ).readSourceCode();
  452. });
  453. it('should return files data', () => {
  454. assert.throws(testFunc, expectedError);
  455. });
  456. after(() => {
  457. fs.unlinkSync(filePath1);
  458. fs.unlinkSync(filePath2);
  459. fs.unlinkSync(filePath3);
  460. fs.unlinkSync(filePath4);
  461. });
  462. });
  463. });
  464. });
  465. });
  466. describe('Variant #3: logging', () => {
  467. const tmpFileName: string = 'test.js';
  468. const inputPath: string = `${tmpDirectoryPath}/${tmpFileName}`;
  469. const expectedConsoleLogCallResult: boolean = true;
  470. const expectedLoggingMessage: string = `[javascript-obfuscator-cli] Obfuscating file: ${inputPath}...`;
  471. let consoleLogSpy: sinon.SinonSpy<any, void>,
  472. consoleLogCallResult: boolean,
  473. loggingMessageResult: string;
  474. before(() => {
  475. consoleLogSpy = sinon.spy(console, 'log');
  476. fs.writeFileSync(inputPath, fileContent);
  477. new SourceCodeReader(inputPath, {}).readSourceCode();
  478. consoleLogCallResult = consoleLogSpy.called;
  479. loggingMessageResult = consoleLogSpy.getCall(0).args[0];
  480. });
  481. it('should call `console.log`', () => {
  482. assert.equal(consoleLogCallResult, expectedConsoleLogCallResult);
  483. });
  484. it('should log file name to the console', () => {
  485. assert.include(loggingMessageResult, expectedLoggingMessage);
  486. });
  487. after(() => {
  488. consoleLogSpy.restore();
  489. fs.unlinkSync(inputPath);
  490. });
  491. });
  492. });
  493. after(() => {
  494. rimraf.sync(tmpDirectoryPath);
  495. });
  496. });