file_map.test.js 6.2 KB

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