931 lines
35 KiB
C#
931 lines
35 KiB
C#
// TestUtilities.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-26 16:19:47>
|
|
//
|
|
// ------------------------------------------------------------------
|
|
//
|
|
// This module defines some utility classes used by the unit tests for
|
|
// DotNetZip.
|
|
//
|
|
// ------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Net;
|
|
using System.IO;
|
|
using Ionic.Zip;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
|
|
namespace Ionic.Zip.Tests.Utilities
|
|
{
|
|
class TestUtilities
|
|
{
|
|
static System.Random _rnd;
|
|
static string cdir;
|
|
static TestUtilities()
|
|
{
|
|
_rnd = new System.Random();
|
|
LoremIpsumWords = LoremIpsum.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
|
|
cdir = Directory.GetCurrentDirectory();
|
|
}
|
|
|
|
|
|
|
|
#region Test Init and Cleanup
|
|
|
|
internal static void Initialize(out string TopLevelDir)
|
|
{
|
|
if (cdir == null) cdir = Directory.GetCurrentDirectory();
|
|
|
|
TopLevelDir = TestUtilities.GenerateUniquePathname("tmp");
|
|
Directory.CreateDirectory(TopLevelDir);
|
|
Directory.SetCurrentDirectory(Path.GetDirectoryName(TopLevelDir));
|
|
}
|
|
|
|
internal static void Cleanup(string CurrentDir, List<String> FilesToRemove)
|
|
{
|
|
Assert.AreNotEqual<string>(Path.GetFileName(CurrentDir), "Temp", "at finish");
|
|
Directory.SetCurrentDirectory(CurrentDir);
|
|
IOException GotException = null;
|
|
int Tries = 0;
|
|
do
|
|
{
|
|
try
|
|
{
|
|
GotException = null;
|
|
foreach (string filename in FilesToRemove)
|
|
{
|
|
if (Directory.Exists(filename))
|
|
{
|
|
// turn off any ReadOnly attributes
|
|
ClearReadOnly(filename);
|
|
Directory.Delete(filename, true);
|
|
}
|
|
if (File.Exists(filename))
|
|
{
|
|
File.Delete(filename);
|
|
}
|
|
}
|
|
Tries++;
|
|
}
|
|
catch (IOException ioexc)
|
|
{
|
|
GotException = ioexc;
|
|
// use an backoff interval before retry
|
|
System.Threading.Thread.Sleep(200 * Tries);
|
|
}
|
|
} while ((GotException != null) && (Tries < 4));
|
|
if (GotException != null) throw GotException;
|
|
}
|
|
|
|
|
|
public static void ClearReadOnly(string dirname)
|
|
{
|
|
// don't traverse reparse points
|
|
if ((File.GetAttributes(dirname) & FileAttributes.ReparsePoint) != 0)
|
|
return;
|
|
|
|
foreach (var d in Directory.GetDirectories(dirname))
|
|
{
|
|
ClearReadOnly(d); // recurse
|
|
}
|
|
|
|
foreach (var f in Directory.GetFiles(dirname))
|
|
{
|
|
// clear ReadOnly and System attributes
|
|
var a = File.GetAttributes(f);
|
|
if ((a & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
|
{
|
|
a ^= FileAttributes.ReadOnly;
|
|
File.SetAttributes(f, a);
|
|
}
|
|
if ((a & FileAttributes.System) == FileAttributes.System)
|
|
{
|
|
a ^= FileAttributes.System;
|
|
File.SetAttributes(f, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Helper methods
|
|
|
|
internal static string TrimVolumeAndSwapSlashes(string pathName)
|
|
{
|
|
//return (((pathname[1] == ':') && (pathname[2] == '\\')) ? pathname.Substring(3) : pathname)
|
|
// .Replace('\\', '/');
|
|
if (String.IsNullOrEmpty(pathName)) return pathName;
|
|
if (pathName.Length < 2) return pathName.Replace('\\', '/');
|
|
return (((pathName[1] == ':') && (pathName[2] == '\\')) ? pathName.Substring(3) : pathName)
|
|
.Replace('\\', '/');
|
|
}
|
|
|
|
internal static DateTime RoundToEvenSecond(DateTime source)
|
|
{
|
|
// round to nearest second:
|
|
if ((source.Second % 2) == 1)
|
|
source += new TimeSpan(0, 0, 1);
|
|
|
|
DateTime dtRounded = new DateTime(source.Year, source.Month, source.Day, source.Hour, source.Minute, source.Second);
|
|
//if (source.Millisecond >= 500) dtRounded = dtRounded.AddSeconds(1);
|
|
return dtRounded;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// count occurrences of sample in string s.
|
|
/// </summary>
|
|
internal static int CountOccurrences(string s, string sample)
|
|
{
|
|
int nFound = 0;
|
|
int n = 0;
|
|
do
|
|
{
|
|
n = s.IndexOf(sample,n);
|
|
if (n>0) nFound++;
|
|
n++;
|
|
} while (n>0);
|
|
return nFound;
|
|
}
|
|
|
|
|
|
internal static void CreateAndFillFileText(string filename, Int64 size)
|
|
{
|
|
CreateAndFillFileText(filename, size, null);
|
|
}
|
|
|
|
|
|
internal static void CreateAndFillFileText(string filename,
|
|
Int64 size,
|
|
Action<Int64> update)
|
|
{
|
|
Int64 bytesRemaining = size;
|
|
|
|
if (size > 128 * 1024)
|
|
{
|
|
var rnd = new System.Random();
|
|
RandomTextGenerator rtg = new RandomTextGenerator();
|
|
int chunkSize = 48 * 1024;
|
|
int variationSize = 2 * 1024;
|
|
var newLinePair = Encoding.ASCII.GetBytes("\n\n");
|
|
int nCycles = 0;
|
|
// fill the file with text data, selecting large blocks at a time
|
|
var fodder = new byte[32][];
|
|
using (var fs = File.Create(filename))
|
|
{
|
|
do
|
|
{
|
|
int n = rnd.Next(fodder.Length);
|
|
if (fodder[n] == null)
|
|
{
|
|
string generatedText = rtg.Generate(chunkSize);
|
|
fodder[n] = Encoding.ASCII.GetBytes(generatedText);
|
|
}
|
|
|
|
var bytes = fodder[n];
|
|
int len = bytes.Length - rnd.Next(variationSize);
|
|
fs.Write(bytes,0,len);
|
|
bytesRemaining -= len;
|
|
fs.Write(newLinePair, 0, newLinePair.Length);
|
|
bytesRemaining -= newLinePair.Length;
|
|
nCycles++;
|
|
if ((nCycles % 1024) == 0)
|
|
{
|
|
if (update != null)
|
|
update(size - bytesRemaining);
|
|
}
|
|
} while (bytesRemaining > 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// fill the file with text data, selecting one word at a time
|
|
using (StreamWriter sw = File.CreateText(filename))
|
|
{
|
|
do
|
|
{
|
|
// pick a word at random
|
|
string selectedWord = LoremIpsumWords[_rnd.Next(LoremIpsumWords.Length)];
|
|
if (bytesRemaining < selectedWord.Length + 1)
|
|
{
|
|
sw.Write(selectedWord.Substring(0, (int)bytesRemaining));
|
|
bytesRemaining = 0;
|
|
}
|
|
else
|
|
{
|
|
sw.Write(selectedWord);
|
|
sw.Write(" ");
|
|
bytesRemaining -= (selectedWord.Length + 1);
|
|
}
|
|
if (update != null)
|
|
update(size - bytesRemaining);
|
|
|
|
} while (bytesRemaining > 0);
|
|
sw.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void CreateAndFillFileText(string Filename,
|
|
string Line,
|
|
Int64 size)
|
|
{
|
|
CreateAndFillFileText(Filename, Line, size, null);
|
|
}
|
|
|
|
|
|
internal static void CreateAndFillFileText(string Filename,
|
|
string Line,
|
|
Int64 size,
|
|
System.Action<Int64> update)
|
|
{
|
|
Int64 bytesRemaining = size;
|
|
// fill the file by repeatedly writing out the same line
|
|
using (StreamWriter sw = File.CreateText(Filename))
|
|
{
|
|
do
|
|
{
|
|
if (bytesRemaining < Line.Length + 2)
|
|
{
|
|
if (bytesRemaining == 1)
|
|
sw.Write(" ");
|
|
else if (bytesRemaining == 1)
|
|
sw.WriteLine();
|
|
else
|
|
sw.WriteLine(Line.Substring(0, (int)bytesRemaining - 2));
|
|
bytesRemaining = 0;
|
|
}
|
|
else
|
|
{
|
|
sw.WriteLine(Line);
|
|
bytesRemaining -= (Line.Length + 2);
|
|
}
|
|
if (update != null)
|
|
update(size - bytesRemaining);
|
|
} while (bytesRemaining > 0);
|
|
sw.Close();
|
|
}
|
|
}
|
|
|
|
internal static void CreateAndFillFileBinary(string Filename, Int64 size)
|
|
{
|
|
_CreateAndFillBinary(Filename, size, false, null);
|
|
}
|
|
|
|
internal static void CreateAndFillFileBinary(string Filename, Int64 size, System.Action<Int64> update)
|
|
{
|
|
_CreateAndFillBinary(Filename, size, false, update);
|
|
}
|
|
|
|
internal static void CreateAndFillFileBinaryZeroes(string Filename, Int64 size, System.Action<Int64> update)
|
|
{
|
|
_CreateAndFillBinary(Filename, size, true, update);
|
|
}
|
|
|
|
delegate void ProgressUpdate(System.Int64 bytesXferred);
|
|
|
|
private static void _CreateAndFillBinary(string filename, Int64 size, bool zeroes, System.Action<Int64> update)
|
|
{
|
|
Int64 bytesRemaining = size;
|
|
// fill with binary data
|
|
int sz = 65536 * 8;
|
|
if (size < sz) sz = (int)size;
|
|
byte[] buffer = new byte[sz];
|
|
int nCycles = 0;
|
|
using (var fileStream = File.Create(filename))
|
|
{
|
|
while (bytesRemaining > 0)
|
|
{
|
|
int sizeOfChunkToWrite = (bytesRemaining > buffer.Length) ? buffer.Length : (int)bytesRemaining;
|
|
if (!zeroes) _rnd.NextBytes(buffer);
|
|
fileStream.Write(buffer, 0, sizeOfChunkToWrite);
|
|
bytesRemaining -= sizeOfChunkToWrite;
|
|
nCycles++;
|
|
if (size > 1024*1024)
|
|
{
|
|
if ((nCycles % 256) == 0)
|
|
{
|
|
if (update != null)
|
|
update(size - bytesRemaining);
|
|
}
|
|
}
|
|
}
|
|
fileStream.Close();
|
|
}
|
|
}
|
|
|
|
|
|
internal static void CreateAndFillFile(string filename, Int64 size)
|
|
{
|
|
if (size == 0)
|
|
File.Create(filename);
|
|
else if (_rnd.Next(2) == 0)
|
|
CreateAndFillFileText(filename, size);
|
|
else
|
|
CreateAndFillFileBinary(filename, size);
|
|
}
|
|
|
|
internal enum FileFlavor
|
|
{
|
|
Text = 0, Binary = 1,
|
|
}
|
|
|
|
internal static void CreateAndFillFile(string filename,
|
|
Int64 size,
|
|
FileFlavor flavor)
|
|
{
|
|
if (size == 0)
|
|
File.Create(filename);
|
|
else if (flavor == FileFlavor.Text)
|
|
CreateAndFillFileText(filename, size);
|
|
else
|
|
CreateAndFillFileBinary(filename, size);
|
|
}
|
|
|
|
internal static string CreateUniqueFile(string extension, string ContainingDirectory)
|
|
{
|
|
//string nameOfFileToCreate = GenerateUniquePathname(extension, ContainingDirectory);
|
|
string nameOfFileToCreate = Path.Combine(ContainingDirectory, String.Format("{0}.{1}", Path.GetRandomFileName(), extension));
|
|
// create an empty file
|
|
using (var fs = File.Create(nameOfFileToCreate)) { }
|
|
return nameOfFileToCreate;
|
|
}
|
|
|
|
internal static string CreateUniqueFile(string extension)
|
|
{
|
|
return CreateUniqueFile(extension, null);
|
|
}
|
|
|
|
internal static string CreateUniqueFile(string extension, Int64 size)
|
|
{
|
|
return CreateUniqueFile(extension, null, size);
|
|
}
|
|
|
|
internal static string CreateUniqueFile(string extension, string ContainingDirectory, Int64 size)
|
|
{
|
|
//string fileToCreate = GenerateUniquePathname(extension, ContainingDirectory);
|
|
string nameOfFileToCreate = Path.Combine(ContainingDirectory, String.Format("{0}.{1}", Path.GetRandomFileName(), extension));
|
|
CreateAndFillFile(nameOfFileToCreate, size);
|
|
return nameOfFileToCreate;
|
|
}
|
|
|
|
static System.Reflection.Assembly _a = null;
|
|
private static System.Reflection.Assembly _MyAssembly
|
|
{
|
|
get
|
|
{
|
|
if (_a == null)
|
|
{
|
|
_a = System.Reflection.Assembly.GetExecutingAssembly();
|
|
}
|
|
return _a;
|
|
}
|
|
}
|
|
|
|
internal static string GenerateUniquePathname(string extension)
|
|
{
|
|
return GenerateUniquePathname(extension, null);
|
|
}
|
|
|
|
internal static string GenerateUniquePathname(string extension, string ContainingDirectory)
|
|
{
|
|
string candidate = null;
|
|
String AppName = _MyAssembly.GetName().Name;
|
|
|
|
string parentDir = (ContainingDirectory == null) ? System.Environment.GetEnvironmentVariable("TEMP") :
|
|
ContainingDirectory;
|
|
if (parentDir == null) return null;
|
|
|
|
int index = 0;
|
|
do
|
|
{
|
|
index++;
|
|
string Name = String.Format("{0}-{1}-{2}.{3}",
|
|
AppName, System.DateTime.Now.ToString("yyyyMMMdd-HHmmss"), index, extension);
|
|
candidate = Path.Combine(parentDir, Name);
|
|
} while (File.Exists(candidate));
|
|
|
|
// this file/path does not exist. It can now be created, as
|
|
// file or directory.
|
|
return candidate;
|
|
}
|
|
|
|
internal static int CountEntries(string zipfile)
|
|
{
|
|
int entries = 0;
|
|
using (ZipFile zip = ZipFile.Read(zipfile))
|
|
{
|
|
foreach (ZipEntry e in zip)
|
|
if (!e.IsDirectory) entries++;
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
|
|
internal static string GetCheckSumString(string filename)
|
|
{
|
|
return CheckSumToString(ComputeChecksum(filename));
|
|
}
|
|
|
|
internal static string CheckSumToString(byte[] checksum)
|
|
{
|
|
var sb = new System.Text.StringBuilder();
|
|
foreach (byte b in checksum)
|
|
sb.Append(b.ToString("x2").ToLower());
|
|
return sb.ToString();
|
|
}
|
|
|
|
internal static byte[] ComputeChecksum(string filename)
|
|
{
|
|
var _md5 = System.Security.Cryptography.MD5.Create();
|
|
using (FileStream fs = File.OpenRead(filename))
|
|
{
|
|
return _md5.ComputeHash(fs);
|
|
}
|
|
}
|
|
|
|
private static char GetOneRandomPasswordChar()
|
|
{
|
|
const int range = 126 - 33;
|
|
const int start = 33;
|
|
char x = '\0';
|
|
do
|
|
{
|
|
x = (char)(_rnd.Next(range) + start);
|
|
|
|
} while (x == '^' || x == '&' || x == '"' || x == '>' || x == '<');
|
|
return x;
|
|
}
|
|
|
|
internal static string GenerateRandomPassword()
|
|
{
|
|
int length = _rnd.Next(22) + 12;
|
|
return GenerateRandomPassword(length);
|
|
}
|
|
|
|
internal static string GenerateRandomPassword(int length)
|
|
{
|
|
char[] a = new char[length];
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
a[i] = GetOneRandomPasswordChar();
|
|
}
|
|
|
|
string result = new System.String(a);
|
|
return result;
|
|
}
|
|
|
|
|
|
public static string GenerateRandomAsciiString()
|
|
{
|
|
return GenerateRandomAsciiString(_rnd.Next(14));
|
|
}
|
|
|
|
public static string GenerateRandomName()
|
|
{
|
|
return
|
|
GenerateRandomUpperString(1) +
|
|
GenerateRandomLowerString(_rnd.Next(9) + 3);
|
|
}
|
|
|
|
public static string GenerateRandomName(int length)
|
|
{
|
|
return
|
|
GenerateRandomUpperString(1) +
|
|
GenerateRandomLowerString(length - 1);
|
|
}
|
|
|
|
public static string GenerateRandomAsciiString(int length)
|
|
{
|
|
return GenerateRandomAsciiStringImpl(length, 0);
|
|
}
|
|
|
|
public static string GenerateRandomUpperString()
|
|
{
|
|
return GenerateRandomAsciiStringImpl(_rnd.Next(10) + 3, 65);
|
|
}
|
|
|
|
public static string GenerateRandomUpperString(int length)
|
|
{
|
|
return GenerateRandomAsciiStringImpl(length, 65);
|
|
}
|
|
|
|
public static string GenerateRandomLowerString(int length)
|
|
{
|
|
return GenerateRandomAsciiStringImpl(length, 97);
|
|
}
|
|
|
|
public static string GenerateRandomLowerString()
|
|
{
|
|
return GenerateRandomAsciiStringImpl(_rnd.Next(9) + 4, 97);
|
|
}
|
|
|
|
private static string GenerateRandomAsciiStringImpl(int length, int delta)
|
|
{
|
|
bool WantRandomized = (delta == 0);
|
|
|
|
string result = "";
|
|
char[] a = new char[length];
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (WantRandomized)
|
|
delta = (_rnd.Next(2) == 0) ? 65 : 97;
|
|
a[i] = GetOneRandomAsciiChar(delta);
|
|
}
|
|
|
|
result = new System.String(a);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
private static char GetOneRandomAsciiChar(int delta)
|
|
{
|
|
// delta == 65 means uppercase
|
|
// delta == 97 means lowercase
|
|
return (char)(_rnd.Next(26) + delta);
|
|
}
|
|
|
|
public static char GetOneRandomLowercaseAsciiChar()
|
|
{
|
|
return (char)(_rnd.Next(26) + 97);
|
|
}
|
|
|
|
public static char GetOneRandomUppercaseAsciiChar()
|
|
{
|
|
return (char)(_rnd.Next(26) + 65);
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static int GenerateFilesOneLevelDeep(TestContext tc,
|
|
string testName,
|
|
string dirToZip,
|
|
Action<Int16, Int32> update,
|
|
out int subdirCount)
|
|
{
|
|
int[] settings = { 7, 6, 17, 23, 4000, 4000 }; // to randomly set dircount, filecount, and filesize
|
|
return GenerateFilesOneLevelDeep(tc, testName, dirToZip, settings, update, out subdirCount);
|
|
}
|
|
|
|
|
|
internal static int GenerateFilesOneLevelDeep(TestContext tc,
|
|
string testName,
|
|
string dirToZip,
|
|
int[] settings,
|
|
Action<Int16, Int32> update,
|
|
out int subdirCount)
|
|
{
|
|
int entriesAdded = 0;
|
|
String filename = null;
|
|
|
|
subdirCount = _rnd.Next(settings[0]) + settings[1];
|
|
if (update != null)
|
|
update(0, subdirCount);
|
|
tc.WriteLine("{0}: Creating {1} subdirs.", testName, subdirCount);
|
|
for (int i = 0; i < subdirCount; i++)
|
|
{
|
|
string subdir = Path.Combine(dirToZip, String.Format("dir{0:D4}", i));
|
|
Directory.CreateDirectory(subdir);
|
|
|
|
int filecount = _rnd.Next(settings[2]) + settings[3];
|
|
if (update != null)
|
|
update(1, filecount);
|
|
tc.WriteLine(":: Subdir {0}, Creating {1} files.", i, filecount);
|
|
for (int j = 0; j < filecount; j++)
|
|
{
|
|
int n = _rnd.Next(2);
|
|
filename = String.Format("file{0:D4}.{1}", j, (n == 0) ? "txt" : "bin");
|
|
TestUtilities.CreateAndFillFile(Path.Combine(subdir, filename),
|
|
_rnd.Next(settings[4]) + settings[5],
|
|
(FileFlavor)n);
|
|
entriesAdded++;
|
|
if (update != null)
|
|
update(3, j + 1);
|
|
}
|
|
if (update != null)
|
|
update(2, i + 1);
|
|
}
|
|
if (update != null)
|
|
update(4, entriesAdded);
|
|
return entriesAdded;
|
|
}
|
|
|
|
|
|
internal static string[] GenerateFilesFlat(string subdir)
|
|
{
|
|
return GenerateFilesFlat(subdir, 0);
|
|
}
|
|
|
|
internal static string[] GenerateFilesFlat(string subdir, int numFilesToCreate)
|
|
{
|
|
return GenerateFilesFlat(subdir, numFilesToCreate, 0, 0);
|
|
}
|
|
|
|
internal static string[] GenerateFilesFlat(string subdir, int numFilesToCreate, int size)
|
|
{
|
|
return GenerateFilesFlat(subdir, numFilesToCreate, size, size);
|
|
}
|
|
|
|
internal static string[] GenerateFilesFlat(string subdir,
|
|
int numFilesToCreate,
|
|
int lowSize, int highSize)
|
|
{
|
|
return GenerateFilesFlat(subdir, numFilesToCreate, lowSize, highSize,
|
|
null);
|
|
}
|
|
|
|
internal static string[] GenerateFilesFlat(string subdir,
|
|
int numFilesToCreate,
|
|
int lowSize,
|
|
int highSize,
|
|
Action<Int32,Int32,Int64> update)
|
|
{
|
|
if (numFilesToCreate==0)
|
|
numFilesToCreate = _rnd.Next(23) + 14;
|
|
|
|
if (lowSize == highSize && lowSize == 0)
|
|
{
|
|
lowSize = 5000;
|
|
highSize = 39000;
|
|
}
|
|
if (!Directory.Exists(subdir))
|
|
Directory.CreateDirectory(subdir);
|
|
|
|
int i = 0;
|
|
Action<Int64> byteUpdate = null;
|
|
if (update != null)
|
|
{
|
|
byteUpdate = new Action<Int64>( x => {
|
|
update(1,i,x);
|
|
});
|
|
}
|
|
|
|
string[] filesToZip = new string[numFilesToCreate];
|
|
for (i = 0; i < numFilesToCreate; i++)
|
|
{
|
|
filesToZip[i] = Path.Combine(subdir, String.Format("testfile{0:D3}.txt", i));
|
|
var sz = _rnd.Next(highSize - lowSize) + lowSize;
|
|
if (update != null)
|
|
update(0, i, sz);
|
|
TestUtilities.CreateAndFillFileText(filesToZip[i],
|
|
sz,
|
|
byteUpdate);
|
|
if (update != null) update(2,i,numFilesToCreate);
|
|
}
|
|
return filesToZip;
|
|
}
|
|
|
|
|
|
internal static string GetTestBinDir(string startingPoint)
|
|
{
|
|
return GetTestDependentDir(startingPoint, "Zip Tests\\bin\\Debug");
|
|
}
|
|
|
|
internal static string GetTestSrcDir(string startingPoint)
|
|
{
|
|
return GetTestDependentDir(startingPoint, "Zip Tests");
|
|
}
|
|
|
|
private static string GetTestDependentDir(string startingPoint, string subdir)
|
|
{
|
|
var location = startingPoint;
|
|
for (int i = 0; i < 3; i++)
|
|
location = Path.GetDirectoryName(location);
|
|
|
|
location = Path.Combine(location, subdir);
|
|
return location;
|
|
}
|
|
|
|
|
|
internal static Ionic.CopyData.Transceiver
|
|
StartProgressMonitor(string progressChannel, string title, string initialStatus)
|
|
{
|
|
string testBin = TestUtilities.GetTestBinDir(cdir);
|
|
string progressMonitorTool = Path.Combine(testBin, "Resources\\UnitTestProgressMonitor.exe");
|
|
string requiredDll = Path.Combine(testBin, "Resources\\Ionic.CopyData.dll");
|
|
Assert.IsTrue(File.Exists(progressMonitorTool), "progress monitor tool does not exist ({0})", progressMonitorTool);
|
|
Assert.IsTrue(File.Exists(requiredDll), "required DLL does not exist ({0})", requiredDll);
|
|
|
|
// start the progress monitor
|
|
string ignored;
|
|
//this.Exec(progressMonitorTool, String.Format("-channel {0}", progressChannel), false);
|
|
TestUtilities.Exec_NoContext(progressMonitorTool, String.Format("-channel {0}", progressChannel), false, out ignored);
|
|
|
|
var txrx = new Ionic.CopyData.Transceiver();
|
|
System.Threading.Thread.Sleep(1000);
|
|
txrx.Channel = progressChannel;
|
|
System.Threading.Thread.Sleep(450);
|
|
txrx.Send("test " + title);
|
|
System.Threading.Thread.Sleep(120);
|
|
txrx.Send("status " + initialStatus);
|
|
return txrx;
|
|
}
|
|
|
|
internal static int Exec_NoContext(string program, string args, out string output)
|
|
{
|
|
return Exec_NoContext(program, args, true, out output);
|
|
}
|
|
|
|
|
|
internal static int Exec_NoContext(string program, string args, bool waitForExit, out string output)
|
|
{
|
|
System.Diagnostics.Process p = new System.Diagnostics.Process
|
|
{
|
|
StartInfo =
|
|
{
|
|
FileName = program,
|
|
CreateNoWindow = true,
|
|
Arguments = args,
|
|
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
|
|
UseShellExecute = false,
|
|
}
|
|
|
|
};
|
|
|
|
if (waitForExit)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
p.StartInfo.RedirectStandardOutput = true;
|
|
p.StartInfo.RedirectStandardError = true;
|
|
// must read at least one of the stderr or stdout asynchronously,
|
|
// to avoid deadlock
|
|
Action<Object, System.Diagnostics.DataReceivedEventArgs> stdErrorRead = (o, e) =>
|
|
{
|
|
if (!String.IsNullOrEmpty(e.Data))
|
|
sb.Append(e.Data);
|
|
};
|
|
|
|
p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(stdErrorRead);
|
|
p.Start();
|
|
p.BeginErrorReadLine();
|
|
output = p.StandardOutput.ReadToEnd();
|
|
p.WaitForExit();
|
|
if (sb.Length > 0)
|
|
output += sb.ToString();
|
|
output = CleanWzzipOut(output); // just in case
|
|
return p.ExitCode;
|
|
}
|
|
else
|
|
{
|
|
p.Start();
|
|
}
|
|
output = "";
|
|
return 0;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The WinZip command-line tools emit dots and backspaces in the output.
|
|
/// For a large zip file, the output can be 1mb or more, of which 99% is
|
|
/// dots and backspaces. This method trims them from the output, making it
|
|
/// suitable for printing into the TestContext output.
|
|
/// </summary>
|
|
protected static string CleanWzzipOut(string txt)
|
|
{
|
|
int previousLength = 0;
|
|
int cycles = 0;
|
|
do
|
|
{
|
|
// wzzip.exe can generate long sequences of dots, followed by long
|
|
// sequences of backspaces. Don't want to replace two backspaces
|
|
// with the empty string, so replace a sequence of a non-backspace
|
|
// char followed by backspace with the empty string. Do it in
|
|
// cycles to handle those long sequences.
|
|
|
|
cycles++;
|
|
previousLength = txt.Length;
|
|
txt = Regex.Replace(txt, "[^\u0008]\u0008", "");
|
|
} while (previousLength != txt.Length && cycles < 80);
|
|
|
|
return txt;
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal static string LoremIpsum =
|
|
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer " +
|
|
"vulputate, nibh non rhoncus euismod, erat odio pellentesque lacus, sit " +
|
|
"amet convallis mi augue et odio. Phasellus cursus urna facilisis " +
|
|
"quam. Suspendisse nec metus et sapien scelerisque euismod. Nullam " +
|
|
"molestie sem quis nisl. Fusce pellentesque, ante sed semper egestas, sem " +
|
|
"nulla vestibulum nulla, quis sollicitudin leo lorem elementum " +
|
|
"wisi. Aliquam vestibulum nonummy orci. Sed in dolor sed enim ullamcorper " +
|
|
"accumsan. Duis vel nibh. Class aptent taciti sociosqu ad litora torquent " +
|
|
"per conubia nostra, per inceptos hymenaeos. Sed faucibus, enim sit amet " +
|
|
"venenatis laoreet, nisl elit posuere est, ut sollicitudin tortor velit " +
|
|
"ut ipsum. Aliquam erat volutpat. Phasellus tincidunt vehicula " +
|
|
"eros. Curabitur vitae erat. " +
|
|
"\n " +
|
|
"Quisque pharetra lacus quis sapien. Duis id est non wisi sagittis " +
|
|
"adipiscing. Nulla facilisi. Etiam quam erat, lobortis eu, facilisis nec, " +
|
|
"blandit hendrerit, metus. Fusce hendrerit. Nunc magna libero, " +
|
|
"sollicitudin non, vulputate non, ornare id, nulla. Suspendisse " +
|
|
"potenti. Nullam in mauris. Curabitur et nisl vel purus vehicula " +
|
|
"sodales. Class aptent taciti sociosqu ad litora torquent per conubia " +
|
|
"nostra, per inceptos hymenaeos. Cum sociis natoque penatibus et magnis " +
|
|
"dis parturient montes, nascetur ridiculus mus. Donec semper, arcu nec " +
|
|
"dignissim porta, eros odio tempus pede, et laoreet nibh arcu et " +
|
|
"nisl. Morbi pellentesque eleifend ante. Morbi dictum lorem non " +
|
|
"ante. Nullam et augue sit amet sapien varius mollis. " +
|
|
"\n " +
|
|
"Nulla erat lorem, fringilla eget, ultrices nec, dictum sed, " +
|
|
"sapien. Aliquam libero ligula, porttitor scelerisque, lobortis nec, " +
|
|
"dignissim eu, elit. Etiam feugiat, dui vitae laoreet faucibus, tellus " +
|
|
"urna molestie purus, sit amet pretium lorem pede in erat. Ut non libero " +
|
|
"et sapien porttitor eleifend. Vestibulum ante ipsum primis in faucibus " +
|
|
"orci luctus et ultrices posuere cubilia Curae; In at lorem et lacus " +
|
|
"feugiat iaculis. Nunc tempus eros nec arcu tristique egestas. Quisque " +
|
|
"metus arcu, pretium in, suscipit dictum, bibendum sit amet, " +
|
|
"mauris. Aliquam non urna. Suspendisse eget diam. Aliquam erat " +
|
|
"volutpat. In euismod aliquam lorem. Mauris dolor nisl, consectetuer sit " +
|
|
"amet, suscipit sodales, rutrum in, lorem. Nunc nec nisl. Nulla ante " +
|
|
"libero, aliquam porttitor, aliquet at, imperdiet sed, diam. Pellentesque " +
|
|
"tincidunt nisl et ipsum. Suspendisse purus urna, semper quis, laoreet " +
|
|
"in, vestibulum vel, arcu. Nunc elementum eros nec mauris. " +
|
|
"\n " +
|
|
"Vivamus congue pede at quam. Aliquam aliquam leo vel turpis. Ut " +
|
|
"commodo. Integer tincidunt sem a risus. Cras aliquam libero quis " +
|
|
"arcu. Integer posuere. Nulla malesuada, wisi ac elementum sollicitudin, " +
|
|
"libero libero molestie velit, eu faucibus est ante eu libero. Sed " +
|
|
"vestibulum, dolor ac ultricies consectetuer, tellus risus interdum diam, " +
|
|
"a imperdiet nibh eros eget mauris. Donec faucibus volutpat " +
|
|
"augue. Phasellus vitae arcu quis ipsum ultrices fermentum. Vivamus " +
|
|
"ultricies porta ligula. Nullam malesuada. Ut feugiat urna non " +
|
|
"turpis. Vivamus ipsum. Vivamus eleifend condimentum risus. Curabitur " +
|
|
"pede. Maecenas suscipit pretium tortor. Integer pellentesque. " +
|
|
"\n " +
|
|
"Mauris est. Aenean accumsan purus vitae ligula. Lorem ipsum dolor sit " +
|
|
"amet, consectetuer adipiscing elit. Nullam at mauris id turpis placerat " +
|
|
"accumsan. Sed pharetra metus ut ante. Aenean vel urna sit amet ante " +
|
|
"pretium dapibus. Sed nulla. Sed nonummy, lacus a suscipit semper, erat " +
|
|
"wisi convallis mi, et accumsan magna elit laoreet sem. Nam leo est, " +
|
|
"cursus ut, molestie ac, laoreet id, mauris. Suspendisse auctor nibh. " +
|
|
"\n";
|
|
|
|
static string[] LoremIpsumWords;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class Extensions
|
|
{
|
|
|
|
public static IEnumerable<string> SplitByWords(this string subject)
|
|
{
|
|
List<string> tokens = new List<string>();
|
|
Regex regex = new Regex(@"\s+");
|
|
tokens.AddRange(regex.Split(subject));
|
|
|
|
return tokens;
|
|
}
|
|
|
|
// Capitalize
|
|
public static string Capitalize(this string subject)
|
|
{
|
|
if (subject.Length < 2) return subject.ToUpper();
|
|
return subject.Substring(0, 1).ToUpper() +
|
|
subject.Substring(1);
|
|
}
|
|
|
|
// TrimPunctuation
|
|
public static string TrimPunctuation(this string subject)
|
|
{
|
|
while (subject.EndsWith(".") ||
|
|
subject.EndsWith(",") ||
|
|
subject.EndsWith(";") ||
|
|
subject.EndsWith("?") ||
|
|
subject.EndsWith("!"))
|
|
subject = subject.Substring(0, subject.Length - 1);
|
|
return subject;
|
|
}
|
|
}
|
|
|
|
|
|
}
|