Skip to content
This repository was archived by the owner on Mar 19, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Added test for mscorsn DLL load errors
  • Loading branch information
jnm2 committed Feb 15, 2017
commit f0fcc373bd3f7811430d16c8ebf9be0972414da8
115 changes: 115 additions & 0 deletions ILMerge.Tests/Helpers/ProcessUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace ILMerging.Tests.Helpers
{
public static class ProcessUtils
{
public static ProcessResult Run(ProcessStartInfo startInfo)
{
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;

var process = new Process { StartInfo = startInfo };

var standardStreamData = new List<StandardStreamData>();
var currentData = new StringBuilder();
var currentDataIsError = false;

process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null) return;
if (currentDataIsError)
{
if (currentData.Length != 0)
standardStreamData.Add(new StandardStreamData(currentDataIsError, currentData.ToString()));
currentData.Clear();
currentDataIsError = false;
}
currentData.AppendLine(e.Data);
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null) return;
if (!currentDataIsError)
{
if (currentData.Length != 0)
standardStreamData.Add(new StandardStreamData(currentDataIsError, currentData.ToString()));
currentData.Clear();
currentDataIsError = true;
}
currentData.AppendLine(e.Data);
};

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

if (currentData.Length != 0)
standardStreamData.Add(new StandardStreamData(currentDataIsError, currentData.ToString()));

return new ProcessResult(process.ExitCode, standardStreamData.ToArray());
}

[DebuggerDisplay("{ToString(),nq}")]
public struct ProcessResult
{
public ProcessResult(int exitCode, StandardStreamData[] standardStreamData)
{
ExitCode = exitCode;
StandardStreamData = standardStreamData;
}

public int ExitCode { get; }
public StandardStreamData[] StandardStreamData { get; }

public override string ToString() => ToString(true);

/// <param name="showStreamSource">If true, appends "[stdout] " or "[stderr] " to the beginning of each line.</param>
public string ToString(bool showStreamSource)
{
var r = new StringBuilder("Exit code ").Append(ExitCode);

if (StandardStreamData.Length != 0) r.AppendLine();

foreach (var data in StandardStreamData)
{
if (showStreamSource)
{
var lines = data.Data.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

// StandardStreamData.Data always ends with a blank line, so skip that
for (var i = 0; i < lines.Length - 1; i++)
r.Append(data.IsError ? "[stderr] " : "[stdout] ").AppendLine(lines[i]);
}
else
{
r.Append(data.Data);
}
}

return r.ToString();
}
}

[DebuggerDisplay("{ToString(),nq}")]
public struct StandardStreamData
{
public StandardStreamData(bool isError, string data)
{
IsError = isError;
Data = data;
}

public bool IsError { get; }
public string Data { get; }

public override string ToString() => (IsError ? "[stderr] " : "[stdout] ") + Data;
}
}
}
40 changes: 40 additions & 0 deletions ILMerge.Tests/Helpers/ShadowCopyUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace ILMerging.Tests.Helpers
{
public static class ShadowCopyUtils
{
public static IEnumerable<Assembly> GetTransitiveClosure(params Assembly[] assemblies)
{
var finishedAssemblies = new HashSet<Assembly>();

using (var en = StackEnumerator.Create(assemblies))
foreach (var assembly in en)
{
if (!finishedAssemblies.Add(assembly)) continue;
yield return assembly;
en.Recurse(assembly.GetReferencedAssemblies().Select(Assembly.Load));
}
}

public static IEnumerable<string> GetTransitiveClosureDirectories(params Assembly[] assemblies)
{
return GetTransitiveClosure(assemblies)
.Where(_ => !_.GlobalAssemblyCache)
.Select(_ => Path.GetDirectoryName(_.Location))
.Distinct(StringComparer.OrdinalIgnoreCase);
}

/// <summary>
/// Necessary because of test runners like ReSharper and NCrunch which shadow copy each assembly to an isolated directory
/// </summary>
public static string GenerateILMergeLibCliSwitches(params Assembly[] assemblies)
{
return string.Join(" ", GetTransitiveClosureDirectories(Assembly.GetExecutingAssembly()).Select(_ => $"/lib:\"{_}\""));
}
}
}
153 changes: 153 additions & 0 deletions ILMerge.Tests/Helpers/StackEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace ILMerging.Tests.Helpers
{
public static class StackEnumerator
{
public static StackEnumerator<T> Create<T>(params T[] initial) => new StackEnumerator<T>(initial);
public static StackEnumerator<T> Create<T>(IEnumerable<T> initial) => new StackEnumerator<T>(initial);
public static StackEnumerator<T> Create<T>(IEnumerator<T> initial) => new StackEnumerator<T>(initial);
public static StackEnumerator<TContext, T> Create<TContext, T>(TContext initialContext, params T[] initial) => new StackEnumerator<TContext, T>(initialContext, initial);
public static StackEnumerator<TContext, T> Create<TContext, T>(TContext initialContext, IEnumerable<T> initial) => new StackEnumerator<TContext, T>(initialContext, initial);
public static StackEnumerator<TContext, T> Create<TContext, T>(TContext initialContext, IEnumerator<T> initial) => new StackEnumerator<TContext, T>(initialContext, initial);
}

public sealed class StackEnumerator<T> : IDisposable
{
private readonly Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
private IEnumerator<T> current;

public bool MoveNext()
{
while (!current.MoveNext())
{
current.Dispose();
if (stack.Count == 0) return false;
current = stack.Pop();
}

return true;
}

public T Current => current.Current;

public void Recurse(IEnumerator<T> newCurrent)
{
if (newCurrent == null) return;
stack.Push(current);
current = newCurrent;
}
public void Recurse(IEnumerable<T> newCurrent)
{
if (newCurrent == null) return;
Recurse(newCurrent.GetEnumerator());
}
public void Recurse(params T[] newCurrent)
{
Recurse((IEnumerable<T>)newCurrent);
}

public StackEnumerator(IEnumerator<T> initial)
{
current = initial ?? System.Linq.Enumerable.Empty<T>().GetEnumerator();
}
public StackEnumerator(IEnumerable<T> initial) : this(initial?.GetEnumerator())
{
}
public StackEnumerator(params T[] initial) : this((IEnumerable<T>)initial)
{
}

// Foreach support
[EditorBrowsable(EditorBrowsableState.Never)]
public StackEnumerator<T> GetEnumerator()
{
return this;
}

public void Dispose()
{
current.Dispose();
foreach (var item in stack)
item.Dispose();
stack.Clear();
}
}

public sealed class StackEnumerator<TContext, T> : IDisposable
{
public struct ContextCurrent
{
public TContext Context { get; }

public T Current { get; }

public ContextCurrent(TContext context, T current)
{
Context = context;
Current = current;
}
}

private readonly Stack<Tuple<TContext, IEnumerator<T>>> stack = new Stack<Tuple<TContext, IEnumerator<T>>>();
private Tuple<TContext, IEnumerator<T>> current;

public bool MoveNext()
{
while (!current.Item2.MoveNext())
{
current.Item2.Dispose();
if (stack.Count == 0) return false;
current = stack.Pop();
}

return true;
}

public ContextCurrent Current => new ContextCurrent(current.Item1, current.Item2.Current);

public void Recurse(TContext newContext, IEnumerator<T> newCurrent)
{
if (newCurrent == null) return;
stack.Push(current);
current = Tuple.Create(newContext, newCurrent);
}
public void Recurse(TContext newContext, IEnumerable<T> newCurrent)
{
if (newCurrent == null) return;
Recurse(newContext, newCurrent.GetEnumerator());
}
public void Recurse(TContext newContext, params T[] newCurrent)
{
Recurse(newContext, (IEnumerable<T>)newCurrent);
}

public StackEnumerator(TContext initialContext, IEnumerator<T> initial)
{
current = Tuple.Create(initialContext, initial ?? System.Linq.Enumerable.Empty<T>().GetEnumerator());
}
public StackEnumerator(TContext initialContext, IEnumerable<T> initial) : this(initialContext, initial?.GetEnumerator())
{
}
public StackEnumerator(TContext initialContext, params T[] initial) : this(initialContext, (IEnumerable<T>)initial)
{
}

// Foreach support
[EditorBrowsable(EditorBrowsableState.Never)]
public StackEnumerator<TContext, T> GetEnumerator()
{
return this;
}

public void Dispose()
{
current.Item2.Dispose();
foreach (var item in stack)
item.Item2.Dispose();
stack.Clear();
}
}
}
29 changes: 29 additions & 0 deletions ILMerge.Tests/Helpers/TempFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace ILMerging.Tests.Helpers
{
[DebuggerDisplay("{ToString(),nq}")]
public sealed class TempFile : IDisposable
{
public TempFile(string path)
{
this.path = path;
}

private string path;
public string Path => path;

public static implicit operator string(TempFile tempFile) => tempFile.path;

public override string ToString() => path;

public void Dispose()
{
var path = Interlocked.Exchange(ref this.path, null);
if (path != null) File.Delete(path);
}
}
}
Loading