// ExtendedTests.cs // ------------------------------------------------------------------ // // Copyright (c) 2008-2011 Dino Chiesa. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // // This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // // last saved (in emacs): // Time-stamp: <2011-August-06 17:04:31> // // ------------------------------------------------------------------ // // This module defines some extended tests for DotNetZip. It gets into // advanced features - file selection, encryption, and more. // // ------------------------------------------------------------------ using System; using System.IO; using System.Text; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Ionic.Zip; using Ionic.Zip.Tests.Utilities; namespace Ionic.Zip.Tests.Extended { public class XTWFND : System.Xml.XmlTextWriter { public XTWFND(TextWriter w) : base(w) { Formatting = System.Xml.Formatting.Indented; } public override void WriteStartDocument() { } } /// /// Summary description for ExtendedTests /// [TestClass] public class ExtendedTests : IonicTestClass { public ExtendedTests() : base() { } static String StreamToStringUTF8(Stream s) { string result = null; // UTF-8 is the default, but I want to be explicit here. using (var f = new StreamReader(s, System.Text.Encoding.UTF8)) { result = f.ReadToEnd(); } return result; } static bool IsEncodable(String s, Encoding e) { bool result = false; try { byte[] b = e.GetBytes(s); var s2 = e.GetString(b); result = (s == s2); } catch { result = false; } return result; } EncryptionAlgorithm[] crypto = { EncryptionAlgorithm.None, EncryptionAlgorithm.PkzipWeak, EncryptionAlgorithm.WinZipAes128, EncryptionAlgorithm.WinZipAes256, }; EncryptionAlgorithm[] cryptoNoPkzip = { EncryptionAlgorithm.None, EncryptionAlgorithm.WinZipAes128, EncryptionAlgorithm.WinZipAes256, }; Ionic.Zlib.CompressionLevel[] compLevels = { Ionic.Zlib.CompressionLevel.None, Ionic.Zlib.CompressionLevel.BestSpeed, Ionic.Zlib.CompressionLevel.Default, Ionic.Zlib.CompressionLevel.BestCompression, }; Zip64Option[] z64 = { Zip64Option.Never, Zip64Option.AsNecessary, Zip64Option.Always, }; [TestMethod] [Timeout(22 * 60*1000)] public void Bzip2_Perf() { // Verify that the parallel compress option works properly // with BZip2. TestContext.WriteLine("Creating the fodder files..."); _txrx = TestUtilities.StartProgressMonitor("BZip2PerfTest", "BZip2 Performance Test", "Creating files"); var update = new Action((op,ix,sz) => { switch(op) { case 0: _txrx.Send("pb 1 max " + sz); _txrx.Send("status Creating file " + ix); break; case 1: _txrx.Send("pb 1 value " + sz); break; case 2: _txrx.Send("pb 0 step"); _txrx.Send("pb 1 value 0"); break; } }); _txrx.Send("bars 2"); int threshold = 1024 * 1024; int n = _rnd.Next(3) + 3; int minSize = 0x2000000 + this._rnd.Next(0x4000000); int maxSize = 0x2000000 + minSize + this._rnd.Next(0x80000); string dirInZip = "files"; string extractDir = "extract"; string subdir = dirInZip; _txrx.Send("pb 0 max " + n); var filesToZip = TestUtilities.GenerateFilesFlat(subdir, n, minSize, maxSize, update); var fi = new FileInfo(filesToZip[_rnd.Next(filesToZip.Length)]); Assert.IsTrue(fi.Length > threshold, "For file {1}, length ({0}) does not meet threshold", fi.Name, fi.Length); // Get the unzip.exe tool: string dnzDir = CurrentDir; for (int i = 0; i < 3; i++) dnzDir = Path.GetDirectoryName(dnzDir); string unzip = Path.Combine(dnzDir, "Tools\\Unzip\\bin\\debug\\Unzip.exe"); Assert.IsTrue(File.Exists(unzip), "The unzip.exe tool is not available."); _txrx.Send("pb 0 max " + (4*2)); _txrx.Send("status done creating files..."); // two passes: once for regular, once for parallel compress var ts = new TimeSpan[2]; var fileSize = new Int64[2]; for (int k=0; k < 2; k++) { System.Threading.Thread.Sleep(1200); var msg = string.Format("test BZip2 perf check, cycle {0}/2 (est. time: 22 mins)",k+1); _txrx.Send(msg); string zipFileToCreate = "BZip2_Perf."+k+".zip"; TestContext.WriteLine("pass {0}, Creating the zip...", k); var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); // Now, Create the zip archive with DotNetZip _cancelIndex = -1; using (ZipFile zip1 = new ZipFile()) { zip1.ParallelDeflateThreshold = (k==0) ? -1 : threshold; zip1.CompressionMethod = CompressionMethod.BZip2; zip1.AddFiles(filesToZip, dirInZip); zip1.SaveProgress += SaveProgress; zip1.Save(zipFileToCreate); } stopwatch.Stop(); ts[k] = stopwatch.Elapsed; fi = new FileInfo(zipFileToCreate); fileSize[k] = fi.Length; TestContext.WriteLine("size of resulting zip: {0}k", fileSize[k] / 1024); _txrx.Send("pb 0 step"); _txrx.Send("status verifying the number of files"); // Verify the number of files in the zip TestContext.WriteLine("Verifying the number of files in the zip..."); Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), filesToZip.Length, "Incorrect number of entries in the zip file."); _txrx.Send("pb 0 step"); // examine and unpack the zip archive via DNZ tools. // Get info on the zip file: string unzipOut = this.Exec(unzip, "-i " + zipFileToCreate); // Verify that the output states that the compression method // used for each entry was BZIP2... _txrx.Send("status checking for BZIP compression..."); TestContext.WriteLine("Verifying that BZIP2 was used..."); Assert.AreEqual (TestUtilities.CountOccurrences(unzipOut, "Compression: BZip2"), n); _txrx.Send("pb 0 step"); _txrx.Send("status Extracting via infozip unzip.exe..."); // Extract the zip. eg, unzip.exe test.zip -d TestContext.WriteLine("Extracting via unzip.exe..."); this.Exec(unzip, zipFileToCreate + " -d " + extractDir); // Verify the count of extracted files int fileCount = Directory.GetFiles(Path.Combine(extractDir,dirInZip)).Length; Assert.IsTrue(fileCount == n, "Not all files were extracted? (found {0}, expected {1})", fileCount, n); Directory.Delete(extractDir, true); _txrx.Send("pb 0 step"); } var delta = (ts[0].TotalSeconds - ts[1].TotalSeconds) / (0.01 * ts[0].TotalSeconds); TestContext.WriteLine("Parallel compression reduced compression time by {0:N1}%", delta); // verify the time required for parallel compression is lower. Assert.IsTrue(ts[1] < ts[0], "Parallel compression took MORE time."); delta = Math.Abs((int)(fileSize[1]-fileSize[0])) / (0.01 * fileSize[0]); Assert.IsTrue(delta < 5.0, "Parallel compression is not within 5% of normal filesize."); TestContext.WriteLine("A-ok"); } [TestMethod] public void TestZip_IsZipFile() { string zipFileToCreate = Path.Combine(TopLevelDir, "TestZip_IsZipFile.zip"); int entriesAdded = 0; String filename = null; string subdir = Path.Combine(TopLevelDir, "A"); Directory.CreateDirectory(subdir); int fileCount = _rnd.Next(10) + 10; for (int j = 0; j < fileCount; j++) { filename = Path.Combine(subdir, String.Format("FileToBeAdded-{0:D2}.txt", j)); TestUtilities.CreateAndFillFileText(filename, _rnd.Next(34000) + 5000); entriesAdded++; } using (ZipFile zip1 = new ZipFile()) { zip1.AddDirectory(subdir, Path.GetFileName(subdir)); zip1.Save(zipFileToCreate); } // Verify the files are in the zip Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), entriesAdded, "The Zip file has the wrong number of entries."); Assert.IsTrue(ZipFile.IsZipFile(zipFileToCreate), "The IsZipFile() method returned an unexpected result for an existing zip file."); Assert.IsTrue(ZipFile.IsZipFile(zipFileToCreate, true), "The IsZipFile() method returned an unexpected result for an existing zip file."); Assert.IsTrue(!ZipFile.IsZipFile(filename), "The IsZipFile() method returned an unexpected result for a extant file that is not a zip."); filename = Path.Combine(subdir, String.Format("ThisFileDoesNotExist.{0:D2}.txt", _rnd.Next(2000))); Assert.IsTrue(!ZipFile.IsZipFile(filename), "The IsZipFile() method returned an unexpected result for a non-existent file."); } [TestMethod] public void TestZip_IsZipFile_Stream() { string zipFileToCreate = Path.Combine(TopLevelDir, "TestZip_IsZipFile_Stream.zip"); int entriesAdded = 0; String filename = null; string subdir = Path.Combine(TopLevelDir, "A"); Directory.CreateDirectory(subdir); int fileCount = _rnd.Next(10) + 10; for (int j = 0; j < fileCount; j++) { filename = Path.Combine(subdir, String.Format("FileToBeAdded-{0:D2}.txt", j)); TestUtilities.CreateAndFillFileText(filename, _rnd.Next(34000) + 5000); entriesAdded++; } using (ZipFile zip1 = new ZipFile()) { zip1.AddDirectory(subdir, Path.GetFileName(subdir)); zip1.Save(zipFileToCreate); } // Verify the files are in the zip Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), entriesAdded, "The Zip file has the wrong number of entries."); using (FileStream input = File.OpenRead(zipFileToCreate)) { Assert.IsTrue(ZipFile.IsZipFile(input, false), "The IsZipFile() method returned an unexpected result for an existing zip file."); } using (FileStream input = File.OpenRead(zipFileToCreate)) { Assert.IsTrue(ZipFile.IsZipFile(input, true), "The IsZipFile() method returned an unexpected result for an existing zip file."); } } [TestMethod] public void ReadZip_DirectoryBitSetForEmptyDirectories() { string zipFileToCreate = Path.Combine(TopLevelDir, "ReadZip_DirectoryBitSetForEmptyDirectories.zip"); using (ZipFile zip1 = new ZipFile()) { zip1.AddDirectoryByName("Directory1"); // must retrieve with a trailing slash. ZipEntry e1 = zip1["Directory1/"]; Assert.AreNotEqual(null, e1); Assert.IsTrue(e1.IsDirectory, "The IsDirectory property was not set as expected."); zip1.AddDirectoryByName("Directory2"); zip1.AddEntry(Path.Combine("Directory2", "Readme.txt"), "This is the content"); Assert.IsTrue(zip1["Directory2/"].IsDirectory, "The IsDirectory property was not set as expected."); zip1.Save(zipFileToCreate); Assert.IsTrue(zip1["Directory1/"].IsDirectory, "The IsDirectory property was not set as expected."); } // read the zip and retrieve the dir entries again using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { Assert.IsTrue(zip2["Directory1/"].IsDirectory, "The IsDirectory property was not set as expected."); Assert.IsTrue(zip2["Directory2/"].IsDirectory, "The IsDirectory property was not set as expected."); } // now specify dir names with backslash using (ZipFile zip3 = ZipFile.Read(zipFileToCreate)) { Assert.IsTrue(zip3["Directory1\\"].IsDirectory, "The IsDirectory property was not set as expected."); Assert.IsTrue(zip3["Directory2\\"].IsDirectory, "The IsDirectory property was not set as expected."); Assert.IsNull(zip3["Directory1"]); Assert.IsNull(zip3["Directory2"]); } } [TestMethod] [ExpectedException(typeof(System.ArgumentException))] public void Create_DuplicateEntries_wi8047() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_DuplicateEntries_wi8047.zip"); string filename = "file.test"; string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); using (var zip = new ZipFile()) { int n = _rnd.Next(files.Length); zip.UpdateFile(files[n]).FileName = filename; int n2 = 0; while ((n2 = _rnd.Next(files.Length)) == n) ; zip.UpdateFile(files[n2]).FileName = filename; zip.Save(zipFileToCreate); } } [TestMethod] public void Create_RenameRemoveAndRenameAgain_wi8047() { string filename = "file.test"; string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); for (int m = 0; m < 2; m++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_RenameRemoveAndRenameAgain_wi8047-{0}.zip", m)); using (var zip = new ZipFile()) { // select a single file from the list int n = _rnd.Next(files.Length); // insert the selected file into the zip, and also rename it zip.UpdateFile(files[n]).FileName = filename; // conditionally save if (m > 0) zip.Save(zipFileToCreate); // remove the original file zip.RemoveEntry(zip[filename]); // select another file from the list, making sure it is not the same file int n2 = 0; while ((n2 = _rnd.Next(files.Length)) == n) ; // insert that other file and rename it zip.UpdateFile(files[n2]).FileName = filename; zip.Save(zipFileToCreate); } Assert.AreEqual(1, TestUtilities.CountEntries(zipFileToCreate), "Trial {0}: The Zip file has the wrong number of entries.", m); } } [TestMethod] public void Create_EmitTimestampOptions() { string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_EmitTimestampOptions-{0}-{1}.zip", j, k)); using (var zip = new ZipFile()) { if (j == 1) zip.EmitTimesInUnixFormatWhenSaving = false; else if (j == 2) zip.EmitTimesInUnixFormatWhenSaving = true; if (k == 1) zip.EmitTimesInWindowsFormatWhenSaving = false; else if (k == 2) zip.EmitTimesInWindowsFormatWhenSaving = true; zip.AddFiles(files, "files"); zip.Save(zipFileToCreate); } Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate), "The Zip file has the wrong number of entries."); using (var zip = ZipFile.Read(zipFileToCreate)) { for (int i = 0; i < zip.Entries.Count; i++) { if (j == 2) Assert.AreEqual(ZipEntryTimestamp.Unix, zip[i].Timestamp & ZipEntryTimestamp.Unix, "Missing Unix timestamp (cycle {0},{1}) (entry {2}).", j, k, i); else Assert.AreEqual(ZipEntryTimestamp.None, zip[i].Timestamp & ZipEntryTimestamp.Unix, "Unix timestamp is present when none is expected (cycle {0},{1}) (entry {2}).", j, k, i); if (k == 1) Assert.AreEqual(ZipEntryTimestamp.None, zip[i].Timestamp & ZipEntryTimestamp.Windows, "Windows timestamp is present when none is expected (cycle {0},{1}) (entry {2}).", j, k, i); else Assert.AreEqual(ZipEntryTimestamp.Windows, zip[i].Timestamp & ZipEntryTimestamp.Windows, "Missing Windows timestamp (cycle {0},{1}) (entry {2}).", j, k, i); Assert.AreEqual(ZipEntryTimestamp.DOS, zip[i].Timestamp & ZipEntryTimestamp.DOS, "Missing DOS timestamp (entry (cycle {0},{1}) (entry {2}).", j, k, i); } } } } } [TestMethod] public void Extract_AfterSaveNoDispose() { string zipFileToCreate = Path.Combine(TopLevelDir, "Extract_AfterSaveNoDispose.zip"); string inputString = ""; using (ZipFile zip1 = new ZipFile()) { MemoryStream ms1 = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(inputString)); zip1.AddEntry("woo\\Test.xml", ms1); zip1.Save(zipFileToCreate); MemoryStream ms2 = new MemoryStream(); zip1["Woo/Test.xml"].Extract(ms2); ms2.Seek(0, SeekOrigin.Begin); var sw1 = new StringWriter(); var w1 = new XTWFND(sw1); var d1 = new System.Xml.XmlDocument(); d1.Load(ms2); d1.Save(w1); var sw2 = new StringWriter(); var w2 = new XTWFND(sw2); var d2 = new System.Xml.XmlDocument(); d2.Load(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(inputString))); d2.Save(w2); Assert.AreEqual(sw2.ToString(), sw1.ToString(), "Unexpected value on extract ({0}).", sw1.ToString()); } } [TestMethod] public void Test_AddUpdateFileFromStream() { string[] passwords = { null, "Password", TestUtilities.GenerateRandomPassword(), "A" }; for (int k = 0; k < passwords.Length; k++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Test_AddUpdateFileFromStream-{0}.zip", k)); string[] inputStrings = new string[] { TestUtilities.LoremIpsum.Substring(_rnd.Next(5), 170 + _rnd.Next(25)), TestUtilities.LoremIpsum.Substring(100 + _rnd.Next(40), 180+ _rnd.Next(30)) }; // add entries to a zipfile. // use a password.(possibly null) using (ZipFile zip1 = new ZipFile()) { zip1.Password = passwords[k]; for (int i = 0; i < inputStrings.Length; i++) { zip1.AddEntry(String.Format("Lorem{0}.txt", i + 1), inputStrings[i]); } zip1.Save(zipFileToCreate); } using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { zip2["Lorem2.txt"].Password = passwords[k]; string output = StreamToStringUTF8(zip2["Lorem2.txt"].OpenReader()); Assert.AreEqual(output, inputStrings[1], "Trial {0}: Read entry 2 after create: Unexpected value on extract.", k); zip2["Lorem1.txt"].Password = passwords[k]; Stream s = zip2["Lorem1.txt"].OpenReader(); output = StreamToStringUTF8(s); Assert.AreEqual(output, inputStrings[0], "Trial {0}: Read entry 1 after create: Unexpected value on extract.", k); } // update an entry in the zipfile. For this pass, don't use a password. string UpdateString = "This is the updated content. It will replace the original content, added from a string."; using (ZipFile zip3 = ZipFile.Read(zipFileToCreate)) { var ms1 = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(UpdateString)); zip3.UpdateEntry("Lorem1.txt", ms1); zip3.Save(); } using (ZipFile zip4 = ZipFile.Read(zipFileToCreate)) { string output = StreamToStringUTF8(zip4["Lorem1.txt"].OpenReader()); Assert.AreEqual(output, UpdateString, "Trial {0}: Reading after update: Unexpected value on extract.", k); } } } [TestMethod] public void Test_AddEntry_String() { string[] passwords = { null, "Password", TestUtilities.GenerateRandomPassword(), "A" }; Encoding[] encodings = { Encoding.UTF8, Encoding.Default, Encoding.ASCII, Encoding.GetEncoding("Big5"), Encoding.GetEncoding("iso-8859-1"), Encoding.GetEncoding("Windows-1252"), }; string testBin = TestUtilities.GetTestBinDir(CurrentDir); string testStringsFile = Path.Combine(testBin, "Resources\\TestStrings.txt"); var contentStrings = File.ReadAllLines(testStringsFile); int[] successfulEncodings = new int[contentStrings.Length]; for (int a = 0; a < crypto.Length; a++) { for (int b = 0; b < passwords.Length; b++) { for (int c = 0; c < encodings.Length; c++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Test_AddEntry_String-{0}.{1}.{2}.zip", a, b, c)); Assert.IsFalse(File.Exists(zipFileToCreate), "The zip file '{0}' already exists.", zipFileToCreate); // add entries to a zipfile. // use a password.(possibly null) using (ZipFile zip1 = new ZipFile(zipFileToCreate)) { zip1.Comment = String.Format("Test zip file.\nEncryption({0}) Pw({1}) fileEncoding({2})", crypto[a].ToString(), passwords[b], encodings[c].ToString()); zip1.Encryption = crypto[a]; zip1.Password = passwords[b]; for (int d = 0; d < contentStrings.Length; d++) { string entryName = String.Format("File{0}.txt", d + 1); // add each string using the given encoding zip1.AddEntry(entryName, contentStrings[d], encodings[c]); } zip1.Save(); } // Verify the number of files in the zip Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), contentStrings.Length, "Incorrect number of entries in the zip file."); using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { zip2.Password = passwords[b]; for (int d = 0; d < contentStrings.Length; d++) { try { string entryName = String.Format("File{0}.txt", d + 1); //zip2[entryName].Password = Passwords[b]; // should not be necessary using (Stream s = zip2[entryName].OpenReader()) { using (var sr = new StreamReader(s, encodings[c])) { try { Assert.AreNotEqual(null, sr); string retrievedContent = sr.ReadLine(); if (IsEncodable(contentStrings[d], encodings[c])) { Assert.AreEqual(contentStrings[d], retrievedContent, "encryption({0}) pw({1}) encoding({2}), contentString({3}) file({4}): the content did not match.", a, b, c, d, entryName); successfulEncodings[d]++; } else { Assert.AreNotEqual(Encoding.UTF8, encodings[c]); Assert.AreNotEqual(contentStrings[d], retrievedContent, "encryption({0}) pw({1}) encoding({2}), contentString({3}) file({4}): the content should not match, but does.", a, b, c, d, entryName); } } catch (Exception exc1) { TestContext.WriteLine("Exception while reading: a({0}) b({1}) c({2}) d({3})", a, b, c, d); throw new Exception("broken", exc1); } } } } catch (Exception e1) { TestContext.WriteLine("Exception in OpenReader: Encryption({0}) pw({1}) c({2}) d({3})", crypto[a].ToString(), passwords[b], encodings[c].ToString(), d); throw new Exception("broken", e1); } } } } } } for (int d = 0; d < successfulEncodings.Length; d++) Assert.AreNotEqual(0, successfulEncodings[d], "Content item #{0} ({1}) was never encoded successfully.", d, contentStrings[d]); } [TestMethod] public void Test_AddDirectoryByName() { for (int n = 1; n <= 10; n++) { var dirsAdded = new System.Collections.Generic.List(); string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Test_AddDirectoryByName{0:N2}.zip", n)); using (ZipFile zip1 = new ZipFile()) { for (int i = 0; i < n; i++) { // create an arbitrary directory name, add it to the zip archive string dirName = TestUtilities.GenerateRandomName(24); zip1.AddDirectoryByName(dirName); dirsAdded.Add(dirName + "/"); } zip1.Save(zipFileToCreate); } int dirCount = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { foreach (var e in zip2) { TestContext.WriteLine("dir: {0}", e.FileName); Assert.IsTrue(dirsAdded.Contains(e.FileName), "Cannot find the expected entry"); Assert.IsTrue(e.IsDirectory); dirCount++; } } Assert.AreEqual(n, dirCount); } } [TestMethod] public void Test_AddDirectoryByName_Nested() { Directory.SetCurrentDirectory(TopLevelDir); var dirsAdded = new System.Collections.Generic.List(); string zipFileToCreate = Path.Combine(TopLevelDir, "Test_AddDirectoryByName_Nested.zip"); using (ZipFile zip1 = new ZipFile(zipFileToCreate)) { for (int n = 1; n <= 14; n++) { string DirName = n.ToString(); for (int i = 0; i < n; i++) { // create an arbitrary directory name, add it to the zip archive DirName = Path.Combine(DirName, TestUtilities.GenerateRandomAsciiString(11)); } zip1.AddDirectoryByName(DirName); dirsAdded.Add(DirName.Replace("\\", "/") + "/"); } zip1.Save(); } int dirCount = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { foreach (var e in zip2) { TestContext.WriteLine("dir: {0}", e.FileName); Assert.IsTrue(dirsAdded.Contains(e.FileName), "Cannot find the expected directory."); Assert.IsTrue(e.IsDirectory); dirCount++; } } Assert.AreEqual(dirsAdded.Count, dirCount); } [TestMethod] public void Test_AddDirectoryByName_WithFiles() { Directory.SetCurrentDirectory(TopLevelDir); var dirsAdded = new System.Collections.Generic.List(); string password = TestUtilities.GenerateRandomPassword(); string zipFileToCreate = Path.Combine(TopLevelDir, "Test_AddDirectoryByName_WithFiles.zip"); using (ZipFile zip1 = new ZipFile(zipFileToCreate)) { string dirName = null; int T = 3 + _rnd.Next(4); for (int n = 0; n < T; n++) { // nested directories dirName = (n == 0) ? "root" : Path.Combine(dirName, TestUtilities.GenerateRandomAsciiString(8)); zip1.AddDirectoryByName(dirName); dirsAdded.Add(dirName.Replace("\\", "/") + "/"); if (n % 2 == 0) zip1.Password = password; zip1.AddEntry(Path.Combine(dirName, new System.String((char)(n + 48), 3) + ".txt"), "Hello, Dolly!"); if (n % 2 == 0) zip1.Password = null; } zip1.Save(); } int entryCount = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { foreach (var e in zip2) { TestContext.WriteLine("e: {0}", e.FileName); if (e.IsDirectory) Assert.IsTrue(dirsAdded.Contains(e.FileName), "Cannot find the expected directory."); else { if ((entryCount - 1) % 4 == 0) e.Password = password; string output = StreamToStringUTF8(e.OpenReader()); Assert.AreEqual("Hello, Dolly!", output); } entryCount++; } } Assert.AreEqual(dirsAdded.Count * 2, entryCount); } int _progressEventCalls, _numSaving, _totalToSave, _cancelIndex, spCycles; bool _pb2Set, _pb1Set; Int64 maxBytesXferred = 0; void SaveProgress(object sender, SaveProgressEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Saving_Started: if (_txrx != null) { _txrx.Send("status saving started..."); _pb1Set = false; _numSaving= 1; } break; case ZipProgressEventType.Saving_BeforeWriteEntry: if (_txrx != null) { _txrx.Send("status Compressing " + e.CurrentEntry.FileName); spCycles = 0; if (!_pb1Set) { _txrx.Send("pb 1 max " + e.EntriesTotal); _pb1Set = true; } _totalToSave = e.EntriesTotal; _pb2Set = false; } break; case ZipProgressEventType.Saving_AfterWriteEntry: _progressEventCalls++; TestContext.WriteLine("{0}: {1} ({2}/{3})", e.EventType.ToString(), e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); if (_cancelIndex == _progressEventCalls) { e.Cancel = true; TestContext.WriteLine("Cancelling..."); } if (_txrx != null) { _txrx.Send("pb 1 step"); _numSaving++; } break; case ZipProgressEventType.Saving_EntryBytesRead: Assert.IsTrue(e.BytesTransferred <= e.TotalBytesToTransfer, "For entry {0}, BytesTransferred is greater than TotalBytesToTransfer: ({1} > {2})", e.CurrentEntry.FileName, e.BytesTransferred, e.TotalBytesToTransfer); maxBytesXferred = e.BytesTransferred; if (_txrx!=null) { spCycles++; if ((spCycles % 128) == 0) { if (!_pb2Set) { _txrx.Send("pb 2 max " + e.TotalBytesToTransfer); _pb2Set = true; } _txrx.Send(String.Format("status Saving entry {0}/{1} :: {2} :: {3}/{4}mb {5:N0}%", _numSaving, _totalToSave, e.CurrentEntry.FileName, e.BytesTransferred/(1024*1024), e.TotalBytesToTransfer/(1024*1024), ((double)e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))); _txrx.Send("pb 2 value " + e.BytesTransferred); } } break; case ZipProgressEventType.Saving_Completed: if (_txrx != null) { _txrx.Send("status Save completed"); _pb2Set = false; _txrx.Send("pb 1 max 1"); _txrx.Send("pb 1 value 1"); } break; default: break; } } bool _wasCanceled = false; void AddProgress(object sender, AddProgressEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Adding_AfterAddEntry: _progressEventCalls++; TestContext.WriteLine("{0}: {1}", e.EventType.ToString(), e.CurrentEntry.FileName); if (_cancelIndex == _progressEventCalls) { e.Cancel = true; TestContext.WriteLine("Cancelling..."); _wasCanceled = true; } break; } } void ExtractProgress(object sender, ExtractProgressEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Extracting_AfterExtractEntry: _progressEventCalls++; TestContext.WriteLine("Extracted: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesExtracted, e.EntriesTotal); // synthetic cancellation if (_cancelIndex == _progressEventCalls) { e.Cancel = true; TestContext.WriteLine("Cancelling..."); } break; case ZipProgressEventType.Extracting_EntryBytesWritten: maxBytesXferred = e.BytesTransferred; break; default: break; } } [TestMethod] public void Create_WithEvents() { string dirToZip = Path.Combine(TopLevelDir, "EventTest"); Directory.CreateDirectory(dirToZip); var randomizerSettings = new int[] { 6, 4, // dircount 7, 8, // filecount 10000, 15000 // filesize }; int subdirCount = 0; int entriesAdded = TestUtilities.GenerateFilesOneLevelDeep(TestContext, "Create_WithEvents", dirToZip, randomizerSettings, null, out subdirCount); for (int m = 0; m < 2; m++) { TestContext.WriteLine("======================================================="); TestContext.WriteLine("Trial {0}", m); string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_WithEvents-{0}.zip", m)); string targetDirectory = Path.Combine(TopLevelDir, "unpack" + m.ToString()); _progressEventCalls = 0; _cancelIndex = -1; // don't cancel this Save // create a zip file using (ZipFile zip1 = new ZipFile()) { zip1.SaveProgress += SaveProgress; zip1.Comment = "This is the comment on the zip archive."; zip1.AddDirectory(dirToZip, Path.GetFileName(dirToZip)); zip1.Save(zipFileToCreate); } if (m > 0) { // update the zip file using (ZipFile zip1 = ZipFile.Read(zipFileToCreate)) { zip1.SaveProgress += SaveProgress; zip1.Comment = "This is the comment on the zip archive."; zip1.AddEntry("ReadThis.txt", "This is the content for the readme file in the archive."); zip1.Save(); } entriesAdded++; } int expectedNumberOfProgressCalls = (entriesAdded + subdirCount) * (m + 1) + 1; Assert.AreEqual(expectedNumberOfProgressCalls, _progressEventCalls, "The number of progress events was unexpected ({0}!={1}).", expectedNumberOfProgressCalls, _progressEventCalls); _progressEventCalls = 0; _cancelIndex = -1; // don't cancel this Extract using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { zip2.ExtractProgress += ExtractProgress; zip2.ExtractAll(targetDirectory); } Assert.AreEqual(_progressEventCalls, entriesAdded + subdirCount + 1, "The number of Entries added is not equal to the number of entries extracted."); } } [TestMethod] public void CreateZip_AddDirectory_NoFilesInRoot_WI5893() { string zipFileToCreate = Path.Combine(TopLevelDir, "CreateZip_AddDirectory_NoFilesInRoot_WI5893.zip"); int i, j; int entries = 0; int subdirCount = _rnd.Next(5) + 5; for (i = 0; i < subdirCount; i++) { string subdir = Path.Combine(TopLevelDir, "DirectoryToZip.test." + i); Directory.CreateDirectory(subdir); int fileCount = _rnd.Next(13) + 7; for (j = 0; j < fileCount; j++) { String file = Path.Combine(subdir, String.Format("file{0:D3}.a", j)); TestUtilities.CreateAndFillFile(file, _rnd.Next(100) + 500); entries++; } } using (ZipFile zip = new ZipFile()) { zip.AddDirectory(TopLevelDir, string.Empty); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), entries, "The Zip file has the wrong number of entries."); } [TestMethod] public void Create_AddDirectory_NoFilesInRoot_WI5893a() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_AddDirectory_NoFilesInRoot_WI5893a.zip"); int i, j; int entries = 0; int subdirCount = _rnd.Next(4) + 4; for (i = 0; i < subdirCount; i++) { string subdir = Path.Combine(TopLevelDir, "DirectoryToZip.test." + i); Directory.CreateDirectory(subdir); int fileCount = _rnd.Next(16) + 8; for (j = 0; j < fileCount; j++) { String file = Path.Combine(subdir, String.Format("testfile{0:D3}.a", j)); TestUtilities.CreateAndFillFile(file, _rnd.Next(100) + 500); entries++; } } using (ZipFile zip = new ZipFile()) { zip.AddDirectory(TopLevelDir, string.Empty); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), entries, "The Zip file has the wrong number of entries."); } [TestMethod] public void Create_SaveCancellation() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_SaveCancellation.zip"); string dirToZip = Path.Combine(TopLevelDir, "EventTest"); Directory.CreateDirectory(dirToZip); int subdirCount = 0; int entriesAdded = TestUtilities.GenerateFilesOneLevelDeep(TestContext, "Create_SaveCancellation", dirToZip, null, out subdirCount); _cancelIndex = entriesAdded - _rnd.Next(entriesAdded / 2); _progressEventCalls = 0; using (ZipFile zip1 = new ZipFile()) { zip1.SaveProgress += SaveProgress; zip1.Comment = "The save on this zip archive will be canceled."; zip1.AddDirectory(dirToZip, Path.GetFileName(dirToZip)); zip1.Save(zipFileToCreate); } Assert.AreEqual(_progressEventCalls, _cancelIndex); Assert.IsFalse(File.Exists(zipFileToCreate), "The zip file save should have been canceled."); } [TestMethod] public void Create_AddCancellation_wi13371() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_AddCancellation.zip"); string dirToZip = Path.Combine(TopLevelDir, "EventTest"); Directory.CreateDirectory(dirToZip); int subdirCount = 0; int entriesAdded = TestUtilities.GenerateFilesOneLevelDeep(TestContext, "Create_AddCancellation", dirToZip, null, out subdirCount); _cancelIndex = entriesAdded - _rnd.Next(entriesAdded / 2); _progressEventCalls = 0; _wasCanceled = false; using (ZipFile zip1 = new ZipFile()) { zip1.AddProgress += AddProgress; zip1.Comment = "The add of files into this zip archive will be canceled."; zip1.AddDirectory(dirToZip, Path.GetFileName(dirToZip)); if (!_wasCanceled) zip1.Save(zipFileToCreate); } Assert.AreEqual(_progressEventCalls, _cancelIndex); Assert.IsFalse(File.Exists(zipFileToCreate), "The zip file should not exist."); } [TestMethod] public void ExtractAll_Cancellation() { string zipFileToCreate = Path.Combine(TopLevelDir, "ExtractAll_Cancellation.zip"); string targetDirectory = Path.Combine(TopLevelDir, "unpack"); string dirToZip = Path.Combine(TopLevelDir, "EventTest"); Directory.CreateDirectory(dirToZip); int subdirCount = 0; int entriesAdded = TestUtilities.GenerateFilesOneLevelDeep(TestContext, "ExtractAll_Cancellation", dirToZip, null, out subdirCount); using (ZipFile zip1 = new ZipFile()) { zip1.Comment = "The extract on this zip archive will be canceled."; zip1.AddDirectory(dirToZip, Path.GetFileName(dirToZip)); zip1.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); _cancelIndex = entriesAdded - _rnd.Next(entriesAdded / 2); _progressEventCalls = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { zip2.ExtractProgress += ExtractProgress; zip2.ExtractAll(targetDirectory); } Assert.AreEqual(_progressEventCalls, _cancelIndex); } [TestMethod] public void ExtractAll_WithPassword() { string zipFileToCreate = Path.Combine(TopLevelDir, "ExtractAll_WithPassword.zip"); string targetDirectory = Path.Combine(TopLevelDir, "unpack"); string dirToZip = Path.Combine(TopLevelDir, "dirToZip"); Directory.CreateDirectory(dirToZip); int subdirCount = 0; int entriesAdded = TestUtilities.GenerateFilesOneLevelDeep(TestContext, "ExtractAll_WithPassword", dirToZip, null, out subdirCount); string password = TestUtilities.GenerateRandomPassword(); using (ZipFile zip1 = new ZipFile()) { zip1.Password = password; zip1.Comment = "Brick walls are there for a reason: to let you show how badly you want your goal."; zip1.AddDirectory(dirToZip, Path.GetFileName(dirToZip)); zip1.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate, password); _cancelIndex = -1; // don't cancel this Extract _progressEventCalls = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { zip2.Password = password; zip2.ExtractProgress += ExtractProgress; zip2.ExtractAll(targetDirectory); } Assert.AreEqual(_progressEventCalls, entriesAdded + subdirCount + 1); } [TestMethod] public void Extract_ImplicitPassword() { for (int k = 0; k < compLevels.Length; k++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Extract_ImplicitPassword-{0}.zip", k)); Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); string[] passwords = new string[files.Length]; using (ZipFile zip1 = new ZipFile()) { zip1.Comment = "Brick walls are there for a reason: to let you show how badly you want your goal."; zip1.CompressionLevel = compLevels[k]; for (int i = 0; i < files.Length; i++) { passwords[i] = TestUtilities.GenerateRandomPassword(); zip1.Password = passwords[i]; TestContext.WriteLine(" Adding entry: {0} pw({1})", files[i], passwords[i]); zip1.AddFile(files[i], Path.GetFileName(dirToZip)); } zip1.Save(zipFileToCreate); } TestContext.WriteLine("\n"); // extract using the entry from the enumerator int nExtracted = 0; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate)) { foreach (ZipEntry e in zip2) { e.Password = passwords[nExtracted]; TestContext.WriteLine(" Extracting entry: {0} pw({1})", e.FileName, passwords[nExtracted]); e.Extract("unpack1"); nExtracted++; } } Assert.AreEqual(files.Length, nExtracted); // extract using the filename indexer nExtracted = 0; using (ZipFile zip3 = ZipFile.Read(zipFileToCreate)) { foreach (var name in zip3.EntryFileNames) { zip3.Password = passwords[nExtracted]; zip3[name].Extract("unpack2"); nExtracted++; } } Assert.AreEqual(files.Length, nExtracted); } } [TestMethod] public void Extract_MultiThreaded_wi6637() { int nConcurrentZipFiles = 5; for (int k = 0; k < 1; k++) { TestContext.WriteLine("\n-----------------------------\r\n{0}: Trial {1}...", DateTime.Now.ToString("HH:mm:ss"), k); Directory.SetCurrentDirectory(TopLevelDir); string[] zipFileToCreate = new string[nConcurrentZipFiles]; for (int m = 0; m < nConcurrentZipFiles; m++) { zipFileToCreate[m] = Path.Combine(TopLevelDir, String.Format("Extract_MultiThreaded-{0}-{1}.zip", k, m)); TestContext.WriteLine(" Creating file: {0}", zipFileToCreate[m]); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); TestContext.WriteLine("Zipping {0} files from dir '{1}'...", files.Length, dirToZip); using (ZipFile zip1 = new ZipFile()) { zip1.Comment = "Brick walls are there for a reason: to let you show how badly you want your goal."; for (int i = 0; i < files.Length; i++) { TestContext.WriteLine(" Adding entry: {0}", files[i]); zip1.AddFile(files[i], Path.GetFileName(dirToZip)); } zip1.Save(zipFileToCreate[m]); } TestContext.WriteLine("\n"); BasicVerifyZip(zipFileToCreate[m]); } // multi-thread extract foreach (string fileName in zipFileToCreate) { TestContext.WriteLine("queueing unzip for file: {0}", fileName); System.Threading.ThreadPool.QueueUserWorkItem(processZip, fileName); } while (completedEntries != zipFileToCreate.Length) System.Threading.Thread.Sleep(400); TestContext.WriteLine("done."); } } private int _completedEntries; private int completedEntries { get { return _completedEntries; } set { lock (this) { _completedEntries = value; } } } private void processZip(object o) { string fileName = o as string; string zDir = Path.Combine("extract", Path.GetFileNameWithoutExtension(fileName.ToString())); TestContext.WriteLine("extracting {0}...", fileName); using (var zFile = ZipFile.Read(fileName)) { zFile.ExtractAll(zDir, ExtractExistingFileAction.OverwriteSilently); } completedEntries++; } void OverwriteDecider(object sender, ExtractProgressEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite: // randomly choose whether to overwrite or not e.CurrentEntry.ExtractExistingFile = (_rnd.Next(2) == 0) ? ExtractExistingFileAction.DoNotOverwrite : ExtractExistingFileAction.OverwriteSilently; break; } } [TestMethod] public void Extract_ExistingFile() { string zipFileToCreate = Path.Combine(TopLevelDir, "Extract_ExistingFile.zip"); string sourceDir = CurrentDir; for (int i = 0; i < 3; i++) sourceDir = Path.GetDirectoryName(sourceDir); Directory.SetCurrentDirectory(TopLevelDir); string[] filenames = { Path.Combine(sourceDir, "Tools\\Zipit\\bin\\Debug\\Zipit.exe"), Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.dll"), Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.pdb"), Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.xml"), //Path.Combine(SourceDir, "AppNote.txt") }; int j = 0; using (ZipFile zip = new ZipFile()) { for (j = 0; j < filenames.Length; j++) zip.AddFile(filenames[j], ""); zip.Comment = "This is a Comment On the Archive"; zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), filenames.Length, "The zip file created has the wrong number of entries."); TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -"); TestContext.WriteLine("1. first extract - this should succeed"); var options = new ReadOptions { StatusMessageWriter = new StringWriter() }; using (ZipFile zip = ZipFile.Read(zipFileToCreate, options)) { for (j = 0; j < filenames.Length; j++) { var f = Path.GetFileName(filenames[j]); zip[f].Extract("unpack", ExtractExistingFileAction.Throw); } } TestContext.WriteLine(options.StatusMessageWriter.ToString()); TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -"); TestContext.WriteLine("2. extract again - DoNotOverwrite"); options.StatusMessageWriter = new StringWriter(); using (ZipFile zip = ZipFile.Read(zipFileToCreate, options)) { for (j = 0; j < filenames.Length; j++) { var f = Path.GetFileName(filenames[j]); zip[f].Extract("unpack", ExtractExistingFileAction.DoNotOverwrite); } } TestContext.WriteLine(options.StatusMessageWriter.ToString()); TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -"); TestContext.WriteLine("3. extract again - OverwriteSilently"); options.StatusMessageWriter = new StringWriter(); using (ZipFile zip = ZipFile.Read(zipFileToCreate, options)) { for (j = 0; j < filenames.Length; j++) { var f = Path.GetFileName(filenames[j]); zip[f].Extract("unpack", ExtractExistingFileAction.OverwriteSilently); } } TestContext.WriteLine(options.StatusMessageWriter.ToString()); TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -"); TestContext.WriteLine("4. extract again - InvokeExtractProgressEvent"); options.StatusMessageWriter = new StringWriter(); using (ZipFile zip = ZipFile.Read(zipFileToCreate, options)) { zip.ExtractProgress += OverwriteDecider; for (j = 0; j < filenames.Length; j++) { var f = Path.GetFileName(filenames[j]); zip[f].Extract("unpack", ExtractExistingFileAction.InvokeExtractProgressEvent); } } TestContext.WriteLine(options.StatusMessageWriter.ToString()); } [TestMethod] public void Extended_CheckZip1() { string[] dirNames = { "", Path.GetFileName(Path.GetRandomFileName()) }; string textToEncode = "Pay no attention to this: " + "We've read in the regular entry header, the extra field, and any " + "encryption header. The pointer in the file is now at the start of " + "the filedata, which is potentially compressed and encrypted. Just " + "ahead in the file, there are _CompressedFileDataSize bytes of data, " + "followed by potentially a non-zero length trailer, consisting of " + "optionally, some encryption stuff (10 byte MAC for AES), " + "and then the bit-3 trailer (16 or 24 bytes). "; for (int i = 0; i < crypto.Length; i++) { for (int j = 0; j < z64.Length; j++) { for (int k = 0; k < dirNames.Length; k++) { string zipFile = String.Format("Extended-CheckZip1-{0}.{1}.{2}.zip", i, j, k); string password = Path.GetRandomFileName(); TestContext.WriteLine("================================="); TestContext.WriteLine("Creating {0}...", Path.GetFileName(zipFile)); using (var zip = new ZipFile()) { zip.Comment = String.Format("Encryption={0} Zip64={1} pw={2}", crypto[i].ToString(), z64[j].ToString(), password); if (crypto[i] != EncryptionAlgorithm.None) { TestContext.WriteLine("Encryption({0}) Zip64({1}) pw({2})", crypto[i].ToString(), z64[j].ToString(), password); zip.Encryption = crypto[i]; zip.Password = password; } else TestContext.WriteLine("Encryption({0}) Zip64({1})", crypto[i].ToString(), z64[j].ToString()); zip.UseZip64WhenSaving = z64[j]; if (!String.IsNullOrEmpty(dirNames[k])) zip.AddDirectoryByName(dirNames[k]); zip.AddEntry(Path.Combine(dirNames[k], "File1.txt"), textToEncode); zip.Save(zipFile); } BasicVerifyZip(zipFile, password); TestContext.WriteLine("Checking zip..."); using (var sw = new StringWriter()) { bool result = ZipFile.CheckZip(zipFile, false, sw); Assert.IsTrue(result, "Zip ({0}) does not check OK", zipFile); var msgs = sw.ToString().Split('\n'); foreach (var msg in msgs) TestContext.WriteLine("{0}", msg); } } } } } [TestMethod] public void Extended_CheckZip2() { string textToEncode = "Pay no attention to this: " + "We've read in the regular entry header, the extra field, and any " + "encryption header. The pointer in the file is now at the start of " + "the filedata, which is potentially compressed and encrypted. Just " + "ahead in the file, there are _CompressedFileDataSize bytes of " + "data, followed by potentially a non-zero length trailer, " + "consisting of optionally, some encryption stuff (10 byte MAC for " + "AES), and then the bit-3 trailer (16 or 24 bytes). " + " " + "The encryption can be either PKZIP 2.0 (weak) encryption, or " + "WinZip-compatible AES encryption, which is considered to be " + "strong and for that reason is preferred. In the WinZip AES " + "option, there are two different keystrengths supported: 128 bits " + "and 256 bits. " + " " + "The extra field, which I mentioned previously, specifies " + "additional metadata about the entry, which is strictly-speaking, " + "optional. These data are things like high-resolution timestamps, " + "data sizes that exceed 2^^32, and other encryption " + "possibilities. In each case the library that reads a zip file " + "needs to be able to correctly deal with the various fields, " + "validating the values within them. " + " " + "Now, cross all that with the variety of usage patterns - creating a " + "zip, or reading, or extracting, or updating, or updating several " + "times. And also, remember that the metadata may change during " + "updates: an application can apply a password where none was used " + "previously, or it may wish to remove an entry from the zip entirely. " + " " + "The huge variety of combinations of possibilities is what makes " + "testing a zip library so challenging. " ; string testBin = TestUtilities.GetTestBinDir(CurrentDir); string fileToZip = Path.Combine(testBin, "Ionic.Zip.dll"); for (int i = 0; i < crypto.Length; i++) { for (int j = 0; j < z64.Length; j++) { string zipFile = String.Format("Extended-CheckZip2-{0}.{1}.zip", i, j); string password = Path.GetRandomFileName(); TestContext.WriteLine("================================="); TestContext.WriteLine("Creating {0}...", Path.GetFileName(zipFile)); string dir = Path.GetRandomFileName(); using (var zip = new ZipFile()) { zip.Comment = String.Format("Encryption={0} Zip64={1} pw={2}", crypto[i].ToString(), z64[j].ToString(), password); zip.Encryption = crypto[i]; if (crypto[i] != EncryptionAlgorithm.None) { TestContext.WriteLine("Encryption({0}) Zip64({1}) pw({2})", crypto[i].ToString(), z64[j].ToString(), password); zip.Password = password; } else TestContext.WriteLine("Encryption({0}) Zip64({1})", crypto[i].ToString(), z64[j].ToString()); zip.UseZip64WhenSaving = z64[j]; int N = _rnd.Next(11) + 5; for (int k = 0; k < N; k++) zip.AddDirectoryByName(Path.GetRandomFileName()); zip.AddEntry("File1.txt", textToEncode); zip.AddFile(fileToZip, Path.GetRandomFileName()); zip.Save(zipFile); } BasicVerifyZip(zipFile, password, false); TestContext.WriteLine("Checking zip..."); using (var sw = new StringWriter()) { bool result = ZipFile.CheckZip(zipFile, false, sw); Assert.IsTrue(result, "Zip ({0}) does not check OK", zipFile); var msgs = sw.ToString().Split('\n'); foreach (var msg in msgs) TestContext.WriteLine("{0}", msg); } TestContext.WriteLine("OK"); TestContext.WriteLine(""); } } } [TestMethod] [ExpectedException(typeof(System.ArgumentException))] public void Create_DuplicateNames_DifferentFolders_wi8982_flat() { _Internal_DuplicateNames_DifferentFolders_wi8982(true); } [TestMethod] public void Create_DuplicateNames_DifferentFolders_wi8982_PreserveHierarchy() { _Internal_DuplicateNames_DifferentFolders_wi8982(false); } public void _Internal_DuplicateNames_DifferentFolders_wi8982(bool flat) { Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); TestUtilities.GenerateFilesFlat(dirToZip, 3); string subdir = Path.Combine(dirToZip, "subdir1"); TestUtilities.GenerateFilesFlat(subdir, 2); for (int i = 0; i < 2; i++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_DuplicateNames_DifferentFolders.{0}.zip", i)); using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.Throw; if (i == 0) zip.AddDirectory(dirToZip, "fodder"); else { var files = Directory.GetFiles(dirToZip, "*.*", SearchOption.AllDirectories); if (flat) zip.AddFiles(files, "fodder"); else zip.AddFiles(files, true, "fodder"); } zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(5, TestUtilities.CountEntries(zipFileToCreate), "Trial {0}: The zip file created has the wrong number of entries.", i); } } [TestMethod] [ExpectedException(typeof(System.IO.IOException))] public void Create_ZipErrorAction_Throw() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_ZipErrorAction_Throw.zip"); Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); int n = _rnd.Next(files.Length); TestContext.WriteLine("Locking file {0}...", files[n]); using (Stream lockStream = new FileStream(files[n], FileMode.Open, FileAccess.Read, FileShare.None)) { using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.Throw; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } } } [TestMethod] public void Create_ZipErrorAction_Skip() { Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); // m is the number of files to lock for (int m = 1; m < 4; m++) { // k is the type of locking. 0 == whole file, 1 == range lock for (int k = 0; k < 2; k++) { TestContext.WriteLine("Trial {0}.{1}...", m, k); string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_ZipErrorAction_Skip-{0}-{1}.zip", m, k)); var locked = new Dictionary(); try { for (int i = 0; i < m; i++) { int n = 0; do { n = _rnd.Next(files.Length); } while (locked.ContainsKey(files[n])); TestContext.WriteLine(" Locking file {0}...", files[n]); FileStream lockStream = null; if (k == 0) { lockStream = new FileStream(files[n], FileMode.Open, FileAccess.Read, FileShare.None); } else { lockStream = new FileStream(files[n], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); int r = _rnd.Next((int)(lockStream.Length / 2)); int s = _rnd.Next((int)(lockStream.Length / 2)); lockStream.Lock(s, r); } locked.Add(files[n], lockStream); } using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.Skip; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } using (var zip = new ZipFile(zipFileToCreate)) { // Writing the info as a single block puts everything on the // same line, makes it unreadable. So we split the strings on // newline boundaries and write them individually. foreach (string s in zip.Info.Split('\r', '\n')) { Console.WriteLine("{0}", s); } } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length - m, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); } finally { foreach (String s in locked.Keys) { locked[s].Close(); } } TestContext.WriteLine(" ..."); System.Threading.Thread.Sleep(320); } } } private int _retryCount; void ErrorHandler_RetryAndEventuallySkip(object sender, ZipErrorEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Error_Saving: _retryCount++; if (_retryCount < 29) e.CurrentEntry.ZipErrorAction = ZipErrorAction.Retry; else e.CurrentEntry.ZipErrorAction = ZipErrorAction.Skip; break; } } void ErrorHandler_RetryAndEventuallyThrow(object sender, ZipErrorEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Error_Saving: _retryCount++; if (_retryCount < 29) e.CurrentEntry.ZipErrorAction = ZipErrorAction.Retry; else e.CurrentEntry.ZipErrorAction = ZipErrorAction.Throw; break; } } [TestMethod] public void Create_ZipErrorAction_RetryAndEventuallySkip() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_ZipErrorAction_RetryAndEventuallySkip.zip"); Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); int n = _rnd.Next(files.Length); TestContext.WriteLine("Locking file {0}...", files[n]); using (Stream lockStream = new FileStream(files[n], FileMode.Open, FileAccess.Read, FileShare.None)) { _retryCount = 0; using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.InvokeErrorEvent; zip.ZipError += ErrorHandler_RetryAndEventuallySkip; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length - 1, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); } [TestMethod] [ExpectedException(typeof(System.IO.IOException))] public void Create_ZipErrorAction_RetryAndEventuallyThrow() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_ZipErrorAction_RetryAndEventuallyThrow.zip"); Directory.SetCurrentDirectory(TopLevelDir); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); int n = _rnd.Next(files.Length); TestContext.WriteLine("Locking file {0}...", files[n]); using (Stream lockStream = new FileStream(files[n], FileMode.Open, FileAccess.Read, FileShare.None)) { _retryCount = 0; using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.InvokeErrorEvent; zip.ZipError += ErrorHandler_RetryAndEventuallyThrow; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } } } private void lockFile(object state) { Object[] a = (Object[])state; string filename = (string)a[0]; int duration = (int)a[1]; using (Stream lockStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None)) { // hold the lock for a specified period of time System.Threading.Thread.Sleep(duration); } } [TestMethod] public void Create_ZipErrorAction_RetryAndEventuallySucceed() { string zipFileToCreate = Path.Combine(TopLevelDir, "Create_ZipErrorAction_RetryAndEventuallySucceed.zip"); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); int n = _rnd.Next(files.Length); TestContext.WriteLine("Locking file {0}...", files[n]); // This will lock the file for 3 seconds, then release it. // The goal is to test whether the retry actually succeeds. System.Threading.ThreadPool.QueueUserWorkItem(lockFile, new Object[] { files[n], 3000 }); System.Threading.Thread.Sleep(200); _retryCount = 0; using (var zip = new ZipFile()) { zip.ZipErrorAction = ZipErrorAction.Retry; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); } [TestMethod] public void ParallelDeflateStream_Create() { string zipFileToCreate = Path.Combine(TopLevelDir, "ParallelDeflateStream_Create.zip"); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip, _rnd.Next(5) + 5, 128 * 1024 + _rnd.Next(20000)); using (var zip = new ZipFile()) { zip.ParallelDeflateThreshold = 65536; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); } [TestMethod] public void ParallelDeflateStream_Create_CompareSpeeds() { string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip, _rnd.Next(5) + 5, 2048 * 1024 + _rnd.Next(200000)); var ts = new TimeSpan[2]; // 2 sets of 2 cycles: first set is warmup, 2nd is timed. // Actually they're both timed but times for the 2nd set // overwrite the times for the 1st set. // Within a set, the first run is non-parallel, 2nd is timed parallel. for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("ParallelDeflateStream_Create.{0}.{1}.zip", i, j)); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); using (var zip = new ZipFile()) { if (j == 0) zip.ParallelDeflateThreshold = -1L; // disable parallel deflate else zip.ParallelDeflateThreshold = 128 * 1024; // threshold for parallel deflating zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } sw.Stop(); BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); ts[j] = sw.Elapsed; TestContext.WriteLine("Cycle {0},{1}, Timespan: {2}", i, j, ts[j]); } } Assert.IsTrue(ts[1] < ts[0], "Parallel deflating is NOT faster than single-threaded, for large files."); } [TestMethod] [ExpectedException(typeof(System.ArgumentOutOfRangeException))] public void ParallelDeflateStream_Create_InvalidThreshold() { string zipFileToCreate = Path.Combine(TopLevelDir, "ParallelDeflateStream_Create_InvalidThreshold.zip"); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip, _rnd.Next(5) + 5, 128 * 1024 + _rnd.Next(20000)); using (var zip = new ZipFile()) { zip.ParallelDeflateThreshold = 17129; zip.AddFiles(files, "fodder"); zip.Save(zipFileToCreate); } // not reached } [TestMethod] public void CompressTiff_Level9_wi8647() { string testBin = TestUtilities.GetTestBinDir(CurrentDir); string tifFile = Path.Combine(testBin, "Resources\\wi8647.tif"); Assert.IsTrue(File.Exists(tifFile), "tif file does not exist ({0})", tifFile); byte[] chk1 = TestUtilities.ComputeChecksum(tifFile); string chk1String = TestUtilities.CheckSumToString(chk1); for (int x = 0; x < (int)(Ionic.Zlib.CompressionLevel.BestCompression); x++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("CompressTiff_Level9-{0}.zip", x)); byte[] chk2 = null; using (var zip = new ZipFile()) { zip.CompressionLevel = (Ionic.Zlib.CompressionLevel)x; zip.AddFile(tifFile, "fodder"); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(1, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); TestContext.WriteLine("---------------Reading {0}...", zipFileToCreate); string extractDir = String.Format("extract{0}", x); using (ZipFile zip = ZipFile.Read(zipFileToCreate)) { var e = zip[0]; TestContext.WriteLine(" Entry: {0} c({1}) u({2})", e.FileName, e.CompressedSize, e.UncompressedSize); e.Extract(extractDir); string filename = Path.Combine(extractDir, e.FileName); chk2 = TestUtilities.ComputeChecksum(filename); } string chk2String = TestUtilities.CheckSumToString(chk2); Assert.AreEqual(chk1String, chk2String, "Cycle {0}, Checksums for ({1}) do not match.", x, tifFile); TestContext.WriteLine(" Cycle {0}: Checksums match ({1}).\n", x, chk1String); } } [TestMethod] [Timeout(30000)] // timeout in ms. 30000 = 30s public void AddDirectory_ReparsePoint_wi8617() { _Internal_AddDirectory_ReparsePoint_wi8617(1); } [TestMethod] [ExpectedException(typeof(Ionic.Zip.ZipException))] public void AddDirectory_ReparsePoint_wi8617_Error1() { _Internal_AddDirectory_ReparsePoint_wi8617(2); } [TestMethod] [ExpectedException(typeof(Ionic.Zip.ZipException))] public void AddDirectory_ReparsePoint_wi8617_Error2() { _Internal_AddDirectory_ReparsePoint_wi8617(0); } private void _Internal_AddDirectory_ReparsePoint_wi8617(int flavor) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("AddDirectory_ReparsePoint-{0}.zip", flavor)); string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var files = TestUtilities.GenerateFilesFlat(dirToZip); string junction = Path.Combine(dirToZip, "cycle"); Ionic.IO.JunctionPoint.Create(junction, dirToZip); using (var zip = new ZipFile()) { if (flavor == 1) zip.AddDirectoryWillTraverseReparsePoints = false; else if (flavor == 2) zip.AddDirectoryWillTraverseReparsePoints = true; // else nothing zip.AddDirectory(dirToZip, "fodder"); zip.Save(zipFileToCreate); } BasicVerifyZip(zipFileToCreate); Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate), "The zip file created has the wrong number of entries."); } [TestMethod] public void ContainsEntryTest() { string zipFileToCreate = "ContainsEntry.zip"; string dirToZip = "dirToZip"; var files = TestUtilities.GenerateFilesFlat(dirToZip); using (var zip = new ZipFile()) { zip.AddFiles(files); zip.Save(zipFileToCreate); } Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate)); using (var zip2 = ZipFile.Read(zipFileToCreate)) { for (int i=0; i < 28; i++) { int n = _rnd.Next(files.Length); TestContext.WriteLine("Checking {0}", files[n]); Assert.IsTrue(zip2.ContainsEntry(files[n]), "missing entry"); } } } [TestMethod] public void SortedSave() { var rtg = new RandomTextGenerator(); WriteDelegate writer = (name, stream) => { byte[] buffer = System.Text.Encoding.ASCII.GetBytes(rtg.Generate(_rnd.Next(2000) + 200)); stream.Write(buffer, 0, buffer.Length); }; int numEntries = _rnd.Next(256) + 48; // Two trials, one with sorted output, and the other with non-sorted output. for (int m = 0; m < 2; m++) { string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("SortedSave-{0}.zip", m)); using (var zip = new ZipFile()) { for (int i = 0; i < numEntries; i++) { // I need the randomness in the first part, to force the sort. string filename = String.Format("{0}-{1:000}.txt", TestUtilities.GenerateRandomAsciiString(6), i); zip.AddEntry(filename, writer); } zip.SortEntriesBeforeSaving = (m == 1); zip.Save(zipFileToCreate); } using (var zip = ZipFile.Read(zipFileToCreate)) { bool sorted = true; for (int i = 0; i < zip.Entries.Count - 1 && sorted; i++) { for (int j = i; j < zip.Entries.Count && sorted; j++) { if (String.Compare(zip[i].FileName, zip[j].FileName, StringComparison.OrdinalIgnoreCase) > 0) { sorted = false; } } } Assert.IsTrue((((m == 1) && sorted) || ((m == 0) && !sorted)), "Unexpected sort results"); } } } [TestMethod] public void DoubleSave_wi10735() { string zipFileToCreate1 = "DoubleSave.1.zip"; string zipFileToCreate2 = "DoubleSave.2.zip"; string dirToZip = "dirToZip"; var files = TestUtilities.GenerateFilesFlat(dirToZip); using (var zip = new ZipFile()) { zip.AddFiles(files); zip.Save(zipFileToCreate1); zip.Save(zipFileToCreate2); } } } }