nebulab-dropbox
Version:
Client library for the Dropbox API
1,116 lines (1,013 loc) • 84.3 kB
text/coffeescript
buildBlob = (fragments, mimeType) ->
try
return new Blob fragments, mimeType
catch blobError
builder = new WebKitBlobBuilder
builder.append fragment for fragment in fragments
return builder.getBlob mimeType
buildClientTests = (clientKeys) ->
# Creates the global client.
setupClient = (test, done) ->
# Should only be used for fixture teardown.
test.__client = new Dropbox.Client clientKeys
done()
# Creates the test directory.
setupDirectory = (test, done) ->
# True if running on node.js
test.node_js = module? and module?.exports? and require?
# All test data should go here.
test.testFolder = '/js tests.' + Math.random().toString(36)
test.__client.mkdir test.testFolder, (error, stat) ->
if error isnt null
console.error error
throw new Error("Unexpected setup error");
done()
# Creates the binary image file in the test directory.
setupImageFile = (test, done) ->
test.imageFile = "#{test.testFolder}/test-binary-image.png"
test.imageFileBytes = testImageBytes
setupImageFileUsingArrayBuffer test, (success) ->
if success
return done()
setupImageFileUsingBlob test, (success) ->
if success
return done()
setupImageFileUsingString test, done
# Standard-compliant browsers write via XHR#send(ArrayBufferView).
setupImageFileUsingArrayBuffer = (test, done) ->
if Uint8Array?
view = new Uint8Array test.imageFileBytes.length
for i in [0...test.imageFileBytes.length]
view[i] = test.imageFileBytes[i]
buffer = view.buffer
test.__client.writeFile test.imageFile, buffer, (error, stat) ->
if error
return done(false)
# Some browsers will send the '[object Uint8Array]' string instead of
# the ArrayBufferView.
if stat.size is buffer.byteLength
test.imageFileTag = stat.versionTag
done true
else
done false
else
done false
# Fallback to XHR#send(Blob).
setupImageFileUsingBlob = (test, done) ->
if Blob?
view = new Uint8Array test.imageFileBytes.length
for i in [0...test.imageFileBytes.length]
view[i] = test.imageFileBytes[i]
buffer = view.buffer
blob = buildBlob [buffer], type: 'image/png'
test.__client.writeFile test.imageFile, blob, (error, stat) ->
if error
return done(false)
if stat.size is blob.size
test.imageFileTag = stat.versionTag
done true
else
done false
else
done false
# Last resort: send a string that will get crushed by encoding errors.
setupImageFileUsingString = (test, done) ->
stringChars = for i in [0...test.imageFileBytes.length]
String.fromCharCode(test.imageFileBytes[i])
test.__client.writeFile(test.imageFile, stringChars.join(''),
{ binary: true },
(error, stat) ->
if error isnt null
console.error error
throw new Error("Unexpected setup error");
test.imageFileTag = stat.versionTag
done()
)
# Creates the plaintext file in the test directory.
setupTextFile = (test, done) ->
test.textFile = "#{test.testFolder}/test-file.txt"
test.textFileData = "Plaintext test file #{Math.random().toString(36)}.\n"
test.__client.writeFile(test.textFile, test.textFileData,
(error, stat) ->
if error isnt null
console.error error
throw new Error("Unexpected setup error");
test.textFileTag = stat.versionTag
done()
)
# Global (expensive) fixtures.
before (done) ->
setupClient @, =>
setupDirectory @, =>
setupImageFile @, =>
setupTextFile @, ->
done()
# Teardown for global fixtures.
after (done) ->
@__client.remove @testFolder, (error, stat) =>
throw new Error(error) if error
done()
# Per-test (cheap) fixtures.
beforeEach ->
@client = new Dropbox.Client clientKeys
describe '#getAccountInfo', ->
it 'returns reasonable information', (done) ->
@client.getAccountInfo (error, accountInfo, rawAccountInfo) ->
expect(error).to.equal null
expect(accountInfo).to.be.instanceOf Dropbox.AccountInfo
expect(accountInfo.uid).to.equal clientKeys.uid
expect(rawAccountInfo).not.to.be.instanceOf Dropbox.AccountInfo
expect(rawAccountInfo).to.have.property 'uid'
done()
describe 'with httpCache', ->
beforeEach ->
@xhr = null
@client.onXhr.addListener (xhr) =>
@xhr = xhr
it 'uses Authorization headers', (done) ->
@client.getAccountInfo httpCache: true,
(error, accountInfo, rawAccountInfo) =>
if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers
expect(@xhr.url).to.contain 'access_token'
else
expect(@xhr.headers).to.have.key 'Authorization'
expect(error).to.equal null
expect(accountInfo).to.be.instanceOf Dropbox.AccountInfo
expect(accountInfo.uid).to.equal clientKeys.uid
expect(rawAccountInfo).not.to.be.instanceOf Dropbox.AccountInfo
expect(rawAccountInfo).to.have.property 'uid'
done()
describe '#mkdir', ->
afterEach (done) ->
return done() unless @newFolder
@client.remove @newFolder, (error, stat) -> done()
it 'creates a folder in the test folder', (done) ->
@newFolder = "#{@testFolder}/test'folder"
@client.mkdir @newFolder, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFolder
expect(stat.isFolder).to.equal true
@client.stat @newFolder, (error, stat) =>
expect(error).to.equal null
expect(stat.isFolder).to.equal true
done()
describe '#readFile', ->
beforeEach ->
@newFile = null
afterEach (done) ->
return done() unless @newFile
@client.remove @newFile, (error, stat) -> done()
it 'reads a text file', (done) ->
@client.readFile @textFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @textFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
# TODO(pwnall): enable after API contents server bug is fixed
#if clientKeys.key is testFullDropboxKeys.key
# expect(stat.inAppFolder).to.equal false
#else
# expect(stat.inAppFolder).to.equal true
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
done()
it 'reads the beginning of a text file', (done) ->
return done() if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
@client.readFile @textFile, start: 0, length: 10,
(error, data, stat, rangeInfo) =>
expect(error).to.equal null
expect(data).to.equal @textFileData.substring(0, 10)
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(rangeInfo).to.be.instanceOf Dropbox.Http.RangeInfo
expect(rangeInfo.start).to.equal 0
expect(rangeInfo.end).to.equal 9
expect(rangeInfo.size).to.equal @textFileData.length
done()
it 'reads the middle of a text file', (done) ->
return done() if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
@client.readFile @textFile, start: 8, length: 10,
(error, data, stat, rangeInfo) =>
expect(error).to.equal null
expect(data).to.equal @textFileData.substring(8, 18)
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(rangeInfo).to.be.instanceOf Dropbox.Http.RangeInfo
expect(rangeInfo.start).to.equal 8
expect(rangeInfo.end).to.equal 17
expect(rangeInfo.size).to.equal @textFileData.length
done()
it 'reads the end of a text file via the start: option', (done) ->
return done() if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
@client.readFile @textFile, start: 10, (error, data, stat, rangeInfo) =>
expect(error).to.equal null
expect(data).to.equal @textFileData.substring(10)
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(rangeInfo).to.be.instanceOf Dropbox.Http.RangeInfo
expect(rangeInfo.start).to.equal 10
expect(rangeInfo.end).to.equal @textFileData.length - 1
expect(rangeInfo.size).to.equal @textFileData.length
done()
it 'reads the end of a text file via the length: option', (done) ->
return done() if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
@client.readFile @textFile, length: 10, (error, data, stat, rangeInfo) =>
expect(error).to.equal null
expect(data).to.
equal @textFileData.substring(@textFileData.length - 10)
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(rangeInfo).to.be.instanceOf Dropbox.Http.RangeInfo
expect(rangeInfo.start).to.equal @textFileData.length - 10
expect(rangeInfo.end).to.equal @textFileData.length - 1
expect(rangeInfo.size).to.equal @textFileData.length
done()
it 'reads a binary file into a string', (done) ->
@client.readFile @imageFile, binary: true, (error, data, stat) =>
expect(error).to.equal null
bytes = (data.charCodeAt i for i in [0...data.length])
expect(bytes).to.deep.equal @imageFileBytes
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @imageFile
expect(stat.isFile).to.equal true
done()
it 'reads a JSON file into a string', (done) ->
jsonString = '{"answer":42,"autoParse":false}'
@newFile = "#{@testFolder}/json test file.json"
@client.writeFile @newFile, jsonString, (error, stat) =>
expect(error).to.equal null
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal jsonString
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
done()
it 'reads a binary file into a Blob', (done) ->
return done() unless Blob?
@client.readFile @imageFile, blob: true, (error, blob, stat) =>
expect(error).to.equal null
expect(blob).to.be.instanceOf Blob
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @imageFile
expect(stat.isFile).to.equal true
onBufferAvailable = (buffer) =>
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
if typeof FileReaderSync isnt 'undefined'
# Firefox WebWorkers don't have FileReader.
reader = new FileReaderSync
buffer = reader.readAsArrayBuffer blob
onBufferAvailable buffer
else
reader = new FileReader
reader.onloadend = ->
return unless reader.readyState == FileReader.DONE
onBufferAvailable reader.result
reader.readAsArrayBuffer blob
it 'reads a binary file into an ArrayBuffer', (done) ->
return done() unless ArrayBuffer?
@client.readFile @imageFile, arrayBuffer: true, (error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(buffer.byteLength).to.equal @imageFileBytes.length
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @imageFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'reads a binary file into a node.js Buffer', (done) ->
return done() unless Buffer?
@client.readFile @imageFile, buffer: true, (error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf Buffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @imageFile
expect(stat.isFile).to.equal true
bytes = (buffer.readUInt8(i) for i in [0...buffer.length])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'reports non-existing files correctly', (done) ->
@client.readFile @textFile + '-not-found', (error, text, stat) =>
expect(text).not.to.be.ok
expect(stat).not.to.be.ok
expect(error).to.be.instanceOf Dropbox.ApiError
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do error codes.
expect(error.status).to.equal Dropbox.ApiError.NOT_FOUND
expect(error.url).to.contain '-not-found'
done()
describe 'with an onXhr listener', ->
beforeEach ->
@listenerXhr = null
@callbackCalled = false
it 'calls the listener with a Dropbox.Util.Xhr argument', (done) ->
@client.onXhr.addListener (xhr) =>
expect(xhr).to.be.instanceOf Dropbox.Util.Xhr
@listenerXhr = xhr
true
@client.readFile @textFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @textFileData
done()
it 'calls the listener before firing the XHR', (done) ->
@client.onXhr.addListener (xhr) =>
unless Dropbox.Util.Xhr.ieXdr # IE's XHR doesn't have readyState
expect(xhr.xhr.readyState).to.equal 1
expect(@callbackCalled).to.equal false
@listenerXhr = xhr
true
@client.readFile @textFile, (error, data, stat) =>
@callbackCalled = true
expect(@listenerXhr).to.be.instanceOf Dropbox.Util.Xhr
expect(error).to.equal null
expect(data).to.equal @textFileData
done()
it 'does not send the XHR if the listener cancels the event', (done) ->
@client.onXhr.addListener (xhr) =>
expect(@callbackCalled).to.equal false
@listenerXhr = xhr
# NOTE: if the client calls send(), a DOM error will fail the test
xhr.send()
false
@client.readFile @textFile, (error, data, stat) =>
@callbackCalled = true
expect(@listenerXhr).to.be.instanceOf Dropbox.Util.Xhr
done()
describe 'with httpCache', ->
beforeEach ->
@xhr = null
@client.onXhr.addListener (xhr) =>
@xhr = xhr
it 'reads a text file using Authorization headers', (done) ->
@client.readFile @textFile, httpCache: true, (error, data, stat) =>
if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers
expect(@xhr.url).to.contain 'access_token'
else
expect(@xhr.headers).to.have.key 'Authorization'
expect(error).to.equal null
expect(data).to.equal @textFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
done()
describe '#writeFile', ->
beforeEach ->
@newFile = null
afterEach (done) ->
return done() unless @newFile
@client.remove @newFile, (error, stat) -> done()
it 'writes a new text file', (done) ->
@newFile = "#{@testFolder}/another text file.txt"
@newFileData = "Another plaintext file #{Math.random().toString(36)}."
@client.writeFile @newFile, @newFileData, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
# TODO(pwnall): enable after API contents server bug is fixed
#if clientKeys.key is testFullDropboxKeys.key
# expect(stat.inAppFolder).to.equal false
#else
# expect(stat.inAppFolder).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @newFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
done()
it 'writes a new empty file', (done) ->
@newFile = "#{@testFolder}/another text file.txt"
@newFileData = ''
@client.writeFile @newFile, @newFileData, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @newFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
done()
it 'writes a new text file with ~ - and _ in the name', (done) ->
@newFile = "#{@testFolder}/oauth~sig-test_file.txt"
@newFileData = "A file whose name checks for OAuth signatures on ~-_"
@client.writeFile @newFile, @newFileData, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @newFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
done()
it 'writes a Blob to a binary file', (done) ->
return done() unless Blob? and ArrayBuffer?
@newFile = "#{@testFolder}/test image from blob.png"
newBuffer = new ArrayBuffer @imageFileBytes.length
newBytes = new Uint8Array newBuffer
for i in [0...@imageFileBytes.length]
newBytes[i] = @imageFileBytes[i]
@newBlob = buildBlob [newBytes], type: 'image/png'
if @newBlob.size isnt newBuffer.byteLength
@newBlob = buildBlob [newBuffer], type: 'image/png'
@client.writeFile @newFile, @newBlob, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
expect(stat.size).to.equal @newBlob.size
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes a File to a binary file', (done) ->
return done() unless File? and Blob? and ArrayBuffer?
@newFile = "#{@testFolder}/test image from file.png"
newBuffer = new ArrayBuffer @imageFileBytes.length
newBytes = new Uint8Array newBuffer
for i in [0...@imageFileBytes.length]
newBytes[i] = @imageFileBytes[i]
# Called when we have a File wrapping newBlob.
actualTestCase = (file) =>
@newFileObject = file
@client.writeFile @newFile, @newFileObject, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
expect(stat.size).to.equal @newFileObject.size
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
try
file = new File [newBuffer], 'test image file.png', type: 'image/png'
actualTestCase file
catch noFileConstructorError
newBlob = buildBlob [newBytes], type: 'image/png'
return done() if typeof webkitRequestFileSystem is 'undefined'
webkitRequestFileSystem window.TEMPORARY, 1024 * 1024, (fileSystem) ->
# NOTE: the File name is different from the uploaded file name, to
# catch bugs such as http://crbug.com/165095
fileSystem.root.getFile 'test image file.png',
create: true, exclusive: false, (fileEntry) ->
fileEntry.createWriter (fileWriter) ->
fileWriter.onwriteend = ->
fileEntry.file (file) ->
actualTestCase file
fileWriter.write newBlob
it 'writes an ArrayBuffer to a binary file', (done) ->
return done() unless ArrayBuffer?
@newFile = "#{@testFolder}/test image from arraybuffer.png"
@newBuffer = new ArrayBuffer @imageFileBytes.length
newBytes = new Uint8Array @newBuffer
for i in [0...@imageFileBytes.length]
newBytes[i] = @imageFileBytes[i]
@client.writeFile @newFile, @newBuffer, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
expect(stat.size).to.equal @newBuffer.byteLength
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes an ArrayBufferView to a binary file', (done) ->
return done() unless ArrayBuffer?
@newFile = "#{@testFolder}/test image from arraybufferview.png"
@newBytes = new Uint8Array @imageFileBytes.length
for i in [0...@imageFileBytes.length]
@newBytes[i] = @imageFileBytes[i]
@client.writeFile @newFile, @newBytes, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
expect(stat.size).to.equal @newBytes.byteLength
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes a node.js Buffer to a binary file', (done) ->
return done() unless Buffer?
@newFile = "#{@testFolder}/test image from node buffer.png"
@newBuffer = new Buffer @imageFileBytes.length
for i in [0...@imageFileBytes.length]
@newBuffer.writeUInt8 @imageFileBytes[i], i
@client.writeFile @newFile, @newBuffer, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
expect(stat.size).to.equal @newBuffer.length
@client.readFile @newFile, buffer: true, (error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf Buffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
bytes = (buffer.readUInt8(i) for i in [0...buffer.length])
expect(bytes).to.deep.equal @imageFileBytes
done()
describe '#resumableUploadStep + #resumableUploadFinish', ->
beforeEach ->
if ArrayBuffer? # IE9 and below doesn't have ArrayBuffer
@length1 = Math.ceil @imageFileBytes.length / 3
@length2 = @imageFileBytes.length - @length1
@arrayBuffer1 = new ArrayBuffer @length1
@buffer1 = new Buffer @length1 if Buffer?
@view1 = new Uint8Array @arrayBuffer1
for i in [0...@length1]
@view1[i] = @imageFileBytes[i]
if @buffer1
@buffer1.writeUInt8 @imageFileBytes[i], i
@arrayBuffer2 = new ArrayBuffer @length2
@buffer2 = new Buffer @length2 if Buffer?
@view2 = new Uint8Array @arrayBuffer2
for i in [0...@length2]
@view2[i] = @imageFileBytes[@length1 + i]
if @buffer2
@buffer2.writeUInt8 @imageFileBytes[@length1 + i], i
if Blob? # node.js and IE9 and below don't have Blob
@blob1 = buildBlob [@view1], type: 'image/png'
if @blob1.size isnt @arrayBuffer1.byteLength
@blob1 = buildBlob [@arrayBuffer1], type: 'image/png'
@blob2 = buildBlob [@view2], type: 'image/png'
if @blob2.size isnt @arrayBuffer2.byteLength
@blob2 = buildBlob [@arrayBuffer2], type: 'image/png'
afterEach (done) ->
@timeout 30 * 1000 # This sequence is slow on the current API server.
return done() unless @newFile
@client.remove @newFile, (error, stat) -> done()
it 'writes a text file in two stages', (done) ->
@timeout 20 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable upload.txt"
line1 = "This is the first fragment\n"
line2 = "This is the second fragment\n"
@client.resumableUploadStep line1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal line1.length
@client.resumableUploadStep line2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal line1.length + line2.length
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor2, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
# TODO(pwnall): enable after API contents server bug is fixed
#if clientKeys.key is testFullDropboxKeys.key
# expect(stat.inAppFolder).to.equal false
#else
# expect(stat.inAppFolder).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal line1 + line2
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
# TODO(pwnall): enable after API contents server bug is fixed
#if clientKeys.key is testFullDropboxKeys.key
# expect(stat.inAppFolder).to.equal false
#else
# expect(stat.inAppFolder).to.equal true
done()
it 'writes a binary file using two ArrayBuffers', (done) ->
return done() unless @arrayBuffer1
@timeout 20 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable arraybuffer upload.png"
@client.resumableUploadStep @arrayBuffer1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal @length1
@client.resumableUploadStep @arrayBuffer2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal @length1 + @length2
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor2, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes a binary file using two ArrayBufferViews', (done) ->
return done() unless @view1
@timeout 20 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable arraybuffer upload.png"
@client.resumableUploadStep @arrayBuffer1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal @length1
@client.resumableUploadStep @arrayBuffer2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal @length1 + @length2
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor2, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes a binary file using two node.js Buffers', (done) ->
return done() unless @buffer1
@timeout 30 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable node buffer upload.png"
@client.resumableUploadStep @buffer1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal @length1
@client.resumableUploadStep @buffer2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal @length1 + @length2
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor2, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, buffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf Buffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
bytes = (buffer.readUInt8(i) for i in [0...buffer.length])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'writes a binary file using two Blobs', (done) ->
return done() unless @blob1
@timeout 20 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable blob upload.png"
@client.resumableUploadStep @blob1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal @length1
@client.resumableUploadStep @blob2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal @length1 + @length2
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor2, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, arrayBuffer: true,
(error, buffer, stat) =>
expect(error).to.equal null
expect(buffer).to.be.instanceOf ArrayBuffer
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
view = new Uint8Array buffer
bytes = (view[i] for i in [0...buffer.byteLength])
expect(bytes).to.deep.equal @imageFileBytes
done()
it 'recovers from out-of-sync correctly', (done) ->
# IE's XDR doesn't return anything on errors, so we can't do recovery.
return done() if Dropbox.Util.Xhr.ieXdr
@timeout 20 * 1000 # This sequence is slow on the current API server.
@newFile = "#{@testFolder}/test resumable upload out of sync.txt"
line1 = "This is the first fragment\n"
line2 = "This is the second fragment\n"
@client.resumableUploadStep line1, null, (error, cursor1) =>
expect(error).to.equal null
expect(cursor1).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor1.offset).to.equal line1.length
cursor1.offset += 10
@client.resumableUploadStep line2, cursor1, (error, cursor2) =>
expect(error).to.equal null
expect(cursor2).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor2.offset).to.equal line1.length
expect(cursor2.tag).to.equal cursor1.tag
@client.resumableUploadStep line2, cursor2, (error, cursor3) =>
expect(error).to.equal null
expect(cursor3).to.be.instanceOf Dropbox.Http.UploadCursor
expect(cursor3.offset).to.equal line1.length + line2.length
expect(cursor3.tag).to.equal cursor1.tag
@client.resumableUploadFinish @newFile, cursor3, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal line1 + line2
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
done()
it 'reports errors correctly', (done) ->
@newFile = "#{@testFolder}/test resumable upload error.txt"
badCursor = new Dropbox.Http.UploadCursor 'trollcursor'
badCursor.offset = 42
@client.resumableUploadStep @textFileData, badCursor, (error, cursor) =>
expect(cursor).to.equal undefined
expect(error).to.be.instanceOf Dropbox.ApiError
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do status codes.
expect(error.status).to.equal Dropbox.ApiError.NOT_FOUND
done()
describe '#stat', ->
it 'retrieves a Stat for a file', (done) ->
@client.stat @textFile, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(stat.versionTag).to.equal @textFileTag
expect(stat.size).to.equal @textFileData.length
if clientKeys.key is testFullDropboxKeys.key
expect(stat.inAppFolder).to.equal false
else
expect(stat.inAppFolder).to.equal true
done()
it 'retrieves a Stat for a folder', (done) ->
@client.stat @testFolder, (error, stat, entries) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @testFolder
expect(stat.isFolder).to.equal true
expect(stat.size).to.equal 0
if clientKeys.key is testFullDropboxKeys.key
expect(stat.inAppFolder).to.equal false
else
expect(stat.inAppFolder).to.equal true
expect(entries).to.equal undefined
done()
it 'retrieves a Stat and entries for a folder', (done) ->
@client.stat @testFolder, { readDir: true }, (error, stat, entries) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @testFolder
expect(stat.isFolder).to.equal true
expect(entries).to.be.ok
expect(entries).to.have.length 2
expect(entries[0]).to.be.instanceOf Dropbox.File.Stat
expect(entries[0].path).not.to.equal @testFolder
expect(entries[0].path).to.have.string @testFolder
done()
it 'fails cleanly for a non-existing path', (done) ->
listenerError = null
@client.onError.addListener (error) -> listenerError = error
@client.stat @testFolder + '/should_404.txt', (error, stat, entries) =>
expect(stat).to.equal undefined
expect(entries).to.equal.null
expect(error).to.be.instanceOf Dropbox.ApiError
expect(listenerError).to.equal error
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do status codes.
expect(error).to.have.property 'status'
expect(error.status).to.equal Dropbox.ApiError.NOT_FOUND
done()
describe 'with httpCache', ->
beforeEach ->
@xhr = null
@client.onXhr.addListener (xhr) =>
@xhr = xhr
it 'retrieves a Stat for a file using Authorization headers', (done) ->
@client.stat @textFile, httpCache: true, (error, stat) =>
if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers
expect(@xhr.url).to.contain 'access_token'
else
expect(@xhr.headers).to.have.key 'Authorization'
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.isFile).to.equal true
expect(stat.versionTag).to.equal @textFileTag
expect(stat.size).to.equal @textFileData.length
if clientKeys.key is testFullDropboxKeys.key
expect(stat.inAppFolder).to.equal false
else
expect(stat.inAppFolder).to.equal true
done()
describe '#readdir', ->
it 'retrieves a Stat and entries for a folder', (done) ->
@client.readdir @testFolder, (error, entries, dirStat, entryStats) =>
expect(error).to.equal null
expect(entries).to.be.ok
expect(entries).to.have.length 2
expect(entries[0]).to.be.a 'string'
expect(entries[0]).not.to.have.string '/'
expect(entries[0]).to.match /^(test-binary-image.png)|(test-file.txt)$/
expect(dirStat).to.be.instanceOf Dropbox.File.Stat
expect(dirStat.path).to.equal @testFolder
expect(dirStat.isFolder).to.equal true
if clientKeys.key is testFullDropboxKeys.key
expect(dirStat.inAppFolder).to.equal false
else
expect(dirStat.inAppFolder).to.equal true
expect(entryStats).to.be.ok
expect(entryStats).to.have.length 2
expect(entryStats[0]).to.be.instanceOf Dropbox.File.Stat
expect(entryStats[0].path).not.to.equal @testFolder
expect(entryStats[0].path).to.have.string @testFolder
done()
describe 'with httpCache', ->
beforeEach ->
@xhr = null
@client.onXhr.addListener (xhr) =>
@xhr = xhr
it 'retrieves a folder Stat and entries using Authorization', (done) ->
@client.readdir @testFolder, httpCache: true,
(error, entries, dir_stat, entry_stats) =>
if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers
expect(@xhr.url).to.contain 'access_token'
else
expect(@xhr.headers).to.have.key 'Authorization'
expect(error).to.equal null
expect(entries).to.be.ok
expect(entries).to.have.length 2
expect(entries[0]).to.be.a 'string'
expect(entries[0]).not.to.have.string '/'
expect(entries[0]).to.match(
/^(test-binary-image.png)|(test-file.txt)$/)
expect(dir_stat).to.be.instanceOf Dropbox.File.Stat
expect(dir_stat.path).to.equal @testFolder
expect(dir_stat.isFolder).to.equal true
expect(entry_stats).to.be.ok
expect(entry_stats).to.have.length 2
expect(entry_stats[0]).to.be.instanceOf Dropbox.File.Stat
expect(entry_stats[0].path).not.to.equal @testFolder
expect(entry_stats[0].path).to.have.string @testFolder
done()
describe 'with contentHash', (done) ->
beforeEach (done) ->
@client.readdir @testFolder, (error, entries, dirStat) =>
expect(error).to.equal null
@contentHash = dirStat.contentHash
done()
it 'does not retrieve a folder twice if the tag matches', (done) ->
@client.readdir @testFolder, contentHash: @contentHash,
(error, entries) ->
expect(error).to.be.instanceOf Dropbox.ApiError
expect(entries).not.to.be.ok
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do status codes
expect(error.status).to.equal Dropbox.ApiError.NO_CONTENT
done()
describe '#history', ->
it 'gets a list of revisions', (done) ->
@client.history @textFile, (error, versions) =>
expect(error).to.equal null
expect(versions).to.have.length 1
expect(versions[0]).to.be.instanceOf Dropbox.File.Stat
expect(versions[0].path).to.equal @textFile
expect(versions[0].size).to.equal @textFileData.length
expect(versions[0].versionTag).to.equal @textFileTag
done()
it 'returns 40x if the limit is set to 0', (done) ->
listenerError = null
@client.onError.addListener (error) -> listenerError = error
@client.history @textFile, limit: 0, (error, versions) =>
expect(error).to.be.instanceOf Dropbox.ApiError
expect(listenerError).to.equal error
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do status codes.
expect(error.status).to.be.within 400, 499
expect(versions).not.to.be.ok
done()
describe 'with httpCache', ->
beforeEach ->
@xhr = null
@client.onXhr.addListener (xhr) =>
@xhr = xhr
it 'gets a list of revisions using Authorization headers', (done) ->
@client.history @textFile, httpCache: true, (error, versions) =>
if Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers
expect(@xhr.url).to.contain 'access_token'
else
expect(@xhr.headers).to.have.key 'Authorization'
expect(error).to.equal null
expect(versions).to.have.length 1
expect(versions[0]).to.be.instanceOf Dropbox.File.Stat
expect(versions[0].path).to.equal @textFile
expect(versions[0].size).to.equal @textFileData.length
expect(versions[0].versionTag).to.equal @textFileTag
done()
describe '#copy', ->
beforeEach ->
@newFile = null
afterEach (done) ->
return done() unless @newFile
@client.remove @newFile, (error, stat) -> done()
it 'copies a file given by path', (done) ->
@newFile = "#{@testFolder}/copy of test-file.txt"
@client.copy @textFile, @newFile, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
if clientKeys.key is testFullDropboxKeys.key
expect(stat.inAppFolder).to.equal false
else
expect(stat.inAppFolder).to.equal true
@client.readFile @newFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @textFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
@client.readFile @textFile, (error, data, stat) =>
expect(error).to.equal null
expect(data).to.equal @textFileData
unless Dropbox.Util.Xhr.ieXdr # IE's XDR doesn't do headers.
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @textFile
expect(stat.versionTag).to.equal @textFileTag
done()
describe '#makeCopyReference', ->
beforeEach ->
@newFile = null
afterEach (done) ->
return done() unless @newFile
@client.remove @newFile, (error, stat) -> done()
it 'creates a Dropbox.File.CopyReference that copies the file', (done) ->
@newFile = "#{@testFolder}/ref copy of test-file.txt"
@client.makeCopyReference @textFile, (error, copyRef) =>
expect(error).to.equal null
expect(copyRef).to.be.instanceOf Dropbox.File.CopyReference
@client.copy copyRef, @newFile, (error, stat) =>
expect(error).to.equal null
expect(stat).to.be.instanceOf Dropbox.File.Stat
expect(stat.path).to.equal @newFile
expect(stat.isFile).to.equal true
# TODO(pwnall): enable after API contents server bug is fixed
# if clientKeys.key is testFullDropboxKey