|
@@ -3,58 +3,59 @@ const { expect } = require('chai')
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
const isUtf8 = require('utf-8-validate')
|
|
const isUtf8 = require('utf-8-validate')
|
|
|
const Settings = require('@overleaf/settings')
|
|
const Settings = require('@overleaf/settings')
|
|
|
-const modulePath = '../../../../app/src/Features/Uploads/FileTypeManager.js'
|
|
|
|
|
|
|
+
|
|
|
|
|
+const MODULE_PATH = '../../../../app/src/Features/Uploads/FileTypeManager.js'
|
|
|
|
|
|
|
|
describe('FileTypeManager', function () {
|
|
describe('FileTypeManager', function () {
|
|
|
|
|
+ const fileContents = 'Ich bin eine kleine Teekanne, kurz und kräftig.'
|
|
|
|
|
+
|
|
|
beforeEach(function () {
|
|
beforeEach(function () {
|
|
|
this.isUtf8 = sinon.spy(isUtf8)
|
|
this.isUtf8 = sinon.spy(isUtf8)
|
|
|
this.stats = {
|
|
this.stats = {
|
|
|
isDirectory: sinon.stub().returns(false),
|
|
isDirectory: sinon.stub().returns(false),
|
|
|
size: 100,
|
|
size: 100,
|
|
|
}
|
|
}
|
|
|
- const fileContents = 'Ich bin eine kleine Teekanne, kurz und kräftig.'
|
|
|
|
|
this.fs = {
|
|
this.fs = {
|
|
|
- stat: sinon.stub().yields(null, this.stats),
|
|
|
|
|
|
|
+ stat: sinon.stub().resolves(this.stats),
|
|
|
readFile: sinon.stub(),
|
|
readFile: sinon.stub(),
|
|
|
}
|
|
}
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('utf8.tex')
|
|
.withArgs('utf8.tex')
|
|
|
- .yields(null, Buffer.from(fileContents, 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(fileContents, 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('utf16.tex')
|
|
.withArgs('utf16.tex')
|
|
|
- .yields(null, Buffer.from(`\uFEFF${fileContents}`, 'utf-16le'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(`\uFEFF${fileContents}`, 'utf-16le'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('latin1.tex')
|
|
.withArgs('latin1.tex')
|
|
|
- .yields(null, Buffer.from(fileContents, 'latin1'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(fileContents, 'latin1'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('latin1-null.tex')
|
|
.withArgs('latin1-null.tex')
|
|
|
- .yields(null, Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('utf8-null.tex')
|
|
.withArgs('utf8-null.tex')
|
|
|
- .yields(null, Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('utf8-non-bmp.tex')
|
|
.withArgs('utf8-non-bmp.tex')
|
|
|
- .yields(null, Buffer.from(`${fileContents}😈`))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(`${fileContents}😈`))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('utf8-control-chars.tex')
|
|
.withArgs('utf8-control-chars.tex')
|
|
|
- .yields(null, Buffer.from(`${fileContents}\x0c${fileContents}`))
|
|
|
|
|
|
|
+ .resolves(Buffer.from(`${fileContents}\x0c${fileContents}`))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('text-short.tex')
|
|
.withArgs('text-short.tex')
|
|
|
- .yields(null, Buffer.from('a'.repeat(0.5 * 1024 * 1024), 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from('a'.repeat(0.5 * 1024 * 1024), 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('text-smaller.tex')
|
|
.withArgs('text-smaller.tex')
|
|
|
- .yields(null, Buffer.from('a'.repeat(2 * 1024 * 1024 - 1), 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from('a'.repeat(2 * 1024 * 1024 - 1), 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('text-exact.tex')
|
|
.withArgs('text-exact.tex')
|
|
|
- .yields(null, Buffer.from('a'.repeat(2 * 1024 * 1024), 'utf-8'))
|
|
|
|
|
|
|
+ .resolves(Buffer.from('a'.repeat(2 * 1024 * 1024), 'utf-8'))
|
|
|
this.fs.readFile
|
|
this.fs.readFile
|
|
|
.withArgs('text-long.tex')
|
|
.withArgs('text-long.tex')
|
|
|
- .yields(null, Buffer.from('a'.repeat(3 * 1024 * 1024), 'utf-8'))
|
|
|
|
|
- this.callback = sinon.stub()
|
|
|
|
|
- this.DocumentHelper = { getEncodingFromTexContent: sinon.stub() }
|
|
|
|
|
- this.FileTypeManager = SandboxedModule.require(modulePath, {
|
|
|
|
|
|
|
+ .resolves(Buffer.from('a'.repeat(3 * 1024 * 1024), 'utf-8'))
|
|
|
|
|
+
|
|
|
|
|
+ this.FileTypeManager = SandboxedModule.require(MODULE_PATH, {
|
|
|
requires: {
|
|
requires: {
|
|
|
- fs: this.fs,
|
|
|
|
|
|
|
+ 'fs/promises': this.fs,
|
|
|
'utf-8-validate': this.isUtf8,
|
|
'utf-8-validate': this.isUtf8,
|
|
|
'@overleaf/settings': Settings,
|
|
'@overleaf/settings': Settings,
|
|
|
},
|
|
},
|
|
@@ -88,6 +89,32 @@ describe('FileTypeManager', function () {
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ describe('isEditable', function () {
|
|
|
|
|
+ it('classifies simple UTF-8 as editable', function () {
|
|
|
|
|
+ expect(this.FileTypeManager.isEditable(fileContents)).to.be.true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it('classifies text with non-BMP characters as binary', function () {
|
|
|
|
|
+ expect(this.FileTypeManager.isEditable(`${fileContents}😈`)).to.be.false
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it('classifies a .tex file as editable', function () {
|
|
|
|
|
+ expect(
|
|
|
|
|
+ this.FileTypeManager.isEditable(fileContents, {
|
|
|
|
|
+ filename: 'some/file.tex',
|
|
|
|
|
+ })
|
|
|
|
|
+ ).to.be.true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it('classifies a .exe file as binary', function () {
|
|
|
|
|
+ expect(
|
|
|
|
|
+ this.FileTypeManager.isEditable(fileContents, {
|
|
|
|
|
+ filename: 'command.exe',
|
|
|
|
|
+ })
|
|
|
|
|
+ ).to.be.false
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
describe('getType', function () {
|
|
describe('getType', function () {
|
|
|
describe('when the file extension is text', function () {
|
|
describe('when the file extension is text', function () {
|
|
|
const TEXT_FILENAMES = [
|
|
const TEXT_FILENAMES = [
|
|
@@ -335,76 +362,58 @@ describe('FileTypeManager', function () {
|
|
|
|
|
|
|
|
describe('shouldIgnore', function () {
|
|
describe('shouldIgnore', function () {
|
|
|
it('should ignore tex auxiliary files', async function () {
|
|
it('should ignore tex auxiliary files', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('file.aux')
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('file.aux')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore dotfiles', async function () {
|
|
it('should ignore dotfiles', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('path/.git')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('path/.git')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore .git directories and contained files', async function () {
|
|
it('should ignore .git directories and contained files', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('path/.git/info')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = await this.FileTypeManager.shouldIgnore('path/.git/info')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should not ignore .latexmkrc dotfile', async function () {
|
|
it('should not ignore .latexmkrc dotfile', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('path/.latexmkrc')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('path/.latexmkrc')
|
|
|
ignore.should.equal(false)
|
|
ignore.should.equal(false)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore __MACOSX', async function () {
|
|
it('should ignore __MACOSX', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('path/__MACOSX')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('path/__MACOSX')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore synctex files', async function () {
|
|
it('should ignore synctex files', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('file.synctex')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('file.synctex')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore synctex(busy) files', async function () {
|
|
it('should ignore synctex(busy) files', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('file.synctex(busy)')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('file.synctex(busy)')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should not ignore .tex files', async function () {
|
|
it('should not ignore .tex files', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('file.tex')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('file.tex')
|
|
|
ignore.should.equal(false)
|
|
ignore.should.equal(false)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should ignore the case of the extension', async function () {
|
|
it('should ignore the case of the extension', async function () {
|
|
|
- const ignore =
|
|
|
|
|
- await this.FileTypeManager.promises.shouldIgnore('file.AUX')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('file.AUX')
|
|
|
ignore.should.equal(true)
|
|
ignore.should.equal(true)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should not ignore files with an ignored extension as full name', async function () {
|
|
it('should not ignore files with an ignored extension as full name', async function () {
|
|
|
- const ignore = await this.FileTypeManager.promises.shouldIgnore('dvi')
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('dvi')
|
|
|
ignore.should.equal(false)
|
|
ignore.should.equal(false)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
it('should not ignore directories with an ignored extension as full name', async function () {
|
|
it('should not ignore directories with an ignored extension as full name', async function () {
|
|
|
this.stats.isDirectory.returns(true)
|
|
this.stats.isDirectory.returns(true)
|
|
|
- const ignore = await this.FileTypeManager.promises.shouldIgnore('dvi')
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const ignore = this.FileTypeManager.shouldIgnore('dvi')
|
|
|
ignore.should.equal(false)
|
|
ignore.should.equal(false)
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|