context: // UpdateTests.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-August-05 16:52:59>
  //
  // ------------------------------------------------------------------
  //
  // This module defines tests for updating zip files via DotNetZip.
  //
  // ------------------------------------------------------------------
  
  using System;
  using System.Linq;
  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.Update
  {
      /// <summary>
      /// Summary description for UnitTest1
      /// </summary>
      [TestClass]
      public class UpdateTests : IonicTestClass
      {
          public UpdateTests() : base() { }
  
          [TestMethod]
          public void UpdateZip_AddNewDirectory()
          {
              string zipFileToCreate = Path.Combine(TopLevelDir, "UpdateZip_AddNewDirectory.zip");
  
              String CommentOnArchive = "BasicTests::UpdateZip_AddNewDirectory(): This archive will be overwritten.";
  
              string newComment = "This comment has been OVERWRITTEN." + DateTime.Now.ToString("G");
              string dirToZip = Path.Combine(TopLevelDir, "zipup");
  
              int i, j;
              int entries = 0;
              string subdir = null;
              String filename = null;
              int subdirCount = _rnd.Next(4) + 4;
              for (i = 0; i < subdirCount; i++)
              {
                  subdir = Path.Combine(dirToZip, "Directory." + i);
                  Directory.CreateDirectory(subdir);
  
                  int fileCount = _rnd.Next(3) + 3;
                  for (j = 0; j < fileCount; j++)
                  {
                      filename = Path.Combine(subdir, "file" + j + ".txt");
                      TestUtilities.CreateAndFillFileText(filename, _rnd.Next(12000) + 5000);
                      entries++;
                  }
              }
  
              using (ZipFile zip = new ZipFile())
              {
                  zip.AddDirectory(dirToZip);
                  zip.Comment = CommentOnArchive;
                  zip.Save(zipFileToCreate);
              }
  
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entries,
                      "The created Zip file has an unexpected number of entries.");
  
              BasicVerifyZip(zipFileToCreate);
  
              // Now create a new subdirectory and add that one
              subdir = Path.Combine(TopLevelDir, "NewSubDirectory");
              Directory.CreateDirectory(subdir);
  
              filename = Path.Combine(subdir, "newfile.txt");
              TestUtilities.CreateAndFillFileText(filename, _rnd.Next(12000) + 5000);
              entries++;
  
              using (ZipFile zip = new ZipFile(zipFileToCreate))
              {
                  zip.AddDirectory(subdir);
                  zip.Comment = newComment;
                  // this will add entries into the existing zip file
                  zip.Save();
              }
  
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entries,
                      "The overwritten Zip file has the wrong number of entries.");
  
              using (ZipFile readzip = new ZipFile(zipFileToCreate))
              {
                  Assert.AreEqual<string>(newComment,
                                          readzip.Comment,
                                          "The zip comment is incorrect.");
              }
          }
  
  
  
          [TestMethod]
          public void UpdateZip_ChangeMetadata_AES()
          {
              Directory.SetCurrentDirectory(TopLevelDir);
              string zipFileToCreate = Path.Combine(TopLevelDir, "UpdateZip_ChangeMetadata_AES.zip");
              string subdir = Path.Combine(TopLevelDir, "A");
              Directory.CreateDirectory(subdir);
  
              // create the files
              int numFilesToCreate = _rnd.Next(13) + 24;
              //int numFilesToCreate = 2;
              string filename = null;
              for (int j = 0; j < numFilesToCreate; j++)
              {
                  filename = Path.Combine(subdir, String.Format("file{0:D3}.txt", j));
                  TestUtilities.CreateAndFillFileText(filename, _rnd.Next(34000) + 5000);
                  //TestUtilities.CreateAndFillFileText(filename, 500);
              }
  
              string password = Path.GetRandomFileName() + Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
  
              using (var zip = new ZipFile())
              {
                  zip.Password = password;
                  zip.Encryption = EncryptionAlgorithm.WinZipAes256;
                  zip.AddFiles(Directory.GetFiles(subdir), "");
                  zip.Save(zipFileToCreate);
              }
  
              // Verify the correct number of files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), numFilesToCreate,
                                   "Fie! The updated Zip file has the wrong number of entries.");
  
              // test extract (and implicitly check CRCs, passwords, etc)
              VerifyZip(zipFileToCreate, password);
  
              byte[] buffer = new byte[_rnd.Next(10000) + 10000];
              _rnd.NextBytes(buffer);
              using (var zip = ZipFile.Read(zipFileToCreate))
              {
                  // modify the metadata for an entry
                  zip[0].LastModified = DateTime.Now - new TimeSpan(7 * 31, 0, 0);
                  zip.Password = password;
                  zip.Encryption = EncryptionAlgorithm.WinZipAes256;
                  zip.AddEntry(Path.GetRandomFileName(), buffer);
                  zip.Save();
              }
  
              // Verify the correct number of files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), numFilesToCreate + 1,
                                   "Fie! The updated Zip file has the wrong number of entries.");
  
              // test extract (and implicitly check CRCs, passwords, etc)
              VerifyZip(zipFileToCreate, password);
          }
  
  
  
          private void VerifyZip(string zipfile, string password)
          {
              Stream bitBucket = Stream.Null;
              TestContext.WriteLine("Checking file {0}", zipfile);
              using (ZipFile zip = ZipFile.Read(zipfile))
              {
                  zip.Password = password;
                  zip.BufferSize = 65536;
                  foreach (var s in zip.EntryFileNames)
                  {
                      TestContext.WriteLine("  Entry: {0}", s);
                      zip[s].Extract(bitBucket);
                  }
              }
              System.Threading.Thread.Sleep(0x500);
          }
  
  
  
          [TestMethod]
          public void UpdateZip_RemoveEntry_ByLastModTime()
          {
              // select the name of the zip file
              string zipFileToCreate = Path.Combine(TopLevelDir, "UpdateZip_RemoveEntry_ByLastModTime.zip");
              // create the subdirectory
              string subdir = Path.Combine(TopLevelDir, "A");
              Directory.CreateDirectory(subdir);
  
              // create the files
              int numFilesToCreate = _rnd.Next(13) + 24;
              string filename = null;
              int entriesAdded = 0;
              for (int j = 0; j < numFilesToCreate; j++)
              {
                  filename = Path.Combine(subdir, String.Format("file{0:D3}.txt", j));
                  TestUtilities.CreateAndFillFileText(filename, _rnd.Next(34000) + 5000);
                  entriesAdded++;
              }
  
              // Add the files to the zip, save the zip
              Directory.SetCurrentDirectory(TopLevelDir);
              int ix = 0;
              System.DateTime origDate = new System.DateTime(2007, 1, 15, 12, 1, 0);
              using (ZipFile zip1 = new ZipFile())
              {
                  String[] filenames = Directory.GetFiles("A");
                  foreach (String f in filenames)
                  {
                      ZipEntry e = zip1.AddFile(f, "");
                      e.LastModified = origDate + new TimeSpan(24 * 31 * ix, 0, 0);  // 31 days * number of entries
                      ix++;
                  }
                  zip1.Comment = "UpdateTests::UpdateZip_RemoveEntry_ByLastModTime(): This archive will soon be updated.";
                  zip1.Save(zipFileToCreate);
              }
  
              // Verify the files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entriesAdded,
                  "The Zip file has the wrong number of entries.");
  
  
              // selectively remove a few files in the zip archive
              var threshold = new TimeSpan(24 * 31 * (2 + _rnd.Next(ix - 12)), 0, 0);
              int numRemoved = 0;
              using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
              {
                  // We cannot remove the entry from the list, within the context of
                  // an enumeration of said list.
                  // So we add the doomed entry to a list to be removed
                  // later.
                  // pass 1: mark the entries for removal
                  var entriesToRemove = new List<ZipEntry>();
                  foreach (ZipEntry e in zip2)
                  {
                      if (e.LastModified < origDate + threshold)
                      {
                          entriesToRemove.Add(e);
                          numRemoved++;
                      }
                  }
  
                  // pass 2: actually remove the entry.
                  foreach (ZipEntry zombie in entriesToRemove)
                      zip2.RemoveEntry(zombie);
  
                  zip2.Comment = "UpdateTests::UpdateZip_RemoveEntry_ByLastModTime(): This archive has been updated.";
                  zip2.Save();
              }
  
              // Verify the correct number of files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entriesAdded - numRemoved,
                  "Fie! The updated Zip file has the wrong number of entries.");
  
              // verify that all entries in the archive are within the threshold
              using (ZipFile zip3 = ZipFile.Read(zipFileToCreate))
              {
                  foreach (ZipEntry e in zip3)
                      Assert.IsTrue((e.LastModified >= origDate + threshold),
                          "Merde. The updated Zip file has entries that lie outside the threshold.");
              }
  
          }
  
  
          [TestMethod]
          public void UpdateZip_RemoveEntry_ByFilename_WithPassword()
          {
              string password = "*!ookahoo";
              string filename = null;
              int entriesToBeAdded = 0;
              string repeatedLine = null;
              int j;
  
              // select the name of the zip file
              string zipFileToCreate = "ByFilename_WithPassword.zip";
              // create the subdirectory
              string subdir = Path.Combine(TopLevelDir, "A");
              Directory.CreateDirectory(subdir);
  
              // create a bunch of files, fill them with content
              int numFilesToCreate = _rnd.Next(13) + 24;
              for (j = 0; j < numFilesToCreate; j++)
              {
                  filename = String.Format("file{0:D3}.txt", j);
                  repeatedLine = String.Format("This line is repeated over and over and over in file {0}",
                                   filename);
                  TestUtilities.CreateAndFillFileText(Path.Combine(subdir, filename), repeatedLine, _rnd.Next(34000) + 5000);
                  entriesToBeAdded++;
              }
  
              // Add the files to the zip, save the zip
              Directory.SetCurrentDirectory(TopLevelDir);
              using (ZipFile zip1 = new ZipFile())
              {
                  String[] filenames = Directory.GetFiles("A");
                  zip1.Password = password;
                  zip1.AddFiles(filenames, "");
  
                  zip1.Comment = "UpdateTests::UpdateZip_RemoveEntry_ByFilename_WithPassword(): This archive will be updated.";
                  zip1.Save(zipFileToCreate);
              }
  
              // Verify the files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entriesToBeAdded,
                  "The Zip file has the wrong number of entries.");
  
  
              // selectively remove a few files in the zip archive
              var filesToRemove = new List<string>();
              int numToRemove = _rnd.Next(numFilesToCreate - 4) + 1;
              using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
              {
                  for (j = 0; j < numToRemove; j++)
                  {
                      // select a new, uniquely named file to create
                      do
                      {
                          filename = String.Format("file{0:D3}.txt", _rnd.Next(numFilesToCreate));
                      } while (filesToRemove.Contains(filename));
                      // add this file to the list
                      filesToRemove.Add(filename);
                      zip2.RemoveEntry(filename);
                  }
  
                  zip2.Comment = "This archive has been modified. Some files have been removed.";
                  zip2.Save();
              }
  
  
              // extract all files, verify none should have been removed,
              // and verify the contents of those that remain
              using (ZipFile zip3 = ZipFile.Read(zipFileToCreate))
              {
                  foreach (string s1 in zip3.EntryFileNames)
                  {
                      Assert.IsFalse(filesToRemove.Contains(s1), String.Format("File ({0}) was not expected.", s1));
  
                      zip3[s1].ExtractWithPassword("extract", password);
                      repeatedLine = String.Format("This line is repeated over and over and over in file {0}",
                                       s1);
  
                      // verify the content of the updated file.
                      var sr = new StreamReader(Path.Combine("extract", s1));
                      string sLine = sr.ReadLine();
                      sr.Close();
  
                      Assert.AreEqual<string>(repeatedLine, sLine,
                                  String.Format("The content of the originally added file ({0}) in the zip archive is incorrect.", s1));
  
                  }
              }
  
              // Verify the files are in the zip
              Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), entriesToBeAdded - filesToRemove.Count,
                  "The updated Zip file has the wrong number of entries.");
          }
  
  
  
          [TestMethod]
          public void UpdateZip_RenameEntry()
          {
              string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
              var files = TestUtilities.GenerateFilesFlat(dirToZip,
                                                          _rnd.Next(13) + 24,
                                                          42 * 1024 + _rnd.Next(20000));
  
              // Two passes:  in pass 1, simply rename the file;
              // in pass 2, rename it so that it has a directory.
              // This shouldn't matter, but we test it anyway.
              for (int k = 0; k < 2; k++)
              {
                  string zipFileToCreate = String.Format("UpdateZip_RenameEntry-{0}.zip", k);
                  TestContext.WriteLine("-----------------------------");
                  TestContext.WriteLine("{0}: Trial {1}, adding {2} files into '{3}'...",
                                        DateTime.Now.ToString("HH:mm:ss"),
                                        k,
                                        files.Length,
                                        zipFileToCreate);
  
                  // Add the files to the zip, save the zip
                  Directory.SetCurrentDirectory(TopLevelDir);
                  using (ZipFile zip1 = new ZipFile())
                  {
                      foreach (String f in files)
                          zip1.AddFile(f, "");
                      zip1.Comment = "This archive will be updated.";
                      zip1.Save(zipFileToCreate);
                  }
  
                  // Verify the number of files in the zip
                  Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate),
                                       files.Length,
                                       "the Zip file has the wrong number of entries.");
  
                  // selectively rename a few files in the zip archive
                  int renameCount = 0;
                  using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
                  {
                      var toRename = new List<ZipEntry>();
                      while (toRename.Count < 2)
                      {
                          foreach (ZipEntry e in zip2)
                          {
                              if (_rnd.Next(2) == 1)
                                  toRename.Add(e);
                          }
                      }
  
                      foreach (ZipEntry e in toRename)
                      {
                          var newname = (k == 0)
                              ? e.FileName + "-renamed"
                              : "renamed_files\\" + e.FileName;
  
                          TestContext.WriteLine("  renaming {0} to {1}", e.FileName, newname);
                          e.FileName = newname;
                          e.Comment = "renamed";
                          renameCount++;
                      }
  
                      zip2.Comment = String.Format("This archive has been modified. {0} files have been renamed.", renameCount);
                      zip2.Save();
                  }
  
  
                  // Extract all the files, verify that none have been removed,
                  // and verify the names of the entries.
                  int renameCount2 = 0;
                  using (ZipFile zip3 = ZipFile.Read(zipFileToCreate))
                  {
                      foreach (string s1 in zip3.EntryFileNames)
                      {
                          string dir = String.Format("extract{0}", k);
                          zip3[s1].Extract(dir);
                          string origFilename = Path.GetFileName((s1.Contains("renamed"))
                              ? s1.Replace("-renamed", "")
                              : s1);
  
                          if (zip3[s1].Comment == "renamed") renameCount2++;
                      }
                  }
  
                  Assert.AreEqual<int>(renameCount, renameCount2,
                      "The updated Zip file has the wrong number of renamed entries.");
  
                  Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate),
                                       files.Length,
                                       "Wrong number of entries.");
              }
          }
  
  
          [TestMethod]
          public void UpdateZip_UpdateEntryComment()
          {
              for (int k = 0; k < 2; k++)
              {
                  int j;
                  int entriesToBeAdded = 0;
                  string filename = null;
                  string repeatedLine = null;
  
                  // select the name of the zip file
                  string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("UpdateZip_UpdateEntryComment-{0}.zip", k));
  
                  // create the subdirectory
                  string subdir = Path.Combine(TopLevelDir, String.Format("A{0}", k));
                  Directory.CreateDirectory(subdir);
  
                  // create a bunch of files
                  //int numFilesToCreate = _rnd.Next(15) + 18;
                  int numFilesToCreate = _rnd.Next(5) + 3;
  
                  TestContext.WriteLine("\n-----------------------------\r\n{0}: Trial {1}, adding {2} files into '{3}'...",
                      DateTime.Now.ToString("HH:mm:ss"),
                      k,
                      numFilesToCreate,
                      zipFileToCreate);
  
                  for (j = 0; j < numFilesToCreate; j++)
                  {
                      filename = String.Format("file{0:D3}.txt", j);
                      repeatedLine = String.Format("This line is repeated over and over and over in file {0}",
                                       filename);
  
  
gt:                     int filesize = _rnd.Next(34000) + 800;