utilities.spec.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. 'use strict';
  2. const assert = require('assert');
  3. const path = require('path');
  4. const fs = require('fs');
  5. const md5 = require('md5');
  6. const server = require('./server');
  7. const fileDir = server.fileDir;
  8. const uploadDir = server.uploadDir;
  9. const {
  10. debugLog,
  11. isFunc,
  12. errorFunc,
  13. getTempFilename,
  14. buildOptions,
  15. buildFields,
  16. checkAndMakeDir,
  17. deleteFile,
  18. copyFile,
  19. saveBufferToFile,
  20. parseFileName,
  21. uriDecodeFileName
  22. } = require('../lib/utilities');
  23. const mockFile = 'basketball.png';
  24. const mockBuffer = fs.readFileSync(path.join(fileDir, mockFile));
  25. const mockHash = md5(mockBuffer);
  26. describe('Test of the utilities functions', function() {
  27. beforeEach(function() {
  28. server.clearUploadsDir();
  29. });
  30. //debugLog tests
  31. describe('Test debugLog function', () => {
  32. let testMessage = 'Test message';
  33. it('debugLog returns false if no options passed', () => {
  34. assert.equal(debugLog(null, testMessage), false);
  35. });
  36. it('debugLog returns false if option debug is false', () => {
  37. assert.equal(debugLog({debug: false}, testMessage), false);
  38. });
  39. it('debugLog returns true if option debug is true', () => {
  40. assert.equal(debugLog({debug: true}, testMessage), true);
  41. });
  42. });
  43. //isFunc tests
  44. describe('Test isFunc function', () => {
  45. it('isFunc returns true if function passed', () => assert.equal(isFunc(()=>{}), true));
  46. it('isFunc returns false if null passed', function() {
  47. assert.equal(isFunc(null), false);
  48. });
  49. it('isFunc returns false if undefined passed', function() {
  50. assert.equal(isFunc(undefined), false);
  51. });
  52. it('isFunc returns false if object passed', function() {
  53. assert.equal(isFunc({}), false);
  54. });
  55. it('isFunc returns false if array passed', function() {
  56. assert.equal(isFunc([]), false);
  57. });
  58. });
  59. //errorFunc tests
  60. describe('Test errorFunc function', () => {
  61. const resolve = () => 'success';
  62. const reject = () => 'error';
  63. it('errorFunc returns resolve if reject function has not been passed', () => {
  64. let result = errorFunc(resolve);
  65. assert.equal(result(), 'success');
  66. });
  67. it('errorFunc returns reject if reject function has been passed', () => {
  68. let result = errorFunc(resolve, reject);
  69. assert.equal(result(), 'error');
  70. });
  71. });
  72. //getTempFilename tests
  73. describe('Test getTempFilename function', () => {
  74. const nameRegexp = /tmp-\d{1,5}-\d{1,}/;
  75. it('getTempFilename result matches regexp /tmp-d{1,5}-d{1,}/', () => {
  76. let errCounter = 0;
  77. let tempName = '';
  78. for (var i = 0; i < 65537; i++) {
  79. tempName = getTempFilename();
  80. if (!nameRegexp.test(tempName)) errCounter ++;
  81. }
  82. assert.equal(errCounter, 0);
  83. });
  84. it('getTempFilename current and previous results are not equal', () => {
  85. let errCounter = 0;
  86. let tempName = '';
  87. let previousName = '';
  88. for (var i = 0; i < 65537; i++) {
  89. previousName = tempName;
  90. tempName = getTempFilename();
  91. if (previousName === tempName) errCounter ++;
  92. }
  93. assert.equal(errCounter, 0);
  94. });
  95. });
  96. //parseFileName
  97. describe('Test parseFileName function', () => {
  98. it('Does nothing to your filename when disabled.', () => {
  99. const opts = {safeFileNames: false};
  100. const name = 'my$Invalid#fileName.png123';
  101. const expected = 'my$Invalid#fileName.png123';
  102. let result = parseFileName(opts, name);
  103. assert.equal(result, expected);
  104. });
  105. it('Cuts of file name length if it more then 255 chars.', () => {
  106. const name = 'a'.repeat(300);
  107. const result = parseFileName({}, name);
  108. assert.equal(result.length, 255);
  109. });
  110. it(
  111. 'Strips away all non-alphanumeric characters (excluding hyphens/underscores) when enabled.',
  112. () => {
  113. const opts = {safeFileNames: true};
  114. const name = 'my$Invalid#fileName.png123';
  115. const expected = 'myInvalidfileNamepng123';
  116. let result = parseFileName(opts, name);
  117. assert.equal(result, expected);
  118. });
  119. it(
  120. 'Strips away all non-alphanumeric chars when preserveExtension: true for a name without dots',
  121. () => {
  122. const opts = {safeFileNames: true, preserveExtension: true};
  123. const name = 'my$Invalid#fileName';
  124. const expected = 'myInvalidfileName';
  125. let result = parseFileName(opts, name);
  126. assert.equal(result, expected);
  127. });
  128. it('Accepts a regex for stripping (decidedly) "invalid" characters from filename.', () => {
  129. const opts = {safeFileNames: /[$#]/g};
  130. const name = 'my$Invalid#fileName.png123';
  131. const expected = 'myInvalidfileName.png123';
  132. let result = parseFileName(opts, name);
  133. assert.equal(result, expected);
  134. });
  135. it(
  136. 'Returns correct filename if name contains dots characters and preserveExtension: true.',
  137. () => {
  138. const opts = {safeFileNames: true, preserveExtension: true};
  139. const name = 'basket.ball.png';
  140. const expected = 'basketball.png';
  141. let result = parseFileName(opts, name);
  142. assert.equal(result, expected);
  143. });
  144. it('Returns a temporary file name if name argument is empty.', () => {
  145. const opts = {safeFileNames: false};
  146. const result = parseFileName(opts);
  147. assert.equal(typeof result, 'string');
  148. });
  149. });
  150. //buildOptions tests
  151. describe('Test buildOptions function', () => {
  152. const source = { option1: '1', option2: '2' };
  153. const sourceAddon = { option3: '3'};
  154. const expected = { option1: '1', option2: '2' };
  155. const expectedAddon = { option1: '1', option2: '2', option3: '3'};
  156. it('buildOptions returns and equal object to the object which was paased', () => {
  157. let result = buildOptions(source);
  158. assert.deepStrictEqual(result, source);
  159. });
  160. it('buildOptions doesnt add non object or null arguments to the result', () => {
  161. let result = buildOptions(source, 2, '3', null);
  162. assert.deepStrictEqual(result, expected);
  163. });
  164. it('buildOptions adds value to the result from the several source argumets', () => {
  165. let result = buildOptions(source, sourceAddon);
  166. assert.deepStrictEqual(result, expectedAddon);
  167. });
  168. });
  169. //buildFields tests
  170. describe('Test buildOptions function', () => {
  171. it('buildFields does nothing if null value has been passed', () => {
  172. let fields = null;
  173. fields = buildFields(fields, 'test', null);
  174. assert.equal(fields, null);
  175. });
  176. });
  177. //checkAndMakeDir tests
  178. describe('Test checkAndMakeDir function', () => {
  179. //
  180. it('checkAndMakeDir returns false if upload options object was not set', () => {
  181. assert.equal(checkAndMakeDir(), false);
  182. });
  183. //
  184. it('checkAndMakeDir returns false if upload option createParentPath was not set', () => {
  185. assert.equal(checkAndMakeDir({}), false);
  186. });
  187. //
  188. it('checkAndMakeDir returns false if filePath was not set', () => {
  189. assert.equal(checkAndMakeDir({createParentPath: true}), false);
  190. });
  191. //
  192. it('checkAndMakeDir return true if path to the file already exists', ()=>{
  193. let dir = path.join(uploadDir, 'testfile');
  194. assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
  195. });
  196. //
  197. it('checkAndMakeDir creates a dir if path to the file not exists', ()=>{
  198. let dir = path.join(uploadDir, 'testfolder', 'testfile');
  199. assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
  200. });
  201. //
  202. it('checkAndMakeDir creates a dir recursively if path to the file not exists', ()=>{
  203. let dir = path.join(uploadDir, 'testfolder', 'testsubfolder', 'testfile');
  204. assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
  205. });
  206. });
  207. //saveBufferToFile tests
  208. describe('Test saveBufferToFile function', function(){
  209. beforeEach(function() {
  210. server.clearUploadsDir();
  211. });
  212. it('Save buffer to a file', function(done) {
  213. let filePath = path.join(uploadDir, mockFile);
  214. saveBufferToFile(mockBuffer, filePath, function(err){
  215. if (err) {
  216. return done(err);
  217. }
  218. fs.stat(filePath, done);
  219. });
  220. });
  221. it('Failed if not a buffer passed', function(done) {
  222. let filePath = path.join(uploadDir, mockFile);
  223. saveBufferToFile(undefined, filePath, function(err){
  224. if (err) {
  225. return done();
  226. }
  227. });
  228. });
  229. it('Failed if wrong path passed', function(done) {
  230. let filePath = '';
  231. saveBufferToFile(mockFile, filePath, function(err){
  232. if (err) {
  233. return done();
  234. }
  235. });
  236. });
  237. });
  238. describe('Test deleteFile function', function(){
  239. beforeEach(function() {
  240. server.clearUploadsDir();
  241. });
  242. it('Failed if nonexistent file passed', function(done){
  243. let filePath = path.join(uploadDir, getTempFilename());
  244. deleteFile(filePath, function(err){
  245. if (err) {
  246. return done();
  247. }
  248. });
  249. });
  250. it('Delete a file', function(done){
  251. let srcPath = path.join(fileDir, mockFile);
  252. let dstPath = path.join(uploadDir, getTempFilename());
  253. //copy a file
  254. copyFile(srcPath, dstPath, function(err){
  255. if (err) {
  256. return done(err);
  257. }
  258. fs.stat(dstPath, (err)=>{
  259. if (err){
  260. return done(err);
  261. }
  262. // delete a file
  263. deleteFile(dstPath, function(err){
  264. if (err) {
  265. return done(err);
  266. }
  267. fs.stat(dstPath, (err)=>{
  268. if (err){
  269. return done();
  270. }
  271. //error if a file still exist
  272. done(err);
  273. });
  274. });
  275. });
  276. });
  277. });
  278. });
  279. describe('Test copyFile function', function(){
  280. beforeEach(function() {
  281. server.clearUploadsDir();
  282. });
  283. it('Copy a file and check a hash', function(done) {
  284. let srcPath = path.join(fileDir, mockFile);
  285. let dstPath = path.join(uploadDir, mockFile);
  286. copyFile(srcPath, dstPath, function(err){
  287. if (err) {
  288. return done(err);
  289. }
  290. fs.stat(dstPath, (err)=>{
  291. if (err){
  292. return done(err);
  293. }
  294. //Match source and destination files hash.
  295. let fileBuffer = fs.readFileSync(dstPath);
  296. let fileHash = md5(fileBuffer);
  297. return (fileHash === mockHash) ? done() : done(err);
  298. });
  299. });
  300. });
  301. it('Failed if wrong source file path passed', function(done){
  302. let srcPath = path.join(fileDir, 'unknown');
  303. let dstPath = path.join(uploadDir, mockFile);
  304. copyFile(srcPath, dstPath, function(err){
  305. if (err) {
  306. return done();
  307. }
  308. });
  309. });
  310. it('Failed if wrong destination file path passed', function(done){
  311. let srcPath = path.join(fileDir, 'unknown');
  312. let dstPath = path.join('unknown', 'unknown');
  313. copyFile(srcPath, dstPath, function(err){
  314. if (err) {
  315. return done();
  316. }
  317. });
  318. });
  319. });
  320. describe('Test uriDecodeFileName function', function() {
  321. const testData = [
  322. { enc: 'test%22filename', dec: 'test"filename' },
  323. { enc: 'test%60filename', dec: 'test`filename' },
  324. { enc: '%3Fx%3Dtest%22filename', dec: '?x=test"filename'}
  325. ];
  326. // Test decoding if uriDecodeFileNames: true.
  327. testData.forEach((testName) => {
  328. const opts = { uriDecodeFileNames: true };
  329. it(`Return ${testName.dec} for input ${testName.enc} if uriDecodeFileNames: true`, () => {
  330. assert.equal(uriDecodeFileName(opts, testName.enc), testName.dec);
  331. });
  332. });
  333. // Test decoding if uriDecodeFileNames: false.
  334. testData.forEach((testName) => {
  335. const opts = { uriDecodeFileNames: false };
  336. it(`Return ${testName.enc} for input ${testName.enc} if uriDecodeFileNames: false`, () => {
  337. assert.equal(uriDecodeFileName(opts, testName.enc), testName.enc);
  338. });
  339. });
  340. });
  341. });