Initial hack at moving over core tests

This commit is contained in:
Paul Betts
2014-07-28 10:53:28 +02:00
parent 9d239d85bd
commit 291c944d77
14 changed files with 1952 additions and 0 deletions

57
test/ContentTypeTests.cs Normal file
View File

@@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Squirrel.Core;
using Squirrel.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;
using Assert = Xunit.Assert;
namespace Squirrel.Tests.Core
{
public class ContentTypeTests
{
[Theory]
[InlineData("basic.xml", "basic-merged.xml")]
[InlineData("complex.xml", "complex-merged.xml")]
public void MergeContentTypes(string inputFileName, string expectedFileName)
{
var inputFile = IntegrationTestHelper.GetPath("fixtures", "content-types", inputFileName);
var expectedFile = IntegrationTestHelper.GetPath("fixtures", "content-types", expectedFileName);
var tempFile = Path.GetTempFileName() + ".xml";
var expected = new XmlDocument();
expected.Load(expectedFile);
var existingTypes = GetContentTypes(expected);
try
{
File.Copy(inputFile, tempFile);
var actual = new XmlDocument();
actual.Load(tempFile);
ContentType.Merge(actual);
var actualTypes = GetContentTypes(actual);
Assert.Equal(existingTypes, actualTypes);
}
finally
{
File.Delete(tempFile);
}
}
static IEnumerable<XmlElement> GetContentTypes(XmlNode doc)
{
var expectedTypesElement = doc.FirstChild.NextSibling;
return expectedTypesElement.ChildNodes.OfType<XmlElement>();
}
}
}

334
test/DeltaPackageTests.cs Normal file
View File

@@ -0,0 +1,334 @@
using System;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using NuGet;
using ReactiveUIMicro;
using Squirrel.Client;
using Squirrel.Core;
using Squirrel.Tests.TestHelpers;
using Xunit;
namespace Squirrel.Tests.Core
{
public class ApplyDeltaPackageTests : IEnableLogger
{
[Fact]
public void ApplyDeltaPackageSmokeTest()
{
var basePackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0-full.nupkg"));
var deltaPackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-delta.nupkg"));
var expectedPackageFile = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-full.nupkg");
var outFile = Path.GetTempFileName() + ".nupkg";
try {
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile);
var result = new ZipPackage(outFile);
var expected = new ZipPackage(expectedPackageFile);
result.Id.ShouldEqual(expected.Id);
result.Version.ShouldEqual(expected.Version);
this.Log().Info("Expected file list:");
expected.GetFiles().Select(x => x.Path).OrderBy(x => x).ForEach(x => this.Log().Info(x));
this.Log().Info("Actual file list:");
result.GetFiles().Select(x => x.Path).OrderBy(x => x).ForEach(x => this.Log().Info(x));
Enumerable.Zip(
expected.GetFiles().Select(x => x.Path).OrderBy(x => x),
result.GetFiles().Select(x => x.Path).OrderBy(x => x),
(e, a) => e == a
).All(x => x).ShouldBeTrue();
} finally {
if (File.Exists(outFile)) {
File.Delete(outFile);
}
}
}
[Fact]
public void ApplyMultipleDeltaPackagesGeneratesCorrectHash()
{
var firstRelease = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "SquirrelDesktopDemo-1.0.0-full.nupkg"), true);
var secondRelease = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "SquirrelDesktopDemo-1.1.0-full.nupkg"), true);
var thirdRelease = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "SquirrelDesktopDemo-1.2.0-full.nupkg"), true);
string installDir, releasesDir;
using(Utility.WithTempDirectory(out releasesDir))
using (IntegrationTestHelper.WithFakeAlreadyInstalledApp("InstalledSquirrelDesktopDemo-1.0.0.zip", out installDir)) {
var firstDelta = Path.Combine(releasesDir, "SquirrelDesktopDemo-1.1.0-delta.nupkg");
var secondDelta = Path.Combine(releasesDir, "SquirrelDesktopDemo-1.2.0-delta.nupkg");
new[] { firstRelease, secondRelease, thirdRelease }
.ForEach(file =>
{
var packageFile = file.ReleasePackageFile;
var fileName = Path.GetFileName(packageFile);
File.Copy(packageFile, Path.Combine(releasesDir, fileName));
});
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(firstRelease, secondRelease, firstDelta);
deltaBuilder.CreateDeltaPackage(secondRelease, thirdRelease, secondDelta);
ReleaseEntry.BuildReleasesFile(releasesDir);
var updateManager = new UpdateManager(
releasesDir, "ShimmerDesktopDemo", FrameworkVersion.Net40, installDir);
using (updateManager) {
var updateInfo = updateManager.CheckForUpdate().First();
Assert.Equal(2, updateInfo.ReleasesToApply.Count());
updateManager.DownloadReleases(updateInfo.ReleasesToApply).Wait();
updateManager.ApplyReleases(updateInfo).Wait();
}
string referenceDir;
using (IntegrationTestHelper.WithFakeAlreadyInstalledApp("InstalledSquirrelDesktopDemo-1.2.0.zip", out referenceDir)) {
var referenceVersion = Path.Combine(referenceDir, "ShimmerDesktopDemo", "app-1.2.0");
var installVersion = Path.Combine(installDir, "ShimmerDesktopDemo", "app-1.2.0");
var referenceFiles = Directory.GetFiles(referenceVersion);
var actualFiles = Directory.GetFiles(installVersion);
Assert.Equal(referenceFiles.Count(), actualFiles.Count());
var invalidFiles =
Enumerable.Zip(referenceFiles, actualFiles,
(reference, actual) => {
var refSha = Utility.CalculateFileSHA1(reference);
var actualSha = Utility.CalculateFileSHA1(actual);
return new { File = actual, Result = refSha == actualSha };
})
.Where(c => !c.Result).ToArray();
Assert.Empty(invalidFiles);
}
}
}
}
public class CreateDeltaPackageTests : IEnableLogger
{
[Fact]
public void CreateDeltaPackageIntegrationTest()
{
var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var baseFixture = new ReleasePackage(basePackage);
var fixture = new ReleasePackage(newPackage);
var tempFiles = Enumerable.Range(0, 3)
.Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg")
.ToArray();
try {
baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);
fixture.CreateReleasePackage(tempFiles[1], sourceDir);
(new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();
(new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);
var fullPkg = new ZipPackage(tempFiles[1]);
var deltaPkg = new ZipPackage(tempFiles[2]);
fullPkg.Id.ShouldEqual(deltaPkg.Id);
fullPkg.Version.CompareTo(deltaPkg.Version).ShouldEqual(0);
deltaPkg.GetFiles().Count().ShouldBeGreaterThan(0);
this.Log().Info("Files in delta package:");
deltaPkg.GetFiles().ForEach(x => this.Log().Info(x.Path));
// v1.1 adds a dependency on DotNetZip
deltaPkg.GetFiles()
.Any(x => x.Path.ToLowerInvariant().Contains("ionic.zip"))
.ShouldBeTrue();
// All the other files should be diffs and shasums
deltaPkg.GetFiles().Any(x => !x.Path.ToLowerInvariant().Contains("ionic.zip")).ShouldBeTrue();
deltaPkg.GetFiles()
.Where(x => !x.Path.ToLowerInvariant().Contains("ionic.zip"))
.All(x => x.Path.ToLowerInvariant().EndsWith("diff") || x.Path.ToLowerInvariant().EndsWith("shasum"))
.ShouldBeTrue();
// Every .diff file should have a shasum file
deltaPkg.GetFiles().Any(x => x.Path.ToLowerInvariant().EndsWith(".diff")).ShouldBeTrue();
deltaPkg.GetFiles()
.Where(x => x.Path.ToLowerInvariant().EndsWith(".diff"))
.ForEach(x => {
var lookingFor = x.Path.Replace(".diff", ".shasum");
this.Log().Info("Looking for corresponding shasum file: {0}", lookingFor);
deltaPkg.GetFiles().Any(y => y.Path == lookingFor).ShouldBeTrue();
});
// Delta packages should be smaller than the original!
var fileInfos = tempFiles.Select(x => new FileInfo(x)).ToArray();
this.Log().Info("Base Size: {0}, Current Size: {1}, Delta Size: {2}",
fileInfos[0].Length, fileInfos[1].Length, fileInfos[2].Length);
(fileInfos[2].Length - fileInfos[1].Length).ShouldBeLessThan(0);
} finally {
tempFiles.ForEach(File.Delete);
}
}
[Fact]
public void WhenBasePackageIsNewerThanNewPackageThrowException()
{
var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var baseFixture = new ReleasePackage(basePackage);
var fixture = new ReleasePackage(newPackage);
var tempFiles = Enumerable.Range(0, 3)
.Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg")
.ToArray();
try
{
baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);
fixture.CreateReleasePackage(tempFiles[1], sourceDir);
(new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();
(new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();
Assert.Throws<InvalidOperationException>(() =>
{
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);
});
}
finally
{
tempFiles.ForEach(File.Delete);
}
}
[Fact]
public void WhenBasePackageReleaseIsNullThrowsException()
{
var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var baseFixture = new ReleasePackage(basePackage);
var fixture = new ReleasePackage(newPackage);
var tempFile = Path.GetTempPath() + Guid.NewGuid() + ".nupkg";
try
{
Assert.Throws<ArgumentException>(() =>
{
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFile);
});
}
finally {
File.Delete(tempFile);
}
}
[Fact]
public void WhenBasePackageDoesNotExistThrowException()
{
var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var baseFixture = new ReleasePackage(basePackage);
var fixture = new ReleasePackage(newPackage);
var tempFiles = Enumerable.Range(0, 3)
.Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg")
.ToArray();
try
{
baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);
fixture.CreateReleasePackage(tempFiles[1], sourceDir);
(new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();
(new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();
// NOW WATCH AS THE FILE DISAPPEARS
File.Delete(baseFixture.ReleasePackageFile);
Assert.Throws<FileNotFoundException>(() =>
{
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);
});
}
finally
{
tempFiles.ForEach(File.Delete);
}
}
[Fact]
public void WhenNewPackageDoesNotExistThrowException()
{
var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var baseFixture = new ReleasePackage(basePackage);
var fixture = new ReleasePackage(newPackage);
var tempFiles = Enumerable.Range(0, 3)
.Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg")
.ToArray();
try
{
baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);
fixture.CreateReleasePackage(tempFiles[1], sourceDir);
(new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();
(new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();
// NOW WATCH AS THE FILE DISAPPEARS
File.Delete(fixture.ReleasePackageFile);
Assert.Throws<FileNotFoundException>(() =>
{
var deltaBuilder = new DeltaPackageBuilder();
deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);
});
}
finally
{
tempFiles.ForEach(File.Delete);
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Squirrel.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Squirrel.Tests")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f781bbe0-d19d-41aa-a78b-c689b1943094")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

197
test/ReleaseEntryTests.cs Normal file
View File

@@ -0,0 +1,197 @@
using System;
using System.IO;
using System.Linq;
using Moq;
using Squirrel.Core;
using Squirrel.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;
namespace Squirrel.Tests.Core
{
public class ReleaseEntryTests
{
[Theory]
[InlineData("94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502", "MyCoolApp-1.0.nupkg", 1004502)]
[InlineData("3a2eadd15dd984e4559f2b4d790ec8badaeb6a39 MyCoolApp-1.1.nupkg 1040561", "MyCoolApp-1.1.nupkg", 1040561)]
[InlineData("14db31d2647c6d2284882a2e101924a9c409ee67 MyCoolApp-1.1.nupkg.delta 80396", "MyCoolApp-1.1.nupkg.delta", 80396)]
public void ParseValidReleaseEntryLines(string releaseEntry, string fileName, long fileSize)
{
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
Assert.Equal(fileName, fixture.Filename);
Assert.Equal(fileSize, fixture.Filesize);
}
[Theory]
[InlineData("Squirrel.Core.1.0.0.0.nupkg", 4457, "75255cfd229a1ed1447abe1104f5635e69975d30")]
[InlineData("Squirrel.Core.1.1.0.0.nupkg", 15830, "9baf1dbacb09940086c8c62d9a9dbe69fe1f7593")]
public void GenerateFromFileTest(string name, long size, string sha1)
{
var path = IntegrationTestHelper.GetPath("fixtures", name);
using (var f = File.OpenRead(path)) {
var fixture = ReleaseEntry.GenerateFromFile(f, "dontcare");
Assert.Equal(size, fixture.Filesize);
Assert.Equal(sha1, fixture.SHA1.ToLowerInvariant());
}
}
[Theory]
[InlineData("94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502", 1, 0)]
[InlineData("3a2eadd15dd984e4559f2b4d790ec8badaeb6a39 MyCoolApp-1.1.nupkg 1040561", 1, 1)]
[InlineData("14db31d2647c6d2284882a2e101924a9c409ee67 MyCoolApp-1.1-delta.nupkg 80396", 1, 1)]
public void ParseVersionTest(string releaseEntry, int expectedMajor, int expectedMinor)
{
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
Assert.Equal(expectedMajor, fixture.Version.Major);
Assert.Equal(expectedMinor, fixture.Version.Minor);
}
[Fact]
public void CanParseGeneratedReleaseEntryAsString()
{
var path = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var entryAsString = ReleaseEntry.GenerateFromFile(path).EntryAsString;
ReleaseEntry.ParseReleaseEntry(entryAsString);
}
[Fact]
public void InvalidReleaseNotesThrowsException()
{
var path = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var fixture = ReleaseEntry.GenerateFromFile(path);
Assert.Throws<Exception>(() => fixture.GetReleaseNotes(IntegrationTestHelper.GetPath("fixtures")));
}
[Fact]
public void GetLatestReleaseWithNullCollectionReturnsNull()
{
Assert.Null(ReleaseEntry.GetPreviousRelease(
null, null, null));
}
[Fact]
public void GetLatestReleaseWithEmptyCollectionReturnsNull()
{
Assert.Null(ReleaseEntry.GetPreviousRelease(
Enumerable.Empty<ReleaseEntry>(), null, null));
}
[Fact]
public void WhenCurrentReleaseMatchesLastReleaseReturnNull()
{
var package = Mock.Of<IReleasePackage>(
r => r.InputPackageFile == "Espera-1.7.6-beta.nupkg");
var releaseEntries = new[] {
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
};
Assert.Null(ReleaseEntry.GetPreviousRelease(
releaseEntries, package, @"C:\temp\somefolder"));
}
[Fact]
public void WhenMultipleReleaseMatchesReturnEarlierResult()
{
var expected = new Version("1.7.5");
var package = Mock.Of<IReleasePackage>(
r => r.InputPackageFile == "Espera-1.7.6-beta.nupkg");
var releaseEntries = new[] {
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
};
var actual = ReleaseEntry.GetPreviousRelease(
releaseEntries,
package,
@"C:\temp\");
Assert.Equal(expected, actual.Version);
}
[Fact]
public void WhenMultipleReleasesFoundReturnPreviousVersion()
{
var expected = new Version("1.7.6");
var input = Mock.Of<IReleasePackage>(
r => r.InputPackageFile == "Espera-1.7.7-beta.nupkg");
var releaseEntries = new[] {
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
};
var actual = ReleaseEntry.GetPreviousRelease(
releaseEntries,
input,
@"C:\temp\");
Assert.Equal(expected, actual.Version);
}
[Fact]
public void WhenMultipleReleasesFoundInOtherOrderReturnPreviousVersion()
{
var expected = new Version("1.7.6");
var input = Mock.Of<IReleasePackage>(
r => r.InputPackageFile == "Espera-1.7.7-beta.nupkg");
var releaseEntries = new[] {
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
};
var actual = ReleaseEntry.GetPreviousRelease(
releaseEntries,
input,
@"C:\temp\");
Assert.Equal(expected, actual.Version);
}
[Fact]
public void WhenReleasesAreOutOfOrderSortByVersion()
{
var path = Path.GetTempFileName();
var firstVersion = new Version("1.0.0");
var secondVersion = new Version("1.1.0");
var thirdVersion = new Version("1.2.0");
var releaseEntries = new[] {
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-delta.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-delta.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg")),
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
};
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();
Assert.Equal(firstVersion, releases[0].Version);
Assert.Equal(secondVersion, releases[1].Version);
Assert.Equal(true, releases[1].IsDelta);
Assert.Equal(secondVersion, releases[2].Version);
Assert.Equal(false, releases[2].IsDelta);
Assert.Equal(thirdVersion, releases[3].Version);
Assert.Equal(true, releases[3].IsDelta);
Assert.Equal(thirdVersion, releases[4].Version);
Assert.Equal(false, releases[4].IsDelta);
}
[Fact]
public void ParseReleaseFileShouldReturnNothingForBlankFiles()
{
Assert.True(ReleaseEntry.ParseReleaseFile("").Count() == 0);
Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 0);
}
static string MockReleaseEntry(string name)
{
return string.Format("94689fede03fed7ab59c24337673a27837f0c3ec {0} 1004502", name);
}
}
}

392
test/ReleasePackageTests.cs Normal file
View File

@@ -0,0 +1,392 @@
using System.Runtime.Versioning;
using MarkdownSharp;
using NuGet;
using ReactiveUIMicro;
using Squirrel.Core;
using Squirrel.Tests.TestHelpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Xunit;
namespace Squirrel.Tests.Core
{
public class CreateReleasePackageTests : IEnableLogger
{
[Fact]
public void ReleasePackageIntegrationTest()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
var fixture = new ReleasePackage(inputPackage);
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
try {
fixture.CreateReleasePackage(outputPackage, sourceDir);
this.Log().Info("Resulting package is at {0}", outputPackage);
var pkg = new ZipPackage(outputPackage);
int refs = pkg.FrameworkAssemblies.Count();
this.Log().Info("Found {0} refs", refs);
refs.ShouldEqual(0);
this.Log().Info("Files in release package:");
List<IPackageFile> files = pkg.GetFiles().ToList();
files.ForEach(x => this.Log().Info(x.Path));
List<string> nonDesktopPaths = new[] {"sl", "winrt", "netcore", "win8", "windows8", "MonoAndroid", "MonoTouch", "MonoMac", "wp", }
.Select(x => @"lib\" + x)
.ToList();
files.Any(x => nonDesktopPaths.Any(y => x.Path.ToLowerInvariant().Contains(y.ToLowerInvariant()))).ShouldBeFalse();
files.Any(x => x.Path.ToLowerInvariant().Contains(@".xml")).ShouldBeFalse();
} finally {
File.Delete(outputPackage);
}
}
[Fact]
public void FindPackageInOurLocalPackageList()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
var fixture = ExposedObject.From(new ReleasePackage(inputPackage));
IPackage result = fixture.matchPackage(new LocalPackageRepository(sourceDir), "xunit", VersionUtility.ParseVersionSpec("[1.0,2.0]"));
result.Id.ShouldEqual("xunit");
result.Version.Version.Major.ShouldEqual(1);
result.Version.Version.Minor.ShouldEqual(9);
}
[Fact]
public void FindDependentPackagesForDummyPackage()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var fixture = ExposedObject.From(new ReleasePackage(inputPackage));
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
IEnumerable<IPackage> results = fixture.findAllDependentPackages(null, new LocalPackageRepository(sourceDir), null, null);
results.Count().ShouldBeGreaterThan(0);
}
[Fact]
public void CanLoadPackageWhichHasNoDependencies()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.NoDependencies.1.0.0.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
var fixture = new ReleasePackage(inputPackage);
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
try {
fixture.CreateReleasePackage(outputPackage, sourceDir);
}
finally {
File.Delete(outputPackage);
}
}
[Fact]
public void CanResolveMultipleLevelsOfDependencies()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "SampleUpdatingApp.1.0.0.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
var fixture = new ReleasePackage(inputPackage);
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
try {
fixture.CreateReleasePackage(outputPackage, sourceDir);
this.Log().Info("Resulting package is at {0}", outputPackage);
var pkg = new ZipPackage(outputPackage);
int refs = pkg.FrameworkAssemblies.Count();
this.Log().Info("Found {0} refs", refs);
refs.ShouldEqual(0);
this.Log().Info("Files in release package:");
pkg.GetFiles().ForEach(x => this.Log().Info(x.Path));
var filesToLookFor = new[] {
"System.Reactive.Core.dll",
"ReactiveUI.dll",
"MarkdownSharp.dll",
"SampleUpdatingApp.exe",
};
filesToLookFor.ForEach(name => {
this.Log().Info("Looking for {0}", name);
pkg.GetFiles().Any(y => y.Path.ToLowerInvariant().Contains(name.ToLowerInvariant())).ShouldBeTrue();
});
} finally {
File.Delete(outputPackage);
}
}
[Fact]
public void SpecFileMarkdownRenderingTest()
{
var dontcare = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg");
var inputSpec = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nuspec");
var fixture = new ReleasePackage(dontcare);
var targetFile = Path.GetTempFileName();
File.Copy(inputSpec, targetFile, true);
try {
var processor = new Func<string, string>(input =>
(new Markdown()).Transform(input));
// NB: For No Reason At All, renderReleaseNotesMarkdown is
// invulnerable to ExposedObject. Whyyyyyyyyy
var renderMinfo = fixture.GetType().GetMethod("renderReleaseNotesMarkdown",
BindingFlags.NonPublic | BindingFlags.Instance);
renderMinfo.Invoke(fixture, new object[] {targetFile, processor});
var doc = XDocument.Load(targetFile);
XNamespace ns = "http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd";
var relNotesElement = doc.Descendants(ns + "releaseNotes").First();
var htmlText = relNotesElement.Value;
this.Log().Info("HTML Text:\n{0}", htmlText);
htmlText.Contains("## Release Notes").ShouldBeFalse();
} finally {
File.Delete(targetFile);
}
}
[Fact]
public void UsesTheRightVersionOfADependencyWhenMultipleAreInPackages()
{
var outputPackage = Path.GetTempFileName() + ".nupkg";
string outputFile = null;
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "CaliburnMicroDemo.1.0.0.nupkg");
var wrongPackage = "Caliburn.Micro.1.4.1.nupkg";
var wrongPackagePath = IntegrationTestHelper.GetPath("fixtures", wrongPackage);
var rightPackage = "Caliburn.Micro.1.5.2.nupkg";
var rightPackagePath = IntegrationTestHelper.GetPath("fixtures", rightPackage);
try {
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
File.Copy(wrongPackagePath, Path.Combine(sourceDir, wrongPackage), true);
File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true);
var package = new ReleasePackage(inputPackage);
var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir);
var zipPackage = new ZipPackage(outputFileName);
var fileName = "Caliburn.Micro.dll";
var dependency = zipPackage.GetLibFiles()
.Where(f => f.Path.EndsWith(fileName))
.Single(f => f.TargetFramework == FrameworkTargetVersion.Net40);
outputFile = new FileInfo(Path.Combine(sourceDir, fileName)).FullName;
using (var of = File.Create(outputFile))
{
dependency.GetStream().CopyTo(of);
}
var assemblyName = AssemblyName.GetAssemblyName(outputFile);
Assert.Equal(1, assemblyName.Version.Major);
Assert.Equal(5, assemblyName.Version.Minor);
}
finally {
File.Delete(outputPackage);
File.Delete(outputFile);
}
}
[Fact]
public void DependentPackageNotFoundAndThrowsError()
{
string packagesDir;
// use empty packages folder
using (Utility.WithTempDirectory(out packagesDir)) {
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectDependsOnJsonDotNet.1.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
try {
var package = new ReleasePackage(inputPackage);
Assert.Throws<Exception>(() =>
package.CreateReleasePackage(outputPackage, packagesDir));
} finally {
File.Delete(outputPackage);
}
}
}
[Fact]
public void DependentPackageFoundAndIncludedInReleasePackage()
{
var packagesDir = IntegrationTestHelper.GetPath("..", "packages");
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectDependsOnJsonDotNet.1.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
try {
var package = new ReleasePackage(inputPackage);
package.CreateReleasePackage(outputPackage, packagesDir);
Assert.True(File.Exists(outputPackage));
} finally {
File.Delete(outputPackage);
}
}
[Fact]
public void WhenInputPackageTargetsMultipleFrameworksCrashHard()
{
var packagesDir = IntegrationTestHelper.GetPath("..", "packages");
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectTargetingMultiplePlatforms.1.0.0.0.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
var package = new ReleasePackage(inputPackage);
Assert.Throws<InvalidOperationException>(() => {
package.CreateReleasePackage(outputPackage, packagesDir);
});
}
[Fact(Skip="TODO")]
public void DependentLocalPackageNotFoundAndThrowsError()
{
// copy ProjectDependsOnOtherProject to a temp folder
// create a release package using it
// should throw an exception indicating it can't find TheOtherProjectItDependsOn.1.0.nupkg
}
[Fact(Skip = "TODO")]
public void DependentLocalPackageFoundAndIncludedInReleasePackage()
{
// copy ProjectDependsOnOtherProject and TheOtherProjectItDependsOn to a temp folder
// create a release package using it
// should contain TheOtherProjectItDependsOn.dll
// XXX: what about scenario where it is in another folder?
}
[Fact]
public void ContentFilesAreIncludedInCreatedPackage()
{
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectWithContent.1.0.0.0-beta.nupkg");
var outputPackage = Path.GetTempFileName() + ".nupkg";
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
var fixture = new ReleasePackage(inputPackage);
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
try
{
fixture.CreateReleasePackage(outputPackage, sourceDir);
this.Log().Info("Resulting package is at {0}", outputPackage);
var pkg = new ZipPackage(outputPackage);
int refs = pkg.FrameworkAssemblies.Count();
this.Log().Info("Found {0} refs", refs);
refs.ShouldEqual(0);
this.Log().Info("Files in release package:");
var contentFiles = pkg.GetContentFiles();
Assert.Equal(2, contentFiles.Count());
var contentFilePaths = contentFiles.Select(f => f.EffectivePath);
Assert.Contains("some-words.txt", contentFilePaths);
Assert.Contains("dir\\item-in-subdirectory.txt", contentFilePaths);
Assert.Equal(1, pkg.GetLibFiles().Count());
}
finally
{
File.Delete(outputPackage);
}
}
[Fact]
public void WhenAProjectContainsNet45BinariesItContainsTheNecessaryDependency()
{
var outputPackage = Path.GetTempFileName() + ".nupkg";
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ThisShouldBeANet45Project.1.0.nupkg");
var rightPackage = "Caliburn.Micro.1.5.2.nupkg";
var rightPackagePath = IntegrationTestHelper.GetPath("fixtures", rightPackage);
try
{
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true);
var package = new ReleasePackage(inputPackage);
var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir);
var zipPackage = new ZipPackage(outputFileName);
var dependency = zipPackage.GetLibFiles()
.Where(f => f.Path.EndsWith("Caliburn.Micro.dll"))
.FirstOrDefault(f => f.TargetFramework == FrameworkTargetVersion.Net45);
Assert.NotNull(dependency);
}
finally
{
File.Delete(outputPackage);
}
}
[Fact]
public void WhenAProjectContainsNet40BinariesItDoesntShipTheNet45Dependencies()
{
var outputPackage = Path.GetTempFileName() + ".nupkg";
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ThisShouldBeANet4Project.1.0.nupkg");
var rightPackage = "Caliburn.Micro.1.5.2.nupkg";
var rightPackagePath = IntegrationTestHelper.GetPath("fixtures", rightPackage);
try
{
var sourceDir = IntegrationTestHelper.GetPath("..", "packages");
(new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();
File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true);
var package = new ReleasePackage(inputPackage);
var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir);
var zipPackage = new ZipPackage(outputFileName);
var dependency = zipPackage.GetLibFiles()
.Where(f => f.Path.EndsWith("Caliburn.Micro.dll"))
.FirstOrDefault(f => f.TargetFramework
== new FrameworkName(".NETFramework,Version=v4.5"));
Assert.Null(dependency);
}
finally
{
File.Delete(outputPackage);
}
}
}
}

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\xunit.core.2.0.0-beta-build2700\build\portable-net45+win+wpa81+wp80\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.0.0-beta-build2700\build\portable-net45+win+wpa81+wp80\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{98AEB048-E27D-42F4-9440-505B7F78BAFD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Squirrel.Tests</RootNamespace>
<AssemblyName>Squirrel.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Web.XmlTransform">
<HintPath>..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll</HintPath>
</Reference>
<Reference Include="NuGet.Core, Version=2.8.50506.491, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NuGet.Core.2.8.2\lib\net40-Client\NuGet.Core.dll</HintPath>
</Reference>
<Reference Include="Splat">
<HintPath>..\packages\Splat.1.4.0\lib\Net45\Splat.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions">
<HintPath>..\packages\xunit.abstractions.2.0.0-beta-build2700\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.core">
<HintPath>..\packages\xunit.core.2.0.0-beta-build2700\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid\xunit.core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Squirrel.csproj">
<Project>{1436e22a-fe3c-4d68-9a85-9e74df2e6a92}</Project>
<Name>Squirrel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\xunit.core.2.0.0-beta-build2700\build\portable-net45+win+wpa81+wp80\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.0.0-beta-build2700\build\portable-net45+win+wpa81+wp80\xunit.core.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,152 @@
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using Xunit;
namespace Squirrel.Tests.TestHelpers
{
public static class AssertExtensions
{
public static void ShouldBeAboutEqualTo(this DateTimeOffset expected, DateTimeOffset current)
{
Assert.Equal(expected.Date, current.Date);
Assert.Equal(expected.Offset, current.Offset);
Assert.Equal(expected.Hour, current.Hour);
Assert.Equal(expected.Minute, current.Minute);
Assert.Equal(expected.Second, current.Second);
}
public static void ShouldBeFalse(this bool currentObject)
{
Assert.False(currentObject);
}
public static void ShouldBeNull(this object currentObject)
{
Assert.Null(currentObject);
}
public static void ShouldBeEmpty(this IEnumerable items)
{
Assert.Empty(items);
}
public static void ShouldNotBeEmpty(this IEnumerable items)
{
Assert.NotEmpty(items);
}
public static void ShouldBeTrue(this bool currentObject)
{
Assert.True(currentObject);
}
public static void ShouldEqual(this object compareFrom, object compareTo)
{
Assert.Equal(compareTo, compareFrom);
}
public static void ShouldEqual<T>(this T compareFrom, T compareTo)
{
Assert.Equal(compareTo, compareFrom);
}
public static void ShouldBeSameAs<T>(this T actual, T expected)
{
Assert.Same(expected, actual);
}
public static void ShouldNotBeSameAs<T>(this T actual, T expected)
{
Assert.NotSame(expected, actual);
}
public static void ShouldBeAssignableFrom<T>(this object instance) where T : class
{
Assert.IsAssignableFrom<T>(instance);
}
public static void ShouldBeType(this object instance, Type type)
{
Assert.IsType(type, instance);
}
public static void ShouldBeType<T>(this object instance)
{
Assert.IsType<T>(instance);
}
public static void ShouldNotBeType<T>(this object instance)
{
Assert.IsNotType<T>(instance);
}
public static void ShouldContain(this string current, string expectedSubstring, StringComparison comparison)
{
Assert.Contains(expectedSubstring, current, comparison);
}
public static void ShouldStartWith(this string current, string expectedSubstring, StringComparison comparison)
{
Assert.True(current.StartsWith(expectedSubstring, comparison));
}
public static void ShouldNotBeNull(this object currentObject)
{
Assert.NotNull(currentObject);
}
public static void ShouldNotBeNullNorEmpty(this string value)
{
Assert.NotNull(value);
Assert.NotEmpty(value);
}
public static void ShouldNotEqual(this object compareFrom, object compareTo)
{
Assert.NotEqual(compareTo, compareFrom);
}
public static void ShouldBeGreaterThan<T>(this T current, T other) where T : IComparable
{
Assert.True(current.CompareTo(other) > 0, current + " is not greater than " + other);
}
public static void ShouldBeLessThan<T>(this T current, T other) where T : IComparable
{
Assert.True(current.CompareTo(other) < 0, current + " is not less than " + other);
}
static string ToSafeString(this char c)
{
if (Char.IsControl(c) || Char.IsWhiteSpace(c))
{
switch (c)
{
case '\r':
return @"\r";
case '\n':
return @"\n";
case '\t':
return @"\t";
case '\a':
return @"\a";
case '\v':
return @"\v";
case '\f':
return @"\f";
default:
return String.Format("\\u{0:X};", (int)c);
}
}
return c.ToString(CultureInfo.InvariantCulture);
}
}
public enum DiffStyle
{
Full,
Minimal
}
}

View File

@@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Dynamic;
using System.Reflection;
// Lovingly stolen from http://exposedobject.codeplex.com/
namespace Squirrel.Tests.TestHelpers
{
public class ExposedClass : DynamicObject
{
private Type m_type;
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_staticMethods;
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genStaticMethods;
private ExposedClass(Type type)
{
m_type = type;
m_staticMethods =
m_type
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.Where(m => !m.IsGenericMethod)
.GroupBy(m => m.Name)
.ToDictionary(
p => p.Key,
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
m_genStaticMethods =
m_type
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.Where(m => m.IsGenericMethod)
.GroupBy(m => m.Name)
.ToDictionary(
p => p.Key,
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
// Get type args of the call
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
//
// Try to call a non-generic instance method
//
if (typeArgs == null
&& m_staticMethods.ContainsKey(binder.Name)
&& m_staticMethods[binder.Name].ContainsKey(args.Length)
&& ExposedObjectHelper.InvokeBestMethod(args, null, m_staticMethods[binder.Name][args.Length], out result))
{
return true;
}
//
// Try to call a generic instance method
//
if (m_staticMethods.ContainsKey(binder.Name)
&& m_staticMethods[binder.Name].ContainsKey(args.Length))
{
List<MethodInfo> methods = new List<MethodInfo>();
foreach (var method in m_genStaticMethods[binder.Name][args.Length])
{
if (method.GetGenericArguments().Length == typeArgs.Length)
{
methods.Add(method.MakeGenericMethod(typeArgs));
}
}
if (ExposedObjectHelper.InvokeBestMethod(args, null, methods, out result))
{
return true;
}
}
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var propertyInfo = m_type.GetProperty(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (propertyInfo != null)
{
propertyInfo.SetValue(null, value, null);
return true;
}
var fieldInfo = m_type.GetField(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (fieldInfo != null)
{
fieldInfo.SetValue(null, value);
return true;
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var propertyInfo = m_type.GetProperty(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (propertyInfo != null)
{
result = propertyInfo.GetValue(null, null);
return true;
}
var fieldInfo = m_type.GetField(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (fieldInfo != null)
{
result = fieldInfo.GetValue(null);
return true;
}
result = null;
return false;
}
public static dynamic From(Type type)
{
return new ExposedClass(type);
}
}
}

View File

@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Dynamic;
using System.Reflection;
// Lovingly stolen from http://exposedobject.codeplex.com/
namespace Squirrel.Tests.TestHelpers
{
public class ExposedObject : DynamicObject
{
private object m_object;
private Type m_type;
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_instanceMethods;
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genInstanceMethods;
private ExposedObject(object obj)
{
m_object = obj;
m_type = obj.GetType();
m_instanceMethods =
m_type
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.Where(m => !m.IsGenericMethod)
.GroupBy(m => m.Name)
.ToDictionary(
p => p.Key,
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
m_genInstanceMethods =
m_type
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.IsGenericMethod)
.GroupBy(m => m.Name)
.ToDictionary(
p => p.Key,
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
}
public object Object { get { return m_object; } }
public static dynamic New<T>()
{
return New(typeof(T));
}
public static dynamic New(Type type)
{
return new ExposedObject(Activator.CreateInstance(type));
}
public static dynamic From(object obj)
{
return new ExposedObject(obj);
}
public static T Cast<T>(ExposedObject t)
{
return (T)t.m_object;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
// Get type args of the call
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
//
// Try to call a non-generic instance method
//
if (typeArgs == null
&& m_instanceMethods.ContainsKey(binder.Name)
&& m_instanceMethods[binder.Name].ContainsKey(args.Length)
&& ExposedObjectHelper.InvokeBestMethod(args, m_object, m_instanceMethods[binder.Name][args.Length], out result))
{
return true;
}
//
// Try to call a generic instance method
//
if (m_instanceMethods.ContainsKey(binder.Name)
&& m_instanceMethods[binder.Name].ContainsKey(args.Length))
{
List<MethodInfo> methods = new List<MethodInfo>();
if (m_genInstanceMethods.ContainsKey(binder.Name) &&
m_genInstanceMethods[binder.Name].ContainsKey(args.Length))
{
foreach (var method in m_genInstanceMethods[binder.Name][args.Length])
{
if (method.GetGenericArguments().Length == typeArgs.Length)
{
methods.Add(method.MakeGenericMethod(typeArgs));
}
}
}
if (ExposedObjectHelper.InvokeBestMethod(args, m_object, methods, out result))
{
return true;
}
}
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var propertyInfo = m_type.GetProperty(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo != null)
{
propertyInfo.SetValue(m_object, value, null);
return true;
}
var fieldInfo = m_type.GetField(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (fieldInfo != null)
{
fieldInfo.SetValue(m_object, value);
return true;
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var propertyInfo = m_object.GetType().GetProperty(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo != null)
{
result = propertyInfo.GetValue(m_object, null);
return true;
}
var fieldInfo = m_object.GetType().GetField(
binder.Name,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (fieldInfo != null)
{
result = fieldInfo.GetValue(m_object);
return true;
}
result = null;
return false;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = m_object;
return true;
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Dynamic;
// Lovingly stolen from http://exposedobject.codeplex.com/
namespace Squirrel.Tests.TestHelpers
{
internal class ExposedObjectHelper
{
private static Type s_csharpInvokePropertyType =
typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
.Assembly
.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
internal static bool InvokeBestMethod(object[] args, object target, List<MethodInfo> instanceMethods, out object result)
{
if (instanceMethods.Count == 1)
{
// Just one matching instance method - call it
if (TryInvoke(instanceMethods[0], target, args, out result))
{
return true;
}
}
else if (instanceMethods.Count > 1)
{
// Find a method with best matching parameters
MethodInfo best = null;
Type[] bestParams = null;
Type[] actualParams = args.Select(p => p == null ? typeof(object) : p.GetType()).ToArray();
Func<Type[], Type[], bool> isAssignableFrom = (a, b) =>
{
for (int i = 0; i < a.Length; i++)
{
if (!a[i].IsAssignableFrom(b[i])) return false;
}
return true;
};
foreach (var method in instanceMethods.Where(m => m.GetParameters().Length == args.Length))
{
Type[] mParams = method.GetParameters().Select(x => x.ParameterType).ToArray();
if (isAssignableFrom(mParams, actualParams))
{
if (best == null || isAssignableFrom(bestParams, mParams))
{
best = method;
bestParams = mParams;
}
}
}
if (best != null && TryInvoke(best, target, args, out result))
{
return true;
}
}
result = null;
return false;
}
internal static bool TryInvoke(MethodInfo methodInfo, object target, object[] args, out object result)
{
try
{
result = methodInfo.Invoke(target, args);
return true;
}
catch (TargetInvocationException) { }
catch (TargetParameterCountException) { }
result = null;
return false;
}
internal static Type[] GetTypeArgs(InvokeMemberBinder binder)
{
if (s_csharpInvokePropertyType.IsInstanceOfType(binder))
{
PropertyInfo typeArgsProperty = s_csharpInvokePropertyType.GetProperty("TypeArguments");
return ((IEnumerable<Type>)typeArgsProperty.GetValue(binder, null)).ToArray();
}
return null;
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading;
using Ionic.Zip;
using Squirrel.Core;
using ReactiveUIMicro;
using Squirrel.Tests.WiXUi;
namespace Squirrel.Tests.TestHelpers
{
public static class IntegrationTestHelper
{
public static string GetPath(params string[] paths)
{
var ret = GetIntegrationTestRootDirectory();
return (new FileInfo(paths.Aggregate (ret, Path.Combine))).FullName;
}
public static string GetIntegrationTestRootDirectory()
{
// XXX: This is an evil hack, but it's okay for a unit test
// We can't use Assembly.Location because unit test runners love
// to move stuff to temp directories
var st = new StackFrame(true);
var di = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(st.GetFileName()), ".."));
return di.FullName;
}
public static bool SkipTestOnXPAndVista()
{
int osVersion = Environment.OSVersion.Version.Major*100 + Environment.OSVersion.Version.Minor;
return (osVersion < 601);
}
public static void RunBlockAsSTA(Action block)
{
Exception ex = null;
var t = new Thread(() => {
try {
block();
} catch (Exception e) {
ex = e;
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
if (ex != null) {
// NB: If we don't do this, the test silently passes
throw new Exception("", ex);
}
}
static object gate = 42;
public static IDisposable WithFakeInstallDirectory(string packageFileName, out string path)
{
var ret = Utility.WithTempDirectory(out path);
File.Copy(GetPath("fixtures", packageFileName), Path.Combine(path, packageFileName));
var rp = ReleaseEntry.GenerateFromFile(Path.Combine(path, packageFileName));
ReleaseEntry.WriteReleaseFile(new[] { rp }, Path.Combine(path, "RELEASES"));
// NB: This is a temporary hack. The reason we serialize the tests
// like this, is to make sure that we don't have two tests registering
// their Service Locators with RxApp.
Monitor.Enter(gate);
return new CompositeDisposable(ret, Disposable.Create(() => Monitor.Exit(gate)));
}
public static IDisposable WithFakeInstallDirectory(out string path)
{
return WithFakeInstallDirectory("SampleUpdatingApp.1.1.0.0.nupkg", out path);
}
public static IDisposable WithFakeAlreadyInstalledApp(out string path)
{
return WithFakeAlreadyInstalledApp("InstalledSampleUpdatingApp-1.1.0.0.zip", out path);
}
public static IDisposable WithFakeAlreadyInstalledApp(string zipFile, out string path)
{
var ret = Utility.WithTempDirectory(out path);
var zf = new ZipFile(GetPath("fixtures", zipFile));
zf.ExtractAll(path);
Monitor.Enter(gate);
return new CompositeDisposable(ret, Disposable.Create(() => Monitor.Exit(gate)));
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.IO;
using System.Net;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading;
namespace Squirrel.Tests
{
public sealed class StaticHttpServer : IDisposable
{
public int Port { get; private set; }
public string RootPath { get; private set; }
IDisposable inner;
public StaticHttpServer(int port, string rootPath)
{
Port = port; RootPath = rootPath;
}
public IDisposable Start()
{
if (inner != null) {
throw new InvalidOperationException("Already started!");
}
var server = new HttpListener();
server.Prefixes.Add(String.Format("http://+:{0}/", Port));
server.Start();
var listener = Observable.Defer(() => Observable.FromAsyncPattern<HttpListenerContext>(server.BeginGetContext, server.EndGetContext)())
.Repeat()
.Subscribe(ctx => {
if (ctx.Request.HttpMethod != "GET") {
closeResponseWith(ctx, 400, "GETs only");
return;
}
var target = Path.Combine(RootPath, ctx.Request.Url.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Substring(1));
var fi = new FileInfo(target);
if (!fi.FullName.StartsWith(RootPath)) {
closeResponseWith(ctx, 401, "Not authorized");
return;
}
if (!fi.Exists) {
closeResponseWith(ctx, 404, "Not found");
return;
}
try {
using (var input = File.OpenRead(target)) {
ctx.Response.StatusCode = 200;
input.CopyTo(ctx.Response.OutputStream);
ctx.Response.Close();
}
} catch (Exception ex) {
closeResponseWith(ctx, 500, ex.ToString());
}
});
var ret = Disposable.Create(() => {
listener.Dispose();
server.Stop();
inner = null;
});
inner = ret;
return ret;
}
static void closeResponseWith(HttpListenerContext ctx, int statusCode, string message)
{
ctx.Response.StatusCode = statusCode;
using (var sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8)) {
sw.WriteLine(message);
}
ctx.Response.Close();
}
public void Dispose()
{
var toDispose = Interlocked.Exchange(ref inner, null);
if (toDispose != null) {
toDispose.Dispose();
}
}
}
}

95
test/UtilityTests.cs Normal file
View File

@@ -0,0 +1,95 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Security.Cryptography;
using System.Text;
using ReactiveUIMicro;
using Squirrel.Core;
using Squirrel.Tests.TestHelpers;
using Xunit;
namespace Squirrel.Tests.Core
{
public class UtilityTests : IEnableLogger
{
[Fact]
public void ShaCheckShouldBeCaseInsensitive()
{
var sha1FromExternalTool = "75255cfd229a1ed1447abe1104f5635e69975d30";
var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg");
var stream = File.OpenRead(inputPackage);
var sha1 = Utility.CalculateStreamSHA1(stream);
Assert.NotEqual(sha1FromExternalTool, sha1);
Assert.Equal(sha1FromExternalTool, sha1, StringComparer.OrdinalIgnoreCase);
}
[Fact]
public void CanDeleteDeepRecursiveDirectoryStructure()
{
string tempDir;
using (Utility.WithTempDirectory(out tempDir)) {
for (var i = 0; i < 50; i++) {
var directory = Path.Combine(tempDir, newId());
CreateSampleDirectory(directory);
}
var files = Directory.GetFiles(tempDir, "*", SearchOption.AllDirectories);
var count = files.Count();
this.Log().Info("Created {0} files under directory {1}", count, tempDir);
var sw = new Stopwatch();
sw.Start();
Utility.DeleteDirectory(tempDir).Wait();
sw.Stop();
this.Log().Info("Delete took {0}ms", sw.ElapsedMilliseconds);
Assert.False(Directory.Exists(tempDir));
}
}
static void CreateSampleDirectory(string directory)
{
while (true) {
Directory.CreateDirectory(directory);
for (var j = 0; j < 100; j++) {
var file = Path.Combine(directory, newId());
if (file.Length > 260) continue;
File.WriteAllText(file, Guid.NewGuid().ToString());
}
if (new Random().NextDouble() > 0.5) {
var childDirectory = Path.Combine(directory, newId());
if (childDirectory.Length > 248) return;
directory = childDirectory;
continue;
}
break;
}
}
static string newId()
{
var text = Guid.NewGuid().ToString();
var bytes = Encoding.Unicode.GetBytes(text);
var provider = new SHA1Managed();
var hashString = string.Empty;
foreach (var x in provider.ComputeHash(bytes)) {
hashString += String.Format("{0:x2}", x);
}
if (hashString.Length > 7) {
return hashString.Substring(0, 7);
}
return hashString;
}
}
}

11
test/packages.config Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
<package id="NuGet.Core" version="2.8.2" targetFramework="net45" />
<package id="Splat" version="1.4.0" targetFramework="net45" />
<package id="xunit" version="2.0.0-beta-build2700" targetFramework="net45" />
<package id="xunit.abstractions" version="2.0.0-beta-build2700" targetFramework="net45" />
<package id="xunit.assert" version="2.0.0-beta-build2700" targetFramework="net45" />
<package id="xunit.core" version="2.0.0-beta-build2700" targetFramework="net45" />
<package id="xunit.runner.utility" version="2.0.0-beta-build2700" targetFramework="net45" />
</packages>