Skip to content

Commit

Permalink
✨ add lazy WalkDependencies for Assembly types
Browse files Browse the repository at this point in the history
  • Loading branch information
fluffynuts committed May 30, 2024
1 parent 4d44caa commit 9022498
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,41 +1,79 @@
using PeanutButter.RandomGenerators;
using System.Reflection;
using PeanutButter.RandomGenerators;

namespace PeanutButter.Utils.Tests
{
[TestFixture]
public class TestAssemblyExtensions
{
[Test]
public void FindTypeByName_WhenGivenUnknownTypeName_ShouldReturnNull()
[TestFixture]
public class FindTypeByName
{
//---------------Set up test pack-------------------
var asm = GetType().Assembly;
var search = RandomValueGen.GetRandomString(20, 30);
//---------------Assert Precondition----------------
[TestFixture]
public class GivenUnknownTypeName
{
[Test]
public void ShouldReturnNull()
{
//---------------Set up test pack-------------------
var asm = GetType().Assembly;
var search = RandomValueGen.GetRandomString(20, 30);
//---------------Assert Precondition----------------

//---------------Execute Test ----------------------
var result = asm.FindTypeByName(search);
//---------------Execute Test ----------------------
var result = asm.FindTypeByName(search);

//---------------Test Result -----------------------
Expect(result)
.To.Be.Null();
//---------------Test Result -----------------------
Expect(result)
.To.Be.Null();
}
}

[TestFixture]
public class GivenKnownTypeName
{
[Test]
public void ShouldReturnTheType()
{
//---------------Set up test pack-------------------
var myType = GetType();
var asm = myType.Assembly;
var search = myType.Name;
//---------------Assert Precondition----------------

//---------------Execute Test ----------------------
var result = asm.FindTypeByName(search);

//---------------Test Result -----------------------
Expect(result)
.To.Equal(myType);
}
}
}

[Test]
public void FindTypeByName_WhenGivenKnownTypeName_ShouldReturnTheType()
[TestFixture]
public class WalkDependencies
{
//---------------Set up test pack-------------------
var myType = GetType();
var asm = myType.Assembly;
var search = myType.Name;
//---------------Assert Precondition----------------

//---------------Execute Test ----------------------
var result = asm.FindTypeByName(search);

//---------------Test Result -----------------------
Expect(result)
.To.Equal(myType);
[Test]
public void ShouldReturnAssemblyDependenciesPerLevel()
{
// Arrange
// Act
var collected = new List<Assembly>();
foreach (var assemblies in typeof(TestAssemblyExtensions).Assembly.WalkDependencies())
{
collected.AddRange(assemblies);
}

// Assert
var asmNames = collected.Select(o => o.FullName).ToArray();
Expect(asmNames)
.To.Contain.At.Least(80).Items(
"At time of writing, this should be around 87..."
);
Expect(asmNames)
.To.Be.Distinct();
}
}
}
}
}
58 changes: 58 additions & 0 deletions source/Utils/PeanutButter.Utils/AssemblyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

Expand Down Expand Up @@ -31,5 +33,61 @@ public static Type FindTypeByName(this Assembly assembly, string typeName)
.GetExportedTypes()
.FirstOrDefault(t => t.Name == typeName);
}


/// <summary>
/// Walks the assembly dependency tree
/// </summary>
/// <param name="asm"></param>
/// <returns></returns>
public static IEnumerable<Assembly[]> WalkDependencies(
this Assembly asm
)
{
var queue = new Queue<Assembly[]>();
queue.Enqueue(asm.InArray());
var seen = new HashSet<string>();
var reported = new HashSet<string>();
var loadedAssemblies = AppDomain.CurrentDomain
.GetAssemblies()
.ToArray();
while (queue.Any())
{
var current = queue.Dequeue();
if (current.Length == 0)
{
yield break;
}

yield return current
.Where(a => !reported.Contains(a.FullName))
.ToArray();
foreach (var a in current)
{
reported.Add(a.FullName);
if (!seen.Add(a.FullName))
{
continue;
}

var refs = a.GetReferencedAssemblies()
.Select(n => $"{n}")
.Select(
n => Tuple.Create(
n,
loadedAssemblies
.FirstOrDefault(
aa => $"{aa.GetName()}" == n
) ?? Assembly.Load(n)
)
)
.Where(o => o.Item2 is not null)
.Select(o => o.Item2)
.ToArray();

queue.Enqueue(refs);
}
}
}
}
}

0 comments on commit 9022498

Please sign in to comment.