UNPKG

jszip

Version:

Create, read and edit .zip files with Javascript http://stuartk.com/jszip

1,181 lines (987 loc) 45.3 kB
'use strict'; //var JSZip = require('../lib'); function similar(actual, expected, mistakes) { // actual is the generated zip, expected is what we got from the xhr. // Be sure to have a well formatted string expected = JSZip.utils.string2binary(expected); if (actual.length !== expected.length) { mistakes -= Math.abs((actual.length||0) - (expected.length||0)); } for (var i = 0; i < Math.min(actual.length, expected.length); i++) { if (actual.charAt(i) !== expected.charAt(i)) { mistakes--; } } if (mistakes < 0) return false; else return true; } /** * bytes -> JSZip -> bytes */ function reload(bytesStream) { return new JSZip(bytesStream, {checkCRC32:true}).generate({type:"string"}); } // cache for files var refZips = {}; function testZipFile(testName, zipName, testFunction) { test(testName, function () { if (refZips[zipName]) { testFunction.call(this, refZips[zipName]); } else { stop(); JSZipTestUtils.loadZipFile(zipName, function (file) { start(); refZips[zipName] = file; testFunction.call(this, file); }, function(error){ if (QUnit.config.semaphore) { start(); } ok(false, error); }); } }); } test("JSZip", function(){ ok(JSZip, "JSZip exists"); var zip = new JSZip(); ok(zip instanceof JSZip, "Constructor works"); var zipNoNew = JSZip(); ok(zipNoNew instanceof JSZip, "Constructor adds `new` before itself where necessary"); }); QUnit.module("Essential"); // {{{ test("JSZip.utils.transformTo", function () { var supportedArgs = ['string', 'array']; if (JSZip.support.arraybuffer) { supportedArgs.push("arraybuffer"); } if (JSZip.support.uint8array) { supportedArgs.push("uint8array"); } if (JSZip.support.nodebuffer) { supportedArgs.push("nodebuffer"); } var txt = 'test text !'; for (var i = 0; i < supportedArgs.length; i++) { for (var j = 0; j < supportedArgs.length; j++) { var step1 = JSZip.utils.transformTo(supportedArgs[i], txt); var step2 = JSZip.utils.transformTo(supportedArgs[j], step1); var result = JSZip.utils.transformTo("string", step2); equal(result, txt, "The transformation string -> " + supportedArgs[i] + " -> " + supportedArgs[j] + " -> string works"); } } }); testZipFile("Zip text file !", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var content = zip.generate(); var actual = JSZip.base64.decode(content); /* Expected differing bytes: 2 version number 4 date/time 4 central dir version numbers 4 central dir date/time 4 external file attributes 18 Total */ ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); testZipFile("Add a file to overwrite", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "hello ?"); zip.file("Hello.txt", "Hello World\n"); var content = zip.generate(); var actual = JSZip.base64.decode(content); /* Expected differing bytes: 2 version number 4 date/time 4 central dir version numbers 4 central dir date/time 4 external file attributes 18 Total */ ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); // zip -X -0 utf8.zip amount.txt testZipFile("Zip text file with UTF-8 characters", "ref/utf8.zip", function(expected) { var zip = new JSZip(); zip.file("amount.txt", "€15\n"); var actual = zip.generate({type:"string"}); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); // zip -X -0 utf8_in_name.zip €15.txt testZipFile("Zip text file with UTF-8 characters in filename", "ref/utf8_in_name.zip", function(expected) { var zip = new JSZip(); zip.file("€15.txt", "€15\n"); var actual = zip.generate({type:"string"}); // zip doesn't generate a strange file like us (utf8 flag AND unicode path extra field) // if one of the files has more data than the other, the bytes are no more aligned and the // error count goes through the roof. The parsing is checked on a other test so I'll // comment this one for now. // ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); testZipFile("Zip text file with date", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n", {date : new Date("July 17, 2009 14:36:57")}); var content = zip.generate(); var actual = JSZip.base64.decode(content); /* Expected differing bytes: 2 version number 4 central dir version numbers 4 external file attributes 10 Total */ ok(similar(actual, expected, 10) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); testZipFile("Zip image file", "ref/image.zip", function(expected) { var zip = new JSZip(); zip.file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true}); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); test("Zip folder() shouldn't throw an exception", function(expected) { var zip = new JSZip(); try { zip.folder(); ok(true, "no exception thrown"); } catch (e) { ok(false, e.message||e); } }); testZipFile("Zip empty folder", "ref/folder.zip", function(expected) { var zip = new JSZip(); zip.folder("folder"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); testZipFile("Zip text, folder and image", "ref/all.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); zip.folder("images").file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true}); var content = zip.generate(); var actual = JSZip.base64.decode(content); /* Expected differing bytes: 2 version number 4 date/time 4 central dir version numbers 4 central dir date/time 4 external file attributes 18 * 3 files 54 Total */ ok(similar(actual, expected, 54) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); test("Finding a file", function() { var zip = new JSZip(); zip.file("Readme", "Hello World!\n"); zip.file("Readme.French", "Bonjour tout le monde!\n"); zip.file("Readme.Pirate", "Ahoy m'hearty!\n"); equal(zip.file("Readme.French").asText(), "Bonjour tout le monde!\n", "Exact match found"); equal(zip.file("Readme.Deutch"), null, "Match exactly nothing"); equal(zip.file(/Readme\../).length, 2, "Match regex free text"); equal(zip.file(/pirate/i).length, 1, "Match regex 1 result"); }); testZipFile("Finding a file : modifying the result doesn't alter the zip", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); zip.file("Hello.txt").name = "Hello2.txt"; zip.file("Hello.txt").options.dir = true; // these changes won't be used var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); test("Finding a file (text search) with a relative folder", function() { var zip = new JSZip(); zip.folder("files/default").file("Readme", "Hello World!\n"); zip.folder("files/translation").file("Readme.French", "Bonjour tout le monde!\n"); zip.folder("files").folder("translation").file("Readme.Pirate", "Ahoy m'hearty!\n"); equal(zip.file("files/translation/Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with the full path"); equal(zip.folder("files").file("translation/Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with a relative path"); equal(zip.folder("files/translation").file("Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with a relative path"); }); test("Finding files (regex) with a relative folder", function() { var zip = new JSZip(); zip.folder("files/default").file("Readme", "Hello World!\n"); zip.folder("files/translation").file("Readme.French", "Bonjour tout le monde!\n"); zip.folder("files").folder("translation").file("Readme.Pirate", "Ahoy m'hearty!\n"); equal(zip.file(/Readme/).length, 3, "match files in subfolders"); equal(zip.folder("files/translation").file(/Readme/).length, 2, "regex match only in subfolders"); equal(zip.folder("files").folder("translation").file(/Readme/).length, 2, "regex match only in subfolders"); equal(zip.folder("files/translation").file(/pirate/i).length, 1, "regex match only in subfolders"); equal(zip.folder("files/translation").file(/^readme/i).length, 2, "regex match only with the relative path"); equal(zip.folder("files/default").file(/pirate/i).length, 0, "regex match only in subfolders"); }); test("Finding folders", function () { var zip = new JSZip(); zip.folder("root/").folder("sub1/"); zip.folder("root/sub2/subsub1"); equal(zip.folder(/sub2\/$/).length, 1, "unique result"); equal(zip.folder(/sub1/).length, 2, "multiple results"); equal(zip.folder(/root/).length, 4, "match on whole path"); }); test("Finding folders with relative path", function () { var zip = new JSZip(); zip.folder("root/").folder("sub1/"); zip.folder("root/sub2/subsub1"); var root = zip.folder("root/sub2"); equal(root.folder(/sub2\/$/).length, 0, "current folder is not matched"); equal(root.folder(/sub1/).length, 1, "sub folder is matched"); equal(root.folder(/^subsub1/).length, 1, "relative folder path is used"); equal(root.folder(/root/).length, 0, "parent folder is not matched"); }); // }}} module Essential QUnit.module("More advanced"); // {{{ testZipFile("Delete file", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Remove.txt", "This file should be deleted\n"); zip.file("Hello.txt", "Hello World\n"); zip.remove("Remove.txt"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete file in folder", "ref/folder.zip", function(expected) { var zip = new JSZip(); zip.folder("folder").file("Remove.txt", "This folder and file should be deleted\n"); zip.remove("folder/Remove.txt"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete file in folder, with a relative path", "ref/folder.zip", function(expected) { var zip = new JSZip(); var folder = zip.folder("folder"); folder.file("Remove.txt", "This folder and file should be deleted\n"); folder.remove("Remove.txt"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete folder", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); zip.file("Hello.txt", "Hello World\n"); zip.remove("remove"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete folder with a final /", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); zip.file("Hello.txt", "Hello World\n"); zip.remove("remove/"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete unknown path", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); zip.remove("unknown_file"); zip.remove("unknown_folder/Hello.txt"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete nested folders", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); zip.folder("remove/second").file("Sub.txt", "This should be removed"); zip.file("remove/second/another.txt", "Another file"); zip.file("Hello.txt", "Hello World\n"); zip.remove("remove"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("Delete nested folders from relative path", "ref/folder.zip", function(expected) { var zip = new JSZip(); zip.folder("folder"); zip.folder("folder/1/2/3"); zip.folder("folder").remove("1"); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); equal(reload(actual), actual, "Generated ZIP can be parsed"); }); testZipFile("add file: from XHR (with bytes > 255)", "ref/text.zip", function(textZip) { var zip = new JSZip(); zip.file("text.zip", textZip, {binary:true}); var actual = zip.generate({base64:false}); equal(reload(actual), actual, "high-order byte is discarded and won't mess up the result"); }); function testFileDataGetters (opts) { if (typeof opts.rawData === "undefined") { opts.rawData = opts.textData; } _actualTestFileDataGetters.asText(opts); _actualTestFileDataGetters.asBinary(opts); _actualTestFileDataGetters.asArrayBuffer(opts); _actualTestFileDataGetters.asUint8Array(opts); _actualTestFileDataGetters.asNodeBuffer(opts); var reload = function () { return { name : "reloaded, " + opts.name, // no check of crc32, we want to test the CompressedObject code. zip : new JSZip(opts.zip.generate({type:"string"}, {checkCRC32:false})), textData : opts.textData, rawData : opts.rawData }; }; _actualTestFileDataGetters.asText(reload()); _actualTestFileDataGetters.asBinary(reload()); _actualTestFileDataGetters.asArrayBuffer(reload()); _actualTestFileDataGetters.asUint8Array(reload()); _actualTestFileDataGetters.asNodeBuffer(reload()); } var _actualTestFileDataGetters = { asText : function (opts) { equal(opts.zip.file("file.txt").asText(), opts.textData, opts.name + " : asText()"); }, asBinary : function (opts) { equal(opts.zip.file("file.txt").asBinary(), opts.rawData, opts.name + " : asBinary()"); }, asArrayBuffer : function (opts) { if (JSZip.support.arraybuffer) { var buffer = opts.zip.file("file.txt").asArrayBuffer(); ok(buffer instanceof ArrayBuffer, opts.name + " : the result is a instance of ArrayBuffer"); var actual = JSZip.utils.transformTo("string", buffer); equal(actual, opts.rawData, opts.name + " : asArrayBuffer()"); } else { try { opts.zip.file("file.txt").asArrayBuffer(); ok(false, "no exception thrown"); } catch (e) { ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); } } }, asUint8Array : function (opts) { if (JSZip.support.uint8array) { var bufferView = opts.zip.file("file.txt").asUint8Array(); ok(bufferView instanceof Uint8Array, opts.name + " : the result is a instance of Uint8Array"); var actual = JSZip.utils.transformTo("string", bufferView); equal(actual, opts.rawData, opts.name + " : asUint8Array()"); } else { try { opts.zip.file("file.txt").asUint8Array(); ok(false, "no exception thrown"); } catch (e) { ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); } } }, asNodeBuffer : function (opts) { if (JSZip.support.nodebuffer) { var buffer = opts.zip.file("file.txt").asNodeBuffer(); ok(buffer instanceof Buffer, opts.name + " : the result is a instance of Buffer"); var actual = JSZip.utils.transformTo("string", buffer); equal(actual, opts.rawData, opts.name + " : .asNodeBuffer()"); } else { try { opts.zip.file("file.txt").asNodeBuffer(); ok(false, "no exception thrown"); } catch (e) { ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); } } } }; test("add file: file(name, undefined)", function() { var zip = new JSZip(), undef; zip.file("file.txt", undef); testFileDataGetters({name : "undefined", zip : zip, textData : ""}); zip = new JSZip(); zip.file("file.txt", undef, {binary:true}); testFileDataGetters({name : "undefined", zip : zip, textData : ""}); zip = new JSZip(); zip.file("file.txt", undef, {base64:true}); testFileDataGetters({name : "undefined", zip : zip, textData : ""}); }); test("add file: file(name, null)", function() { var zip = new JSZip(); zip.file("file.txt", null); testFileDataGetters({name : "null", zip : zip, textData : ""}); zip = new JSZip(); zip.file("file.txt", null, {binary:true}); testFileDataGetters({name : "null", zip : zip, textData : ""}); zip = new JSZip(); zip.file("file.txt", null, {base64:true}); testFileDataGetters({name : "null", zip : zip, textData : ""}); }); test("add file: file(name, stringAsText)", function() { var zip = new JSZip(); zip.file("file.txt", "€15\n", {binary:false}); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", "test\r\ntest\r\n", {binary:false}); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); }); test("add file: file(name, stringAsBinary)", function() { var zip = new JSZip(); zip.file("file.txt", "\xE2\x82\xAC15\n", {binary:true}); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", "test\r\ntest\r\n", {binary:true}); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); }); test("add file: file(name, base64)", function() { var zip = new JSZip(); zip.file("file.txt", "4oKsMTUK", {base64:true}); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", "dGVzdA0KdGVzdA0K", {base64:true}); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); }); test("add file: file(name, unsupported)", function() { var zip = new JSZip(); try { zip.file("test.txt", new Date()); ok(false, "An unsupported object was added, but no exception thrown"); } catch(e) { ok(e.message.match("unsupported format"), "the error message is useful"); } if (JSZip.support.blob) { var blob = zip.generate({type:"blob"}); try { zip.file("test.txt", blob); ok(false, "An blob was added, but no exception thrown"); } catch(e) { ok(e.message.match("unsupported format"), "the error message is useful"); } } }); if (JSZip.support.uint8array) { test("add file: file(name, Uint8Array)", function() { var str2array = function (str) { var array = new Uint8Array(str.length); for(var i = 0; i < str.length; i++) { array[i] = str.charCodeAt(i); } return array; }; var zip = new JSZip(); zip.file("file.txt", str2array("\xE2\x82\xAC15\n")); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", str2array("test\r\ntest\r\n")); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); zip = new JSZip(); zip.file("file.txt", str2array("")); testFileDataGetters({name : "empty content", zip : zip, textData : ""}); }); } if (JSZip.support.arraybuffer) { test("add file: file(name, ArrayBuffer)", function() { var str2buffer = function (str) { var array = new Uint8Array(str.length); for(var i = 0; i < str.length; i++) { array[i] = str.charCodeAt(i); } return array.buffer; }; var zip = new JSZip(); zip.file("file.txt", str2buffer("\xE2\x82\xAC15\n")); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", str2buffer("test\r\ntest\r\n")); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); zip = new JSZip(); zip.file("file.txt", str2buffer("")); testFileDataGetters({name : "empty content", zip : zip, textData : ""}); }); } if (JSZip.support.nodebuffer) { test("add file: file(name, Buffer)", function() { var str2buffer = function (str) { var array = new Buffer(str.length); for(var i = 0; i < str.length; i++) { array[i] = str.charCodeAt(i); } return array; }; var zip = new JSZip(); zip.file("file.txt", str2buffer("\xE2\x82\xAC15\n")); testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); zip = new JSZip(); zip.file("file.txt", str2buffer("test\r\ntest\r\n")); testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); zip = new JSZip(); zip.file("file.txt", str2buffer("")); testFileDataGetters({name : "empty content", zip : zip, textData : ""}); }); } testZipFile("generate : base64:false. Deprecated, but it still works", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var actual = zip.generate({base64:false}); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("generate : base64:true. Deprecated, but it still works", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var content = zip.generate({base64:true}); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("generate : type:string", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var actual = zip.generate({type:"string"}); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("generate : type:base64", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var content = zip.generate({type:"base64"}); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); if (JSZip.support.uint8array) { testZipFile("generate : type:uint8array", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var array = zip.generate({type:"uint8array"}); ok(array instanceof Uint8Array, "The result is a instance of Uint8Array"); equal(array.length, expected.length); var actual = JSZip.utils.transformTo("string", array); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); } else { testZipFile("generate : type:uint8array", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); try { var blob = zip.generate({type:"uint8array"}); ok(false, "Uint8Array is not supported, but no exception thrown"); } catch(e) { ok(e.message.match("not supported by this browser"), "the error message is useful"); } }); } if (JSZip.support.arraybuffer) { testZipFile("generate : type:arraybuffer", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var buffer = zip.generate({type:"arraybuffer"}); ok(buffer instanceof ArrayBuffer, "The result is a instance of ArrayBuffer"); var actual = JSZip.utils.transformTo("string", buffer); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); } else { testZipFile("generate : type:arraybuffer", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); try { var blob = zip.generate({type:"arraybuffer"}); ok(false, "ArrayBuffer is not supported, but no exception thrown"); } catch(e) { ok(e.message.match("not supported by this browser"), "the error message is useful"); } }); } if (JSZip.support.nodebuffer) { testZipFile("generate : type:nodebuffer", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var buffer = zip.generate({type:"nodebuffer"}); ok(buffer instanceof Buffer, "The result is a instance of ArrayBuffer"); var actual = ""; for (var i = 0; i < buffer.length; i++) { actual += String.fromCharCode(buffer[i]); } ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); } else { testZipFile("generate : type:nodebuffer", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); try { var blob = zip.generate({type:"nodebuffer"}); ok(false, "Buffer is not supported, but no exception thrown"); } catch(e) { ok(e.message.match("not supported by this browser"), "the error message is useful"); } }); } if (JSZip.support.blob) { testZipFile("generate : type:blob", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var blob = zip.generate({type:"blob"}); ok(blob instanceof Blob, "The result is a instance of Blob"); equal(blob.type, "application/zip"); equal(blob.size, expected.length); }); } else { testZipFile("generate : type:blob", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); try { var blob = zip.generate({type:"blob"}); ok(false, "Blob is not supported, but no exception thrown"); } catch(e) { ok(e.message.match("not supported by this browser"), "the error message is useful"); } }); } test("Filtering a zip", function() { var zip = new JSZip(); zip.file("1.txt", "1\n"); zip.file("2.txt", "2\n"); zip.file("3.log", "3\n"); var result = zip.filter(function (relativeFilename, file){ return relativeFilename.indexOf(".txt") != -1; }); equal(result.length, 2, "filter has filtered"); ok(result[0].name.indexOf(".txt") != -1, "filter has filtered the good file"); ok(result[1].name.indexOf(".txt") != -1, "filter has filtered the good file"); }); test("Filtering a zip from a relative path", function() { var zip = new JSZip(); zip.file("foo/1.txt", "1\n"); zip.file("foo/2.txt", "2\n"); zip.file("foo/3.log", "3\n"); zip.file("1.txt", "1\n"); zip.file("2.txt", "2\n"); zip.file("3.log", "3\n"); var result = zip.folder("foo").filter(function (relativeFilename, file) { return relativeFilename.indexOf("3") != -1; }); equal(result.length, 1, "filter has filtered"); equal(result[0].name, "foo/3.log", "filter has filtered the good file"); }); test("Filtering a zip : the full path is still accessible", function() { var zip = new JSZip(); zip.file("foo/1.txt", "1\n"); zip.file("foo/2.txt", "2\n"); zip.file("foo/3.log", "3\n"); zip.file("1.txt", "1\n"); zip.file("2.txt", "2\n"); zip.file("3.log", "3\n"); var result = zip.folder("foo").filter(function (relativeFilename, file) { return file.name.indexOf("3") != -1; }); equal(result.length, 1, "the filter only match files/folders in the current folder"); equal(result[0].name, "foo/3.log", "filter has filtered the good file"); }); testZipFile("Filtering a zip : the filter function can't alter the data", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); zip.filter(function (relativeFilename, file) { file.name = "bye.txt"; file.data = "good bye"; file.options.dir = true; }); var content = zip.generate(); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); testZipFile("STORE is the default method", "ref/text.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var content = zip.generate({compression:'STORE'}); var actual = JSZip.base64.decode(content); // no difference with the "Zip text file" test. ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); // zip -0 -X store.zip Hello.txt testZipFile("STORE doesn't compress", "ref/store.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); var content = zip.generate({compression:'STORE'}); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); /* // commented because the new implementation of DEFLATE produces different results from the old one. // zip -6 -X deflate.zip Hello.txt testZipFile("DEFLATE compress", "ref/deflate.zip", function(expected) { var zip = new JSZip(); zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); var content = zip.generate({compression:'DEFLATE'}); var actual = JSZip.base64.decode(content); ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); }); */ test("Lazy decompression works", function () { var zip = new JSZip(); zip.folder("test/").file("Hello.txt", "hello !"); var expected = zip.generate({type:"string", compression:"STORE"}); zip = new JSZip(expected); // lazy equal(zip.generate({type:"string", compression:"STORE"}), expected, "Reloading file, same compression"); zip = new JSZip(zip.generate({type:"string", compression:"DEFLATE"})); zip = new JSZip(zip.generate({type:"string", compression:"STORE"})); var zipData = zip.generate({type:"string", compression:"STORE"}); equal(zipData, expected, "Reloading file, different compression"); // check CRC32 new JSZip(zipData, {checkCRC32:true}).generate({type:"string"}); }); test("Empty files / folders are not compressed", function() { var zip = new JSZip(); zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); zip.folder("folder").file("empty", ""); var deflateCount = 0, emptyDeflateCount = 0; var oldDeflateCompress = JSZip.compressions.DEFLATE.compress; JSZip.compressions.DEFLATE.compress = function (str) { deflateCount++; if (!str) { emptyDeflateCount++; } return str; }; zip.generate({compression:'DEFLATE'}); equal(deflateCount, 1, "The file has been compressed"); equal(emptyDeflateCount, 0, "The file without content and the folder has not been compressed."); JSZip.compressions.DEFLATE.compress = oldDeflateCompress; }); test("unknown compression throws an exception", function () { var zip = new JSZip().file("file.txt", "test"); try { zip.generate({compression:'MAYBE'}); ok(false, "no exception"); } catch (e) { ok(true, "an exception were thrown"); } }); // }}} More advanced QUnit.module("Load file, not supported features"); // {{{ // zip -0 -X -e encrypted.zip Hello.txt testZipFile("basic encryption", "ref/encrypted.zip", function(file) { try { var zip = new JSZip(file); ok(false, "Encryption is not supported, but no exception were thrown"); } catch(e) { equal(e.message, "Encrypted zip are not supported", "the error message is useful"); } }); // }}} Load file, not supported features QUnit.module("Load file, corrupted zip"); // {{{ testZipFile("bad compression method", "ref/invalid/compression.zip", function(file) { try { var zip = new JSZip(file); ok(false, "no exception were thrown"); } catch(e) { ok(e.message.match("Corrupted zip"), "the error message is useful"); } }); testZipFile("invalid crc32 but no check", "ref/invalid/crc32.zip", function(file) { try { var zip = new JSZip(file, {checkCRC32:false}); ok(true, "no exception were thrown"); } catch(e) { ok(false, "An exception were thrown but the check should have been disabled."); } }); testZipFile("invalid crc32", "ref/invalid/crc32.zip", function(file) { try { var zip = new JSZip(file, {checkCRC32:true}); ok(false, "no exception were thrown"); } catch(e) { ok(e.message.match("Corrupted zip"), "the error message is useful"); } }); testZipFile("bad offset", "ref/invalid/bad_offset.zip", function(file) { try { var zip = new JSZip(file); ok(false, "no exception were thrown"); } catch(e) { ok(e.message.match("Corrupted zip"), "the error message is useful"); } }); // }}} Load file, corrupted zip QUnit.module("Load file"); // {{{ testZipFile("load(string) works", "ref/all.zip", function(file) { ok(typeof file === "string"); var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); testZipFile("load(string) handles bytes > 255", "ref/all.zip", function(file) { // the method used to load zip with ajax will remove the extra bits. // adding extra bits :) var updatedFile = ""; for (var i = 0; i < file.length; i++) { updatedFile += String.fromCharCode((file.charCodeAt(i) & 0xff) + 0x4200); } var zip = new JSZip(updatedFile); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); if (JSZip.support.arraybuffer) { testZipFile("load(ArrayBuffer) works", "ref/all.zip", function(fileAsString) { var file = new ArrayBuffer(fileAsString.length); var bufferView = new Uint8Array(file); for( var i = 0; i < fileAsString.length; ++i ) { bufferView[i] = fileAsString.charCodeAt(i); } ok(file instanceof ArrayBuffer); // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). equal(new JSZip(file).file("Hello.txt").asArrayBuffer().byteLength, 12, "don't get the original buffer"); equal(new JSZip(file).file("Hello.txt").asUint8Array().buffer.byteLength, 12, "don't get a view of the original buffer"); equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); } if (JSZip.support.nodebuffer) { testZipFile("load(Buffer) works", "ref/all.zip", function(fileAsString) { var file = new Buffer(fileAsString.length); for( var i = 0; i < fileAsString.length; ++i ) { file[i] = fileAsString.charCodeAt(i); } equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); } if (JSZip.support.uint8array) { testZipFile("load(Uint8Array) works", "ref/all.zip", function(fileAsString) { var file = new Uint8Array(fileAsString.length); for( var i = 0; i < fileAsString.length; ++i ) { file[i] = fileAsString.charCodeAt(i); } ok(file instanceof Uint8Array); // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). equal(new JSZip(file).file("Hello.txt").asArrayBuffer().byteLength, 12, "don't get the original buffer"); equal(new JSZip(file).file("Hello.txt").asUint8Array().buffer.byteLength, 12, "don't get a view of the original buffer"); equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); } // zip -6 -X deflate.zip Hello.txt testZipFile("zip with DEFLATE", "ref/deflate.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "This a looong file : we need to see the difference between the different compression methods.\n", "the zip was correctly read."); }); // zip -0 -z -c archive_comment.zip Hello.txt testZipFile("zip with comment", "ref/archive_comment.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); // zip -0 extra_attributes.zip Hello.txt testZipFile("zip with extra attributes", "ref/extra_attributes.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); // use -fz to force use of Zip64 format // zip -fz -0 zip64.zip Hello.txt testZipFile("zip 64", "ref/zip64.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); // use -fd to force data descriptors as if streaming // zip -fd -0 data_descriptor.zip Hello.txt testZipFile("zip with data descriptor", "ref/data_descriptor.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); }); // combo of zip64 and data descriptors : // zip -fz -fd -0 data_descriptor_zip64.zip Hello.txt // this generate a corrupted zip file :( // TODO : find how to get the two features // zip -0 -X zip_within_zip.zip Hello.txt && zip -0 -X nested.zip Hello.txt zip_within_zip.zip testZipFile("nested zip", "ref/nested.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); var nested = new JSZip(zip.file("zip_within_zip.zip").asBinary()); equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); }); // zip -fd -0 nested_data_descriptor.zip data_descriptor.zip testZipFile("nested zip with data descriptors", "ref/nested_data_descriptor.zip", function(file) { var zip = new JSZip(file); var nested = new JSZip(zip.file("data_descriptor.zip").asBinary()); equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); }); // zip -fz -0 nested_zip64.zip zip64.zip testZipFile("nested zip 64", "ref/nested_zip64.zip", function(file) { var zip = new JSZip(file); var nested = new JSZip(zip.file("zip64.zip").asBinary()); equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); }); // nested zip 64 with data descriptors // zip -fz -fd -0 nested_data_descriptor_zip64.zip data_descriptor_zip64.zip // this generate a corrupted zip file :( // TODO : find how to get the two features // zip -X -0 utf8_in_name.zip €15.txt testZipFile("Zip text file with UTF-8 characters in filename", "ref/utf8_in_name.zip", function(file) { var zip = new JSZip(file); ok(zip.file("€15.txt") !== null, "the utf8 file is here."); equal(zip.file("€15.txt").asText(), "€15\n", "the utf8 content was correctly read (with file().asText)."); equal(zip.files["€15.txt"].asText(), "€15\n", "the utf8 content was correctly read (with files[].astext)."); }); // Created with winrar // winrar will replace the euro symbol with a '_' but set the correct unicode path in an extra field. testZipFile("Zip text file with UTF-8 characters in filename and windows compatibility", "ref/winrar_utf8_in_name.zip", function(file) { var zip = new JSZip(file); ok(zip.file("€15.txt") !== null, "the utf8 file is here."); equal(zip.file("€15.txt").asText(), "€15\n", "the utf8 content was correctly read (with file().asText)."); equal(zip.files["€15.txt"].asText(), "€15\n", "the utf8 content was correctly read (with files[].astext)."); }); // zip backslash.zip -0 -X Hel\\lo.txt testZipFile("Zip text file with backslash in filename", "ref/backslash.zip", function(file) { var zip = new JSZip(file); equal(zip.file("Hel\\lo.txt").asText(), "Hello World\n", "the utf8 content was correctly read."); }); // use izarc to generate a zip file on windows testZipFile("Zip text file from windows with \\ in central dir", "ref/slashes_and_izarc.zip", function(file) { var zip = new JSZip(file); equal(zip.folder("test").file("Hello.txt").asText(), "Hello world\r\n", "the content was correctly read."); }); test("A folder stays a folder", function () { var zip = new JSZip(); zip.folder("folder/"); ok(zip.files['folder/'].options.dir, "the folder is marked as a folder"); var reloaded = new JSZip(zip.generate({base64:false})); ok(reloaded.files['folder/'].options.dir, "the folder is marked as a folder"); }); // }}} Load file QUnit.module("Load complex files"); // {{{ if (QUnit.urlParams.complexfiles) { // http://www.feedbooks.com/book/8/the-metamorphosis testZipFile("Franz Kafka - The Metamorphosis.epub", "ref/complex_files/Franz Kafka - The Metamorphosis.epub", function(file) { var zip = new JSZip(file); equal(zip.filter(function(){return true;}).length, 26, "the zip contains the good number of elements."); equal(zip.file("mimetype").asText(), "application/epub+zip\r\n", "the zip was correctly read."); // the .ncx file tells us that the first chapter is in the main0.xml file. ok(zip.file("OPS/main0.xml").asText().indexOf("One morning, as Gregor Samsa was waking up from anxious dreams") !== -1, "the zip was correctly read."); }); // a showcase in http://msdn.microsoft.com/en-us/windows/hardware/gg463429 testZipFile("Outlook2007_Calendar.xps", "ref/complex_files/Outlook2007_Calendar.xps", function(file) { var zip = new JSZip(file); // the zip file contains 15 entries, but we get 23 when creating all the sub-folders. equal(zip.filter(function(){return true;}).length, 23, "the zip contains the good number of elements."); ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.ms-package.xps-fixeddocument+xml") !== -1, "the zip was correctly read."); }); // an example file in http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip // the data come from http://www.antarctica.ac.uk/met/READER/upper_air/ testZipFile("AntarcticaTemps.xlsx", "ref/complex_files/AntarcticaTemps.xlsx", function(file) { var zip = new JSZip(file); // the zip file contains 16 entries, but we get 27 when creating all the sub-folders. equal(zip.filter(function(){return true;}).length, 27, "the zip contains the good number of elements."); ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml") !== -1, "the zip was correctly read."); }); // same as above, but in the Open Document format testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function(file) { var zip = new JSZip(file); // the zip file contains 19 entries, but we get 27 when creating all the sub-folders. equal(zip.filter(function(){return true;}).length, 27, "the zip contains the good number of elements."); ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); }); } // }}} Load complex files // enforcing Stuk's coding style // vim: set shiftwidth=3 softtabstop=3: