fileTest.js (8841B)
1 describe("Zotero.File", function () { 2 describe("#getContentsAsync()", function () { 3 it("should handle an empty file", function* () { 4 var path = OS.Path.join(getTestDataDirectory().path, "empty"); 5 assert.equal((yield Zotero.File.getContentsAsync(path)), ""); 6 }) 7 8 it("should handle an extended character", function* () { 9 var contents = yield Zotero.File.getContentsAsync( 10 OS.Path.join(getTestDataDirectory().path, "charsets", "utf8.txt") 11 ); 12 assert.lengthOf(contents, 3); 13 assert.equal(contents, "A\u72acB"); 14 }) 15 16 it("should handle an extended Windows-1252 character", function* () { 17 var contents = yield Zotero.File.getContentsAsync( 18 OS.Path.join(getTestDataDirectory().path, "charsets", "windows1252.txt"), 19 "windows-1252" 20 ); 21 assert.lengthOf(contents, 1); 22 assert.equal(contents, "\u00E9"); 23 }) 24 25 it("should handle a GBK character", function* () { 26 var contents = yield Zotero.File.getContentsAsync( 27 OS.Path.join(getTestDataDirectory().path, "charsets", "gbk.txt"), 28 "gbk" 29 ); 30 assert.lengthOf(contents, 1); 31 assert.equal(contents, "\u4e02"); 32 }) 33 34 it("should handle an invalid character", function* () { 35 var contents = yield Zotero.File.getContentsAsync( 36 OS.Path.join(getTestDataDirectory().path, "charsets", "invalid.txt") 37 ); 38 assert.lengthOf(contents, 3); 39 assert.equal(contents, "A\uFFFDB"); 40 }) 41 42 it("should respect maxLength", function* () { 43 var contents = yield Zotero.File.getContentsAsync( 44 OS.Path.join(getTestDataDirectory().path, "test.txt"), 45 false, 46 6 47 ); 48 assert.lengthOf(contents, 6); 49 assert.equal(contents, "Zotero"); 50 }); 51 52 it("should get a file from a file: URI", function* () { 53 var contents = yield Zotero.File.getContentsAsync( 54 OS.Path.toFileURI(OS.Path.join(getTestDataDirectory().path, "test.txt")) 55 ); 56 assert.isTrue(contents.startsWith('Zotero')); 57 }); 58 }) 59 60 describe("#getBinaryContentsAsync()", function () { 61 var magicPNG = ["89", "50", "4e", "47", "0d", "0a", "1a", "0a"].map(x => parseInt(x, 16)); 62 63 it("should return a binary string", function* () { 64 var contents = yield Zotero.File.getBinaryContentsAsync( 65 OS.Path.join(getTestDataDirectory().path, "test.png") 66 ); 67 assert.isAbove(contents.length, magicPNG.length); 68 for (let i = 0; i < magicPNG.length; i++) { 69 assert.equal(magicPNG[i], contents.charCodeAt(i)); 70 } 71 }); 72 73 it("should respect maxLength", function* () { 74 var contents = yield Zotero.File.getBinaryContentsAsync( 75 OS.Path.join(getTestDataDirectory().path, "test.png"), 76 magicPNG.length 77 ); 78 assert.lengthOf(contents, magicPNG.length) 79 for (let i = 0; i < contents.length; i++) { 80 assert.equal(magicPNG[i], contents.charCodeAt(i)); 81 } 82 }); 83 }); 84 85 describe("#putContentsAsync()", function () { 86 it("should save via .tmp file", function* () { 87 var tmpDir = yield getTempDirectory(); 88 var destFile = OS.Path.join(tmpDir, 'test.txt') 89 var tmpFile = destFile + ".tmp"; 90 yield Zotero.File.putContentsAsync(tmpFile, 'A'); 91 assert.isTrue(yield OS.File.exists(tmpFile)); 92 yield Zotero.File.putContentsAsync(destFile, 'B'); 93 assert.isFalse(yield OS.File.exists(tmpFile)); 94 // Make sure .tmp file created when creating temp file was deleted too 95 assert.isFalse(yield OS.File.exists(tmpFile + '.tmp')); 96 }); 97 }); 98 99 100 describe("#rename()", function () { 101 it("should rename a file", async function () { 102 var tmpDir = await getTempDirectory(); 103 var sourceFile = OS.Path.join(tmpDir, 'a'); 104 var destFile = OS.Path.join(tmpDir, 'b'); 105 await Zotero.File.putContentsAsync(sourceFile, ''); 106 await Zotero.File.rename(sourceFile, 'b'); 107 assert.isTrue(await OS.File.exists(destFile)); 108 }); 109 110 it("should overwrite an existing file if `overwrite` is true", async function () { 111 var tmpDir = await getTempDirectory(); 112 var sourceFile = OS.Path.join(tmpDir, 'a'); 113 var destFile = OS.Path.join(tmpDir, 'b'); 114 await Zotero.File.putContentsAsync(sourceFile, 'a'); 115 await Zotero.File.putContentsAsync(destFile, 'b'); 116 await Zotero.File.rename(sourceFile, 'b', { overwrite: true }); 117 assert.isTrue(await OS.File.exists(destFile)); 118 assert.equal(await Zotero.File.getContentsAsync(destFile), 'a'); 119 }); 120 121 it("should get a unique name if target file exists and `unique` is true", async function () { 122 var tmpDir = await getTempDirectory(); 123 var sourceFile = OS.Path.join(tmpDir, 'a'); 124 var destFile = OS.Path.join(tmpDir, 'b'); 125 await Zotero.File.putContentsAsync(sourceFile, 'a'); 126 await Zotero.File.putContentsAsync(destFile, 'b'); 127 var newFilename = await Zotero.File.rename(sourceFile, 'b', { unique: true }); 128 var realDestFile = OS.Path.join(tmpDir, newFilename); 129 assert.equal(newFilename, 'b 2'); 130 assert.isTrue(await OS.File.exists(realDestFile)); 131 assert.equal(await Zotero.File.getContentsAsync(realDestFile), 'a'); 132 }); 133 }); 134 135 136 describe("#getClosestDirectory()", function () { 137 it("should return directory for file that exists", function* () { 138 var tmpDir = yield getTempDirectory(); 139 var closest = yield Zotero.File.getClosestDirectory(tmpDir); 140 assert.equal(closest, tmpDir); 141 }); 142 143 it("should return parent directory for missing file", function* () { 144 var tmpDir = yield getTempDirectory(); 145 var closest = yield Zotero.File.getClosestDirectory(OS.Path.join(tmpDir, 'a')); 146 assert.equal(closest, tmpDir); 147 }); 148 149 it("should find an existing directory three levels up from a missing file", function* () { 150 var tmpDir = yield getTempDirectory(); 151 var closest = yield Zotero.File.getClosestDirectory(OS.Path.join(tmpDir, 'a', 'b', 'c')); 152 assert.equal(closest, tmpDir); 153 }); 154 155 it("should return false for a path that doesn't exist at all", function* () { 156 assert.isFalse(yield Zotero.File.getClosestDirectory('/a/b/c')); 157 }); 158 }); 159 160 161 describe("#copyDirectory()", function () { 162 it("should copy all files within a directory", function* () { 163 var tmpDir = Zotero.getTempDirectory().path; 164 var tmpCopyDir = OS.Path.join(tmpDir, "copyDirectory") 165 var source = OS.Path.join(tmpCopyDir, "1"); 166 var target = OS.Path.join(tmpCopyDir, "2"); 167 yield OS.File.makeDir(source, { 168 from: tmpDir 169 }); 170 171 yield Zotero.File.putContentsAsync(OS.Path.join(source, "A"), "Test 1"); 172 yield Zotero.File.putContentsAsync(OS.Path.join(source, "B"), "Test 2"); 173 174 yield OS.File.removeDir(target, { 175 ignoreAbsent: true 176 }); 177 178 yield Zotero.File.copyDirectory(source, target); 179 180 assert.equal( 181 (yield Zotero.File.getContentsAsync(OS.Path.join(target, "A"))), 182 "Test 1" 183 ); 184 assert.equal( 185 (yield Zotero.File.getContentsAsync(OS.Path.join(target, "B"))), 186 "Test 2" 187 ); 188 }) 189 }) 190 191 describe("#zipDirectory()", function () { 192 it("should compress a directory recursively", function* () { 193 var tmpPath = Zotero.getTempDirectory().path; 194 var path = OS.Path.join(tmpPath, Zotero.Utilities.randomString()); 195 yield OS.File.makeDir(path, { unixMode: 0o755 }); 196 yield Zotero.File.putContentsAsync(OS.Path.join(path, '.zotero-ft-cache'), ''); 197 yield Zotero.File.putContentsAsync(OS.Path.join(path, 'a.txt'), 'A'); 198 // Create subdirectory 199 var subPath = OS.Path.join(path, 'sub'); 200 yield OS.File.makeDir(subPath, { unixMode: 0o755 }); 201 yield Zotero.File.putContentsAsync(OS.Path.join(subPath, 'b.txt'), 'B'); 202 203 var zipFile = OS.Path.join(tmpPath, 'test.zip'); 204 yield Zotero.File.zipDirectory(path, zipFile); 205 206 var zr = Components.classes["@mozilla.org/libjar/zip-reader;1"] 207 .createInstance(Components.interfaces.nsIZipReader); 208 zr.open(Zotero.File.pathToFile(zipFile)); 209 var entries = zr.findEntries('*'); 210 var files = {}; 211 var is = Components.classes['@mozilla.org/scriptableinputstream;1'] 212 .createInstance(Components.interfaces.nsIScriptableInputStream); 213 while (entries.hasMore()) { 214 let entryPointer = entries.getNext(); 215 let entry = zr.getEntry(entryPointer); 216 let inputStream = zr.getInputStream(entryPointer); 217 is.init(inputStream); 218 files[entryPointer] = is.read(entry.realSize); 219 } 220 zr.close(); 221 222 assert.notProperty(files, '.zotero-ft-cache'); 223 assert.propertyVal(files, 'a.txt', 'A'); 224 assert.propertyVal(files, 'sub/b.txt', 'B'); 225 }); 226 }); 227 228 229 describe("#checkFileAccessError()", function () { 230 it("should catch OS.File access-denied errors", function* () { 231 // We can't modify a real OS.File.Error, but we also don't do an instanceof check in 232 // checkFileAccessError, so just set the expected properties. 233 var e = { 234 operation: 'open', 235 becauseAccessDenied: true, 236 path: '/tmp/test' 237 }; 238 try { 239 Zotero.File.checkFileAccessError(e, e.path, 'create'); 240 } 241 catch (e) { 242 if (e instanceof Zotero.Error) { 243 return; 244 } 245 throw e; 246 } 247 throw new Error("Error not thrown"); 248 }); 249 }); 250 })