ProjectLocatorTests.coffee 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. spies = require('chai-spies')
  2. chai = require('chai').use(spies)
  3. assert = require('chai').assert
  4. should = chai.should()
  5. modulePath = "../../../../app/js/Features/Project/ProjectLocator"
  6. SandboxedModule = require('sandboxed-module')
  7. sinon = require('sinon')
  8. Errors = require "../../../../app/js/Features/Errors/Errors"
  9. expect = require("chai").expect
  10. Project = class Project
  11. project = _id : "1234566", rootFolder:[]
  12. rootDoc = name:"rootDoc", _id:"das239djd"
  13. doc1 = name:"otherDoc.txt", _id:"dsad2ddd"
  14. doc2 = name:"docname.txt", _id:"dsad2ddddd"
  15. file1 = name:"file1", _id:"dsa9lkdsad"
  16. subSubFile = name:"subSubFile", _id:"d1d2dk"
  17. subSubDoc = name:"subdoc.txt", _id:"321dmdwi"
  18. secondSubFolder = name:"secondSubFolder", _id:"dsa3e23", docs:[subSubDoc], fileRefs:[subSubFile], folders:[]
  19. subFolder = name:"subFolder", _id:"dsadsa93", folders:[secondSubFolder, null], docs:[], fileRefs:[]
  20. subFolder1 = name:"subFolder1", _id:"123asdjoij"
  21. rootFolder =
  22. _id : "123sdskd"
  23. docs:[doc1, doc2, null, rootDoc]
  24. fileRefs:[file1]
  25. folders:[subFolder1, subFolder]
  26. project.rootFolder[0] = rootFolder
  27. project.rootDoc_id = rootDoc._id
  28. describe 'ProjectLocator', ->
  29. beforeEach ->
  30. Project.getProject = (project_id, fields, callback)=>
  31. callback(null, project)
  32. Project.findById = (project_id, callback)=>
  33. callback(null, project)
  34. @ProjectGetter =
  35. getProject: sinon.stub().callsArgWith(2, null, project)
  36. @locator = SandboxedModule.require modulePath, requires:
  37. '../../models/Project':{Project:Project}
  38. '../../models/User':{User:@User}
  39. "./ProjectGetter":@ProjectGetter
  40. 'logger-sharelatex':
  41. log:->
  42. err:->
  43. warn: ->
  44. describe 'finding a doc', ->
  45. it 'finds one at the root level', (done)->
  46. @locator.findElement {project_id:project._id, element_id:doc2._id, type:"docs"}, (err, foundElement, path, parentFolder)->
  47. assert(!err?)
  48. foundElement._id.should.equal doc2._id
  49. path.fileSystem.should.equal "/#{doc2.name}"
  50. parentFolder._id.should.equal project.rootFolder[0]._id
  51. path.mongo.should.equal "rootFolder.0.docs.1"
  52. done()
  53. it 'when it is nested', (done)->
  54. @locator.findElement {project_id:project._id, element_id:subSubDoc._id, type:"doc"}, (err, foundElement, path, parentFolder)->
  55. assert(!err?)
  56. should.equal foundElement._id, subSubDoc._id
  57. path.fileSystem.should.equal "/#{subFolder.name}/#{secondSubFolder.name}/#{subSubDoc.name}"
  58. parentFolder._id.should.equal secondSubFolder._id
  59. path.mongo.should.equal "rootFolder.0.folders.1.folders.0.docs.0"
  60. done()
  61. it 'should give error if element could not be found', (done)->
  62. @locator.findElement {project_id:project._id, element_id:"ddsd432nj42", type:"docs"}, (err, foundElement, path, parentFolder)->
  63. err.should.deep.equal new Errors.NotFoundError("entity not found")
  64. done()
  65. describe 'finding a folder', ->
  66. it 'should return root folder when looking for root folder', (done)->
  67. @locator.findElement {project_id:project._id, element_id:rootFolder._id, type:"folder"}, (err, foundElement, path, parentFolder)->
  68. assert(!err)
  69. foundElement._id.should.equal rootFolder._id
  70. done()
  71. it 'when at root', (done)->
  72. @locator.findElement {project_id:project._id, element_id:subFolder._id, type:"folder"}, (err, foundElement, path, parentFolder)->
  73. assert(!err)
  74. foundElement._id.should.equal subFolder._id
  75. path.fileSystem.should.equal "/#{subFolder.name}"
  76. parentFolder._id.should.equal rootFolder._id
  77. path.mongo.should.equal "rootFolder.0.folders.1"
  78. done()
  79. it 'when deeply nested', (done)->
  80. @locator.findElement {project_id:project._id, element_id:secondSubFolder._id, type:"folder"}, (err, foundElement, path, parentFolder)->
  81. assert(!err)
  82. foundElement._id.should.equal secondSubFolder._id
  83. path.fileSystem.should.equal "/#{subFolder.name}/#{secondSubFolder.name}"
  84. parentFolder._id.should.equal subFolder._id
  85. path.mongo.should.equal "rootFolder.0.folders.1.folders.0"
  86. done()
  87. describe 'finding a file', ->
  88. it 'when at root', (done)->
  89. @locator.findElement {project_id:project._id, element_id:file1._id, type:"fileRefs"}, (err, foundElement, path, parentFolder)->
  90. assert(!err)
  91. foundElement._id.should.equal file1._id
  92. path.fileSystem.should.equal "/#{file1.name}"
  93. parentFolder._id.should.equal rootFolder._id
  94. path.mongo.should.equal "rootFolder.0.fileRefs.0"
  95. done()
  96. it 'when deeply nested', (done)->
  97. @locator.findElement {project_id:project._id, element_id:subSubFile._id, type:"fileRefs"}, (err, foundElement, path, parentFolder)->
  98. assert(!err)
  99. foundElement._id.should.equal subSubFile._id
  100. path.fileSystem.should.equal "/#{subFolder.name}/#{secondSubFolder.name}/#{subSubFile.name}"
  101. parentFolder._id.should.equal secondSubFolder._id
  102. path.mongo.should.equal "rootFolder.0.folders.1.folders.0.fileRefs.0"
  103. done()
  104. describe 'finding an element with wrong element type', ->
  105. it 'should add an s onto the element type', (done)->
  106. @locator.findElement {project_id:project._id, element_id:subSubDoc._id, type:"doc"}, (err, foundElement, path, parentFolder)->
  107. assert(!err)
  108. foundElement._id.should.equal subSubDoc._id
  109. done()
  110. it 'should convert file to fileRefs', (done)->
  111. @locator.findElement {project_id:project._id, element_id:file1._id, type:"fileRefs"}, (err, foundElement, path, parentFolder)->
  112. assert(!err)
  113. foundElement._id.should.equal file1._id
  114. done()
  115. describe 'should be able to take actual project as well as id', ->
  116. doc3 =
  117. _id:"123dsdj3"
  118. name:"doc3"
  119. rootFolder2 =
  120. _id : "123sddedskd"
  121. docs:[doc3]
  122. project2 =
  123. _id : "1234566"
  124. rootFolder:[rootFolder2]
  125. it 'should find doc in project', (done)->
  126. @locator.findElement {project:project2, element_id:doc3._id, type:"docs"}, (err, foundElement, path, parentFolder)->
  127. assert(!err?)
  128. foundElement._id.should.equal doc3._id
  129. path.fileSystem.should.equal "/#{doc3.name}"
  130. parentFolder._id.should.equal project2.rootFolder[0]._id
  131. path.mongo.should.equal "rootFolder.0.docs.0"
  132. done()
  133. describe 'finding root doc', ->
  134. it 'should return root doc when passed project', (done)->
  135. @locator.findRootDoc project, (err, doc)->
  136. assert !err?
  137. doc._id.should.equal rootDoc._id
  138. done()
  139. it 'should return root doc when passed project_id', (done)->
  140. @locator.findRootDoc project._id, (err, doc)->
  141. assert !err?
  142. doc._id.should.equal rootDoc._id
  143. done()
  144. it 'should return null when the project has no rootDoc', (done) ->
  145. project.rootDoc_id = null
  146. @locator.findRootDoc project, (err, doc)->
  147. assert !err?
  148. expect(doc).to.equal null
  149. done()
  150. it 'should return null when the rootDoc_id no longer exists', (done) ->
  151. project.rootDoc_id = "doesntexist"
  152. @locator.findRootDoc project, (err, doc)->
  153. assert !err?
  154. expect(doc).to.equal null
  155. done()
  156. describe 'findElementByPath', ->
  157. it 'should take a doc path and return the element for a root level document', (done)->
  158. path = "#{doc1.name}"
  159. @locator.findElementByPath project._id, path, (err, element, type)->
  160. element.should.deep.equal doc1
  161. expect(type).to.equal "doc"
  162. done()
  163. it 'should take a doc path and return the element for a root level document with a starting slash', (done)->
  164. path = "/#{doc1.name}"
  165. @locator.findElementByPath project._id, path, (err, element, type)->
  166. element.should.deep.equal doc1
  167. expect(type).to.equal "doc"
  168. done()
  169. it 'should take a doc path and return the element for a nested document', (done)->
  170. path = "#{subFolder.name}/#{secondSubFolder.name}/#{subSubDoc.name}"
  171. @locator.findElementByPath project._id, path, (err, element, type)->
  172. element.should.deep.equal subSubDoc
  173. expect(type).to.equal "doc"
  174. done()
  175. it 'should take a file path and return the element for a root level document', (done)->
  176. path = "#{file1.name}"
  177. @locator.findElementByPath project._id, path, (err, element, type)->
  178. element.should.deep.equal file1
  179. expect(type).to.equal "file"
  180. done()
  181. it 'should take a file path and return the element for a nested document', (done)->
  182. path = "#{subFolder.name}/#{secondSubFolder.name}/#{subSubFile.name}"
  183. @locator.findElementByPath project._id, path, (err, element, type)->
  184. element.should.deep.equal subSubFile
  185. expect(type).to.equal "file"
  186. done()
  187. it 'should take a file path and return the element for a nested document case insenstive', (done)->
  188. path = "#{subFolder.name.toUpperCase()}/#{secondSubFolder.name.toUpperCase()}/#{subSubFile.name.toUpperCase()}"
  189. @locator.findElementByPath project._id, path, (err, element, type)->
  190. element.should.deep.equal subSubFile
  191. expect(type).to.equal "file"
  192. done()
  193. it 'should take a file path and return the element for a nested folder', (done)->
  194. path = "#{subFolder.name}/#{secondSubFolder.name}"
  195. @locator.findElementByPath project._id, path, (err, element, type)->
  196. element.should.deep.equal secondSubFolder
  197. expect(type).to.equal "folder"
  198. done()
  199. it 'should take a file path and return the root folder', (done)->
  200. @locator.findElementByPath project._id, "/", (err, element, type)->
  201. element.should.deep.equal rootFolder
  202. expect(type).to.equal "folder"
  203. done()
  204. it 'should return an error if the file can not be found inside know folder', (done)->
  205. @locator.findElementByPath project._id, "#{subFolder.name}/#{secondSubFolder.name}/exist.txt", (err, element, type)->
  206. err.should.not.equal undefined
  207. assert.equal element, undefined
  208. expect(type).to.be.undefined
  209. done()
  210. it 'should return an error if the file can not be found inside unknown folder', (done)->
  211. @locator.findElementByPath project._id, "this/does/not/exist.txt", (err, element, type)->
  212. err.should.not.equal undefined
  213. assert.equal element, undefined
  214. expect(type).to.be.undefined
  215. done()
  216. describe "where duplicate folder exists", ->
  217. beforeEach ->
  218. @duplicateFolder = {name:"duplicate1", _id:"1234", folders:[{
  219. name: "1"
  220. docs:[{name:"main.tex", _id:"456"}]
  221. folders: []
  222. fileRefs: []
  223. }], docs:[@doc = {name:"main.tex", _id:"456"}], fileRefs:[]}
  224. @project =
  225. rootFolder:[
  226. folders: [@duplicateFolder, @duplicateFolder]
  227. fileRefs: []
  228. docs: []
  229. ]
  230. Project.getProject = sinon.stub()
  231. Project.getProject.callsArgWith(2, null, @project)
  232. it "should not call the callback more than once", (done)->
  233. @locator.findElementByPath project._id, "#{@duplicateFolder.name}/#{@doc.name}", ->
  234. done() #mocha will throw exception if done called multiple times
  235. it "should not call the callback more than once when the path is longer than 1 level below the duplicate level", (done)->
  236. @locator.findElementByPath project._id, "#{@duplicateFolder.name}/1/main.tex", ->
  237. done() #mocha will throw exception if done called multiple times
  238. describe "with a null doc", ->
  239. beforeEach ->
  240. @project =
  241. rootFolder:[
  242. folders: []
  243. fileRefs: []
  244. docs: [{name:"main.tex"}, null, {name:"other.tex"}]
  245. ]
  246. Project.getProject = sinon.stub()
  247. Project.getProject.callsArgWith(2, null, @project)
  248. it "should not crash with a null", (done)->
  249. callback = sinon.stub()
  250. @locator.findElementByPath project._id, "/other.tex", (err, element)->
  251. element.name.should.equal "other.tex"
  252. done()
  253. describe "with a null project", ->
  254. beforeEach ->
  255. @project =
  256. rootFolder:[
  257. folders: []
  258. fileRefs: []
  259. docs: [{name:"main.tex"}, null, {name:"other.tex"}]
  260. ]
  261. Project.getProject = sinon.stub()
  262. Project.getProject.callsArgWith(2, null)
  263. it "should not crash with a null", (done)->
  264. callback = sinon.stub()
  265. @locator.findElementByPath project._id, "/other.tex", (err, element)->
  266. expect(err).to.exist
  267. done()
  268. describe 'findUsersProjectByName finding a project by user_id and project name', ()->
  269. it 'should return the project from an array case insenstive', (done)->
  270. user_id = "123jojoidns"
  271. stubbedProject = {name:"findThis"}
  272. projects = {
  273. owned: [{name:"notThis"}, {name:"wellll"}, stubbedProject, {name:"Noooo"}]
  274. }
  275. @ProjectGetter.findAllUsersProjects = sinon.stub().callsArgWith(2, null, projects)
  276. @locator.findUsersProjectByName user_id, stubbedProject.name.toLowerCase(), (err, project)->
  277. project.should.equal stubbedProject
  278. done()
  279. it 'should return the project which is not archived', (done)->
  280. user_id = "123jojoidns"
  281. stubbedProject = {name:"findThis", _id:12331321}
  282. projects = {
  283. owned: [
  284. {name:"notThis"},
  285. {name:"wellll"},
  286. {name:"findThis",archived:true},
  287. stubbedProject,
  288. {name:"findThis",archived:true},
  289. {name:"Noooo"}
  290. ]
  291. }
  292. @ProjectGetter.findAllUsersProjects = sinon.stub().callsArgWith(2, null, projects)
  293. @locator.findUsersProjectByName user_id, stubbedProject.name.toLowerCase(), (err, project)->
  294. project._id.should.equal stubbedProject._id
  295. done()
  296. it 'should search collab projects as well', (done)->
  297. user_id = "123jojoidns"
  298. stubbedProject = {name:"findThis"}
  299. projects = {
  300. owned: [{name:"notThis"}, {name:"wellll"}, {name:"Noooo"}]
  301. readAndWrite: [stubbedProject]
  302. }
  303. @ProjectGetter.findAllUsersProjects = sinon.stub().callsArgWith(2, null, projects)
  304. @locator.findUsersProjectByName user_id, stubbedProject.name.toLowerCase(), (err, project)->
  305. project.should.equal stubbedProject
  306. done()