// SplitArchives.cs // ------------------------------------------------------------------ // // Copyright (c) 2009-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-July-14 11:07:00> // // ------------------------------------------------------------------ // // This module defines tests for split (or 'spanned') archives. // // ------------------------------------------------------------------ // define REMOTE_FILESYSTEM in order to use a remote filesystem for storage of // the ZIP64 large archive (which can beb huge). Leave it undefined to simply // use the local TEMP directory. //#define REMOTE_FILESYSTEM using System; using System.IO; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Interop=System.Runtime.InteropServices; using Ionic.Zip.Tests.Utilities; namespace Ionic.Zip.Tests.Split { /// /// Summary description for ErrorTests /// [TestClass] public class Split : IonicTestClass { [Interop.DllImport("kernel32.dll", EntryPoint="CreateSymbolicLinkW", CharSet=Interop.CharSet.Unicode)] public static extern int CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); [TestMethod, Timeout(6 * 60*1000)] public void Spanned_Create() { string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); _txrx = TestUtilities.StartProgressMonitor("segmentedzip", "Segmented Zips", "Creating files"); _txrx.Send("pb 0 max 2"); int numFiles = _rnd.Next(10) + 8; int overflows = 0; string msg; _txrx.Send("pb 1 max " + numFiles); var update = new Action( (x,y,z) => { switch (x) { case 0: _txrx.Send(String.Format("pb 2 max {0}", ((int)z))); break; case 1: msg = String.Format("pb 2 value {0}", ((int)z)); _txrx.Send(msg); break; case 2: _txrx.Send("pb 1 step"); _txrx.Send("pb 2 value 0"); msg = String.Format("status created {0}/{1} files", y+1, ((int)z)); _txrx.Send(msg); break; } }); _txrx.Send("status creating " + numFiles + " files..."); string[] filesToZip; Dictionary checksums; CreateLargeFilesWithChecksums(dirToZip, numFiles, update, out filesToZip, out checksums); _txrx.Send("pb 0 step"); int[] segmentSizes = { 0, 64*1024, 128*1024, 512*1024, 1024*1024, 2*1024*1024, 8*1024*1024, 16*1024*1024, 1024*1024*1024 }; _txrx.Send("status zipping..."); _txrx.Send(String.Format("pb 1 max {0}", segmentSizes.Length)); System.EventHandler sp = (sender1, e1) => { switch (e1.EventType) { case ZipProgressEventType.Saving_Started: _txrx.Send(String.Format("pb 2 max {0}", filesToZip.Length)); _txrx.Send("pb 2 value 0"); break; case ZipProgressEventType.Saving_AfterWriteEntry: TestContext.WriteLine("Saved entry {0}, {1} bytes", e1.CurrentEntry.FileName, e1.CurrentEntry.UncompressedSize); _txrx.Send("pb 2 step"); break; } }; for (int m=0; m < segmentSizes.Length; m++) { string trialDir = String.Format("trial{0}", m); Directory.CreateDirectory(trialDir); string zipFileToCreate = Path.Combine(trialDir, String.Format("Archive-{0}.zip",m)); int maxSegSize = segmentSizes[m]; msg = String.Format("status trial {0}/{1} (max seg size {2}k)", m+1, segmentSizes.Length, maxSegSize/1024); _txrx.Send(msg); TestContext.WriteLine("======="); TestContext.WriteLine("Trial {0}", m); if (maxSegSize > 0) TestContext.WriteLine("Creating a segmented zip...segsize({0})", maxSegSize); else TestContext.WriteLine("Creating a regular zip..."); var sw = new StringWriter(); bool aok = false; try { using (var zip = new ZipFile()) { zip.StatusMessageTextWriter = sw; zip.BufferSize = 0x8000; zip.CodecBufferSize = 0x8000; zip.AddDirectory(dirToZip, "files"); zip.MaxOutputSegmentSize = maxSegSize; zip.SaveProgress += sp; zip.Save(zipFileToCreate); } aok = true; } catch (OverflowException) { TestContext.WriteLine("Overflow - too many segments..."); overflows++; } if (aok) { TestContext.WriteLine("{0}", sw.ToString()); // // If you want to see the diskNumber for each entry, // // uncomment the following: // TestContext.WriteLine("Checking info..."); // sw = new StringWriter(); // //string extractDir = String.Format("ex{0}", m); // using (var zip = ZipFile.Read(zipFileToCreate)) // { // zip.StatusMessageTextWriter = sw; // foreach (string s in zip.Info.Split('\r','\n')) // { // Console.WriteLine("{0}", s); // } // // // unnecessary - BasicVerify does this // //foreach (var e in zip) // //e.Extract(extractDir); // } // TestContext.WriteLine("{0}", sw.ToString()); TestContext.WriteLine("Extracting..."); string extractDir = BasicVerifyZip(zipFileToCreate); // also verify checksums VerifyChecksums(Path.Combine(extractDir, "files"), filesToZip, checksums); } _txrx.Send("pb 1 step"); } _txrx.Send("pb 0 step"); Assert.IsTrue(overflows < 3, "Too many overflows. Check the test."); } bool _pb1Set; bool _pb2Set; int _numExtracted; int _numFilesToExtract; int _nCycles; void ExtractProgress(object sender, ExtractProgressEventArgs e) { switch (e.EventType) { case ZipProgressEventType.Extracting_BeforeExtractEntry: if (!_pb1Set) { _txrx.Send(String.Format("pb 1 max {0}", _numFilesToExtract)); _pb1Set = true; } _pb2Set = false; _nCycles = 0; break; case ZipProgressEventType.Extracting_EntryBytesWritten: if (!_pb2Set) { _txrx.Send(String.Format("pb 2 max {0}", e.TotalBytesToTransfer)); _pb2Set = true; } // for performance, don't update the progress monitor every time. _nCycles++; if (_nCycles % 64 == 0) { _txrx.Send(String.Format("status Extracting entry {0}/{1} :: {2} :: {3}/{4}mb :: {5:N0}%", _numExtracted, _numFilesToExtract, e.CurrentEntry.FileName, e.BytesTransferred/(1024*1024), e.TotalBytesToTransfer/(1024*1024), ((double)e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer) )); string msg = String.Format("pb 2 value {0}", e.BytesTransferred); _txrx.Send(msg); } break; case ZipProgressEventType.Extracting_AfterExtractEntry: _numExtracted++; _txrx.Send("pb 1 step"); break; } } [TestMethod] [Timeout(90 * 60*1000)] public void Create_LargeSegmentedArchive() { // There was a claim that large archives (around or above // 1gb) did not work well with archive splitting. This test // covers that case. #if REMOTE_FILESYSTEM string parentDir = Path.Combine("t:\\tdir", Path.GetFileNameWithoutExtension(TopLevelDir)); _FilesToRemove.Add(parentDir); Directory.CreateDirectory(parentDir); string zipFileToCreate = Path.Combine(parentDir, "Create_LargeSegmentedArchive.zip"); #else string zipFileToCreate = Path.Combine(TopLevelDir, "Create_LargeSegmentedArchive.zip"); #endif TestContext.WriteLine("Creating file {0}", zipFileToCreate); // This file will "cache" the randomly generated text, so we // don't have to generate more than once. You know, for // speed. string cacheFile = Path.Combine(TopLevelDir, "cacheFile.txt"); // int maxSegSize = 4*1024*1024; // int sizeBase = 20 * 1024 * 1024; // int sizeRandom = 1 * 1024 * 1024; // int numFiles = 3; // int maxSegSize = 80*1024*1024; // int sizeBase = 320 * 1024 * 1024; // int sizeRandom = 20 * 1024 * 1024 ; // int numFiles = 5; int maxSegSize = 120*1024*1024; int sizeBase = 420 * 1024 * 1024; int sizeRandom = 20 * 1024 * 1024; int numFiles = _rnd.Next(5) + 11; TestContext.WriteLine("The zip will contain {0} files", numFiles); int numSaving= 0, totalToSave = 0, numSegs= 0; long sz = 0; // There are a bunch of Action's here. This test method originally // used ZipFile.AddEntry overload that accepts an opener/closer pair. // It conjured content for the files out of a RandomTextGenerator // stream. This worked, but was very very slow. So I took a new // approach to use a WriteDelegate, and still contrive the data, but // cache it for entries after the first one. This makes things go much // faster. // // But, when using the WriteDelegate, the SaveProgress events of // flavor ZipProgressEventType.Saving_EntryBytesRead do not get // called. Therefore the progress updates are done from within the // WriteDelegate itself. The SaveProgress events for SavingStarted, // BeforeWriteEntry, and AfterWriteEntry do get called. As a result // this method uses 2 delegates: one for writing and one for the // SaveProgress events. WriteDelegate writer = (name, stream) => { Stream input = null; Stream cache = null; try { // use a cahce file as the content. The entry // name will vary but we'll get the content for // each entry from the a single cache file. if (File.Exists(cacheFile)) { input = File.Open(cacheFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); // Make the file slightly shorter with each // successive entry, - just to shake things // up a little. Also seek forward a little. var fl = input.Length; input.SetLength(fl - _rnd.Next(sizeRandom/2) + 5201); input.Seek(_rnd.Next(sizeRandom/2), SeekOrigin.Begin); } else { sz = sizeBase + _rnd.Next(sizeRandom); input = new Ionic.Zip.Tests.Utilities.RandomTextInputStream((int)sz); cache = File.Create(cacheFile); } _txrx.Send(String.Format("pb 2 max {0}", sz)); _txrx.Send("pb 2 value 0"); var buffer = new byte[8192]; int n; Int64 totalWritten = 0; int nCycles = 0; using (input) { while ((n= input.Read(buffer,0, buffer.Length))>0) { stream.Write(buffer,0,n); if (cache!=null) cache.Write(buffer,0,n); totalWritten += n; // for performance, don't update the // progress monitor every time. nCycles++; if (nCycles % 312 == 0) { _txrx.Send(String.Format("pb 2 value {0}", totalWritten)); _txrx.Send(String.Format("status Saving entry {0}/{1} {2} :: {3}/{4}mb {5:N0}%", numSaving, totalToSave, name, totalWritten/(1024*1024), sz/(1024*1024), ((double)totalWritten) / (0.01 * sz))); } } } } finally { if (cache!=null) cache.Dispose(); } }; EventHandler sp = (sender1, e1) => { switch (e1.EventType) { case ZipProgressEventType.Saving_Started: numSaving= 0; break; case ZipProgressEventType.Saving_BeforeWriteEntry: _txrx.Send("test Large Segmented Zip"); _txrx.Send(String.Format("status saving {0}", e1.CurrentEntry.FileName)); totalToSave = e1.EntriesTotal; numSaving++; break; // case ZipProgressEventType.Saving_EntryBytesRead: // if (!_pb2Set) // { // _txrx.Send(String.Format("pb 2 max {0}", e1.TotalBytesToTransfer)); // _pb2Set = true; // } // _txrx.Send(String.Format("status Saving entry {0}/{1} {2} :: {3}/{4}mb {5:N0}%", // numSaving, totalToSave, // e1.CurrentEntry.FileName, // e1.BytesTransferred/(1024*1024), e1.TotalBytesToTransfer/(1024*1024), // ((double)e1.BytesTransferred) / (0.01 * e1.TotalBytesToTransfer))); // string msg = String.Format("pb 2 value {0}", e1.BytesTransferred); // _txrx.Send(msg); // break; case ZipProgressEventType.Saving_AfterWriteEntry: TestContext.WriteLine("Saved entry {0}, {1} bytes", e1.CurrentEntry.FileName, e1.CurrentEntry.UncompressedSize); _txrx.Send("pb 1 step"); _pb2Set = false; break; } }; _txrx = TestUtilities.StartProgressMonitor("largesegmentedzip", "Large Segmented ZIP", "Creating files"); _txrx.Send("bars 3"); _txrx.Send("pb 0 max 2"); _txrx.Send(String.Format("pb 1 max {0}", numFiles)); // build a large zip file out of thin air var sw = new StringWriter(); using (ZipFile zip = new ZipFile()) { zip.StatusMessageTextWriter = sw; zip.BufferSize = 256 * 1024; zip.CodecBufferSize = 128 * 1024; zip.MaxOutputSegmentSize = maxSegSize; zip.SaveProgress += sp; for (int i = 0; i < numFiles; i++) { string filename = TestUtilities.GetOneRandomUppercaseAsciiChar() + Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) + ".txt"; zip.AddEntry(filename, writer); } zip.Save(zipFileToCreate); numSegs = zip.NumberOfSegmentsForMostRecentSave; } #if REMOTE_FILESYSTEM if (((long)numSegs*maxSegSize) < (long)(1024*1024*1024L)) { _FilesToRemove.Remove(parentDir); Assert.IsTrue(false, "There were not enough segments in that zip. numsegs({0}) maxsize({1}).", numSegs, maxSegSize); } #endif _txrx.Send("status Verifying the zip ..."); _txrx.Send("pb 0 step"); _txrx.Send("pb 1 value 0"); _txrx.Send("pb 2 value 0"); ReadOptions options = new ReadOptions { StatusMessageWriter = new StringWriter() }; string extractDir = "verify"; int c = 0; while (Directory.Exists(extractDir + c)) c++; extractDir += c; using (ZipFile zip2 = ZipFile.Read(zipFileToCreate, options)) { _numFilesToExtract = zip2.Entries.Count; _numExtracted= 1; _pb1Set= false; zip2.ExtractProgress += ExtractProgress; zip2.ExtractAll(extractDir); } string status = options.StatusMessageWriter.ToString(); TestContext.WriteLine("status:"); foreach (string line in status.Split('\n')) TestContext.WriteLine(line); } [TestMethod] [ExpectedException(typeof(Ionic.Zip.ZipException))] public void Spanned_InvalidSegmentSize() { string zipFileToCreate = "InvalidSegmentSize.zip"; int segSize = 65536/3 + _rnd.Next(65536/2); using (var zip = new ZipFile()) { zip.MaxOutputSegmentSize = segSize; zip.Save(zipFileToCreate); } } string _fodderDir = null; /// /// Finds or creates and fills a cache directory of fodder files. /// /// the name of the cache directory String CreateSomeFiles() { string fodderName = "fodder"; if (_fodderDir != null) { CreateSymbolicLink(fodderName, _fodderDir, 1); return fodderName; } int baseNumFiles = 12; int baseSize = 0x100000; int numFilesToAdd = baseNumFiles + _rnd.Next(4); string tmpDir = System.Environment.GetEnvironmentVariable("TEMP"); var oldDirs = Directory.GetDirectories(tmpDir, "*.SplitArchives"); string fodderDir; foreach (var dir in oldDirs) { TestContext.WriteLine("Considering directory: {0}", dir); fodderDir = Path.Combine(dir, fodderName); if (!Directory.Exists(fodderDir)) { Directory.Delete(dir, true); } else { var fodderFiles = Directory.GetFiles(fodderDir, "*.txt"); if (fodderFiles.Length < baseNumFiles) { Directory.Delete(dir, true); } else { _fodderDir = fodderDir; CreateSymbolicLink(fodderName, _fodderDir, 1); return fodderName; } } } // upon reaching here, no directories exist that contain suitable // fodder for these tests. Create the directory, and a few // fodder files. string pname = Path.GetFileName(TestUtilities.GenerateUniquePathname("SplitArchives")); string cacheDir = Path.Combine(tmpDir, pname); Directory.CreateDirectory(cacheDir); fodderDir = Path.Combine(cacheDir, fodderName); Directory.CreateDirectory(fodderDir); for (int i=0; i < numFilesToAdd; i++) { int fileSize = baseSize + _rnd.Next(baseSize/2); string fileName = Path.Combine(fodderDir, string.Format("Pippo{0}.txt", i)); TestUtilities.CreateAndFillFileText(fileName, fileSize); } _fodderDir = fodderDir; CreateSymbolicLink(fodderName, _fodderDir, 1); return fodderName; } [TestMethod] [Timeout(5 * 60*1000)] // to protect against stuck file locks public void Spanned_Resave_wi13915() { TestContext.WriteLine("Creating fodder files... {0}", DateTime.Now.ToString("G")); var contentDir = CreateSomeFiles(); var filesToAdd = new List(Directory.GetFiles(contentDir)); int[] segSizes = { 128, 256, 512 }; // Three passes: // pass 1: save as regular, then resave as segmented. // pass 2: save as segmented, then resave as regular. // pass 3: save as segmented, then resave as another segmented archive. for (int m=0; m < 3; m++) { // for various segment sizes for (int k=0; k < segSizes.Length; k++) { string trialDir = String.Format("trial.{0}.{1}", m, k); Directory.CreateDirectory(trialDir); string zipFile1 = Path.Combine(trialDir, "InitialSave."+m+"."+k+".zip"); string zipFile2 = Path.Combine(trialDir, "Updated."+m+"."+k+".zip"); TestContext.WriteLine(""); TestContext.WriteLine("Creating zip... T({0},{1})...{2}", m, k, DateTime.Now.ToString("G")); using (var zip1 = new ZipFile()) { zip1.AddFiles(filesToAdd, ""); if (m!=0) zip1.MaxOutputSegmentSize = segSizes[k] * 1024; zip1.Save(zipFile1); } TestContext.WriteLine(""); TestContext.WriteLine("Re-saving..."); using (var zip2 = ZipFile.Read(zipFile1)) { if (m==0) zip2.MaxOutputSegmentSize = segSizes[k] * 1024; else if (m==2) zip2.MaxOutputSegmentSize = 1024 * (3 * segSizes[k])/2; zip2.Save(zipFile2); } TestContext.WriteLine(""); TestContext.WriteLine("Extracting..."); string extractDir = Path.Combine(trialDir,"extract"); Directory.CreateDirectory(extractDir); using (var zip3 = ZipFile.Read(zipFile2)) { foreach (var e in zip3) { TestContext.WriteLine(" {0}", e.FileName); e.Extract(extractDir); } } string[] filesUnzipped = Directory.GetFiles(extractDir); Assert.AreEqual(filesToAdd.Count, filesUnzipped.Length, "Incorrect number of files extracted."); } } } [TestMethod] [Timeout(5 * 60*1000)] // to protect against stuck file locks public void Spanned_WinZip_Unzip_wi13691() { if (!WinZipIsPresent) throw new Exception("winzip is not present"); TestContext.WriteLine("Creating fodder files... {0}", DateTime.Now.ToString("G")); var contentDir = CreateSomeFiles(); var filesToAdd = new List(Directory.GetFiles(contentDir)); int[] segSizes = { 128, 256, 512 }; // Save as segmented, then read/extract with winzip unzip // for various segment sizes. for (int k=0; k < segSizes.Length; k++) { string trialDir = String.Format("trial.{0}", k); Directory.CreateDirectory(trialDir); string zipFile1 = Path.Combine(trialDir, "InitialSave."+k+".zip"); TestContext.WriteLine(""); TestContext.WriteLine("Creating zip... T({0})...{1}", k, DateTime.Now.ToString("G")); using (var zip1 = new ZipFile()) { zip1.AddFiles(filesToAdd, ""); zip1.MaxOutputSegmentSize = segSizes[k] * 1024; zip1.Save(zipFile1); } TestContext.WriteLine(""); TestContext.WriteLine("Extracting..."); string extractDir = Path.Combine(trialDir,"extract"); Directory.CreateDirectory(extractDir); string args = String.Format("-d -yx {0} \"{1}\"", zipFile1, extractDir); this.Exec(wzunzip, args); string[] filesUnzipped = Directory.GetFiles(extractDir); Assert.AreEqual(filesToAdd.Count, filesUnzipped.Length, "Incorrect number of files extracted, trail {0}", k); } } #if INFOZIP_UNZIP_SUPPORTS_SPLIT_ARCHIVES [TestMethod] [Timeout(5 * 60*1000)] // to protect against stuck file locks public void Spanned_InfoZip_Unzip_wi13691() { if (!InfoZipIsPresent) throw new Exception("InfoZip is not present"); TestContext.WriteLine("Creating fodder files... {0}", DateTime.Now.ToString("G")); var contentDir = CreateSomeFiles(); var filesToAdd = new List(Directory.GetFiles(contentDir)); int[] segSizes = { 128, 256, 512 }; // Save as segmented, then read/extract with winzip unzip // for various segment sizes. for (int k=0; k < segSizes.Length; k++) { string trialDir = String.Format("trial.{0}", k); Directory.CreateDirectory(trialDir); string zipFile1 = Path.Combine(trialDir, "InitialSave."+k+".zip"); TestContext.WriteLine(""); TestContext.WriteLine("Creating zip... T({0})...{1}", k, DateTime.Now.ToString("G")); using (var zip1 = new ZipFile()) { zip1.AddFiles(filesToAdd, ""); zip1.MaxOutputSegmentSize = segSizes[k] * 1024; zip1.Save(zipFile1); } TestContext.WriteLine(""); TestContext.WriteLine("Extracting..."); string extractDir = Path.Combine(trialDir,"extract"); Directory.CreateDirectory(extractDir); string args = String.Format("{0} -d {1}", zipFile1, extractDir); this.Exec(infoZipUnzip, args); string[] filesUnzipped = Directory.GetFiles(extractDir); Assert.AreEqual(filesToAdd.Count, filesUnzipped.Length, "Incorrect number of files extracted, trail {0}", k); } } #endif [TestMethod] [Timeout(5 * 60*1000)] // to protect against stuck file locks public void Spanned_WinZip_Zip_wi13691() { if (!WinZipIsPresent) throw new Exception("WinZip is not present"); TestContext.WriteLine("Creating fodder files... {0}", DateTime.Now.ToString("G")); var contentDir = CreateSomeFiles(); var filesToAdd = new List(Directory.GetFiles(contentDir)); int[] segSizes = { 128, 256, 512 }; // Save as segmented, then read/extract with winzip unzip // for various segment sizes. for (int k=0; k < segSizes.Length; k++) { string trialDir = String.Format("trial.{0}", k); Directory.CreateDirectory(trialDir); string nameOfParts = Path.Combine(trialDir, "InitialSave."+k); string zipFile1 = nameOfParts + ".zip"; TestContext.WriteLine(""); TestContext.WriteLine("Creating zip... T({0})...{1}", k, DateTime.Now.ToString("G")); // with WinZip, must produce a segmented zip in two // steps: first create the regular zip, then split it. // step 1: create the regular zip string args = String.Format("-a -p -r -yx step1.zip \"{0}\"", contentDir); string wzzipOut = this.Exec(wzzip, args); // step 2: split the existing zip // "wzzip -ys[size] archivetosplit.zip nameofparts " args = String.Format("-ys{0} step1.zip {1}", segSizes[k], zipFile1 //nameOfParts ); wzzipOut = this.Exec(wzzip, args); TestContext.WriteLine(""); TestContext.WriteLine("Extracting..."); string extractDir = Path.Combine(trialDir,"extract"); Directory.CreateDirectory(extractDir); using (var zip1 = ZipFile.Read(zipFile1)) { foreach (var e in zip1) { TestContext.WriteLine(" {0}", e.FileName); e.Extract(extractDir); } } string[] filesUnzipped = Directory.GetFiles(extractDir); Assert.AreEqual(filesToAdd.Count, filesUnzipped.Length, "Incorrect number of files extracted, trail {0}", k); } } [TestMethod] [Timeout(5 * 60*1000)] // to protect against stuck file locks public void Spanned_InfoZip_Zip_wi13691() { if (!InfoZipIsPresent) throw new Exception("InfoZip is not present"); TestContext.WriteLine("Creating fodder files... {0}", DateTime.Now.ToString("G")); var contentDir = CreateSomeFiles(); var filesToAdd = new List(Directory.GetFiles(contentDir)); int[] segSizes = { 128, 256, 512 }; // Save as segmented, then read/extract with winzip unzip // for various segment sizes. for (int k=0; k < segSizes.Length; k++) { string trialDir = String.Format("trial.{0}", k); Directory.CreateDirectory(trialDir); string zipFile1 = Path.Combine(trialDir, "InitialSave."+k+".zip"); TestContext.WriteLine(""); TestContext.WriteLine("Creating zip... T({0})...{1}", k, DateTime.Now.ToString("G")); string args = String.Format("-s {0}k {1} -r {2}", segSizes[k], zipFile1, contentDir); this.Exec(infoZip, args); TestContext.WriteLine(""); TestContext.WriteLine("Extracting..."); string extractDir = Path.Combine(trialDir,"extract"); Directory.CreateDirectory(extractDir); using (var zip1 = ZipFile.Read(zipFile1)) { foreach (var e in zip1) { TestContext.WriteLine(" {0}", e.FileName); e.Extract(extractDir); } } string[] filesUnzipped = Directory.GetFiles(Path.Combine(extractDir, contentDir)); Assert.AreEqual(filesToAdd.Count, filesUnzipped.Length, "Incorrect number of files extracted, trail {0}", k); } } } }