SourceCodeReader.spec.ts 24 KB

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