file_map.test.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. 'use strict'
  2. const { expect } = require('chai')
  3. const _ = require('lodash')
  4. const ot = require('..')
  5. const File = ot.File
  6. const FileMap = ot.FileMap
  7. describe('FileMap', function () {
  8. function makeTestFile(pathname) {
  9. return File.fromString(pathname)
  10. }
  11. function makeTestFiles(pathnames) {
  12. return _.zipObject(pathnames, _.map(pathnames, makeTestFile))
  13. }
  14. function makeFileMap(pathnames) {
  15. return new FileMap(makeTestFiles(pathnames))
  16. }
  17. it('allows construction with a single file', function () {
  18. makeFileMap(['a'])
  19. })
  20. it('allows folders to differ by case', function () {
  21. expect(() => {
  22. makeFileMap(['a/b', 'A/c'])
  23. }).not.to.throw
  24. expect(() => {
  25. makeFileMap(['a/b/c', 'A/b/d'])
  26. }).not.to.throw
  27. expect(() => {
  28. makeFileMap(['a/b/c', 'a/B/d'])
  29. }).not.to.throw
  30. })
  31. it('does not allow conflicting paths on construct', function () {
  32. expect(() => {
  33. makeFileMap(['a', 'a/b'])
  34. }).to.throw(FileMap.PathnameConflictError)
  35. })
  36. it('detects conflicting paths with characters that sort before /', function () {
  37. const fileMap = makeFileMap(['a', 'a!'])
  38. expect(fileMap.wouldConflict('a/b')).to.be.truthy
  39. })
  40. it('detects conflicting paths', function () {
  41. const fileMap = makeFileMap(['a/b/c'])
  42. expect(fileMap.wouldConflict('a/b/c/d')).to.be.truthy
  43. expect(fileMap.wouldConflict('a')).to.be.truthy
  44. expect(fileMap.wouldConflict('b')).to.be.falsy
  45. expect(fileMap.wouldConflict('a/b')).to.be.truthy
  46. expect(fileMap.wouldConflict('a/c')).to.be.falsy
  47. expect(fileMap.wouldConflict('a/b/c')).to.be.falsy
  48. expect(fileMap.wouldConflict('a/b/d')).to.be.falsy
  49. expect(fileMap.wouldConflict('d/b/c')).to.be.falsy
  50. })
  51. it('allows paths that differ by case', function () {
  52. const fileMap = makeFileMap(['a/b/c'])
  53. expect(fileMap.wouldConflict('a/b/C')).to.be.falsy
  54. expect(fileMap.wouldConflict('A')).to.be.falsy
  55. expect(fileMap.wouldConflict('A/b')).to.be.falsy
  56. expect(fileMap.wouldConflict('a/B')).to.be.falsy
  57. expect(fileMap.wouldConflict('A/B')).to.be.falsy
  58. })
  59. it('does not add a file with a conflicting path', function () {
  60. const fileMap = makeFileMap(['a/b'])
  61. const file = makeTestFile('a/b/c')
  62. expect(() => {
  63. fileMap.addFile('a/b/c', file)
  64. }).to.throw(FileMap.PathnameConflictError)
  65. })
  66. it('does not move a file to a conflicting path', function () {
  67. const fileMap = makeFileMap(['a/b', 'a/c'])
  68. expect(() => {
  69. fileMap.moveFile('a/b', 'a')
  70. }).to.throw(FileMap.PathnameConflictError)
  71. })
  72. it('errors when trying to move a non-existent file', function () {
  73. const fileMap = makeFileMap(['a'])
  74. expect(() => fileMap.moveFile('b', 'a')).to.throw(FileMap.FileNotFoundError)
  75. })
  76. it('moves a file over an empty folder', function () {
  77. const fileMap = makeFileMap(['a/b'])
  78. fileMap.moveFile('a/b', 'a')
  79. expect(fileMap.countFiles()).to.equal(1)
  80. expect(fileMap.getFile('a')).to.exist
  81. expect(fileMap.getFile('a').getContent()).to.equal('a/b')
  82. })
  83. it('does not move a file over a non-empty folder', function () {
  84. const fileMap = makeFileMap(['a/b', 'a/c'])
  85. expect(() => {
  86. fileMap.moveFile('a/b', 'a')
  87. }).to.throw(FileMap.PathnameConflictError)
  88. })
  89. it('does not overwrite filename that differs by case on add', function () {
  90. const fileMap = makeFileMap(['a'])
  91. fileMap.addFile('A', makeTestFile('A'))
  92. expect(fileMap.countFiles()).to.equal(2)
  93. expect(fileMap.files.a).to.exist
  94. expect(fileMap.files.A).to.exist
  95. expect(fileMap.getFile('a')).to.exist
  96. expect(fileMap.getFile('A').getContent()).to.equal('A')
  97. })
  98. it('changes case on move', function () {
  99. const fileMap = makeFileMap(['a'])
  100. fileMap.moveFile('a', 'A')
  101. expect(fileMap.countFiles()).to.equal(1)
  102. expect(fileMap.files.a).not.to.exist
  103. expect(fileMap.files.A).to.exist
  104. expect(fileMap.getFile('A').getContent()).to.equal('a')
  105. })
  106. it('does not overwrite filename that differs by case on move', function () {
  107. const fileMap = makeFileMap(['a', 'b'])
  108. fileMap.moveFile('a', 'B')
  109. expect(fileMap.countFiles()).to.equal(2)
  110. expect(fileMap.files.a).not.to.exist
  111. expect(fileMap.files.b).to.exist
  112. expect(fileMap.files.B).to.exist
  113. expect(fileMap.getFile('B').getContent()).to.equal('a')
  114. })
  115. it('does not find pathname that differs by case', function () {
  116. const fileMap = makeFileMap(['a'])
  117. expect(fileMap.getFile('a')).to.exist
  118. expect(fileMap.getFile('A')).not.to.exist
  119. expect(fileMap.getFile('b')).not.to.exist
  120. })
  121. it('does not allow non-safe pathnames', function () {
  122. expect(() => {
  123. makeFileMap(['c*'])
  124. }).to.throw(FileMap.BadPathnameError)
  125. const fileMap = makeFileMap([])
  126. expect(() => {
  127. fileMap.addFile('c*', makeTestFile('c:'))
  128. }).to.throw(FileMap.BadPathnameError)
  129. fileMap.addFile('a', makeTestFile('a'))
  130. expect(() => {
  131. fileMap.moveFile('a', 'c*')
  132. }).to.throw(FileMap.BadPathnameError)
  133. expect(() => {
  134. fileMap.addFile('hasOwnProperty', makeTestFile('hasOwnProperty'))
  135. fileMap.addFile('anotherFile', makeTestFile('anotherFile'))
  136. }).to.throw()
  137. })
  138. it('removes a file', function () {
  139. const fileMap = makeFileMap(['a', 'b'])
  140. fileMap.removeFile('a')
  141. expect(fileMap.countFiles()).to.equal(1)
  142. expect(fileMap.files.a).not.to.exist
  143. expect(fileMap.files.b).to.exist
  144. })
  145. it('errors when trying to remove a non-existent file', function () {
  146. const fileMap = makeFileMap(['a'])
  147. expect(() => fileMap.removeFile('b')).to.throw(FileMap.FileNotFoundError)
  148. })
  149. it('has mapAsync', async function () {
  150. const concurrency = 1
  151. for (const test of [
  152. [[], {}],
  153. [['a'], { a: 'a-a' }], // the test is to map to "content-pathname"
  154. [['a', 'b'], { a: 'a-a', b: 'b-b' }],
  155. ]) {
  156. const input = test[0]
  157. const expectedOutput = test[1]
  158. const fileMap = makeFileMap(input)
  159. const result = await fileMap.mapAsync((file, pathname) => {
  160. return file.getContent() + '-' + pathname
  161. }, concurrency)
  162. expect(result).to.deep.equal(expectedOutput)
  163. }
  164. })
  165. })