Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dont throw exception if a type can not be resolved #333

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 7 additions & 0 deletions ArchUnit.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoaderTestAssembly", "TestA
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OtherLoaderTestAssembly", "TestAssemblies\OtherLoaderTestAssembly\OtherLoaderTestAssembly.csproj", "{5A24529B-1794-4080-ADCC-77440BA0A0B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FilteredDirectoryLoaderTestAssembly", "TestAssemblies\FilteredDirectoryLoaderTestAssembly\FilteredDirectoryLoaderTestAssembly.csproj", "{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -94,6 +96,10 @@ Global
{5A24529B-1794-4080-ADCC-77440BA0A0B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A24529B-1794-4080-ADCC-77440BA0A0B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A24529B-1794-4080-ADCC-77440BA0A0B3}.Release|Any CPU.Build.0 = Release|Any CPU
{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -104,5 +110,6 @@ Global
{FBCD91F2-4DB9-44AC-8214-6F2FFF9178D5} = {B1191F18-91CB-4387-B775-A5EB64D3AC30}
{0243F2D4-AC89-4561-A936-D647B6BB821F} = {B1191F18-91CB-4387-B775-A5EB64D3AC30}
{5A24529B-1794-4080-ADCC-77440BA0A0B3} = {B1191F18-91CB-4387-B775-A5EB64D3AC30}
{E6CB8C69-25F5-4C94-8EA3-D56E444EB46B} = {B1191F18-91CB-4387-B775-A5EB64D3AC30}
EndGlobalSection
EndGlobal
75 changes: 75 additions & 0 deletions ArchUnitNET/Domain/UnavailableType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2019 Florian Gather <florian.gather@tngtech.com>
// Copyright 2019 Fritz Brandhuber <fritz.brandhuber@tngtech.com>
// Copyright 2020 Pavel Fischer <rubbiroid@gmail.com>
//
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Generic;
using System.Linq;
using ArchUnitNET.Domain.Dependencies;

namespace ArchUnitNET.Domain
{
public class UnavailableType : IType
{
public UnavailableType(IType type)
{
Type = type;
}

private IType Type { get; }
public string Name => Type.Name;
public string FullName => Type.FullName;

public Visibility Visibility => Type.Visibility;
public bool IsNested => Type.IsNested;
public bool IsGeneric => Type.IsGeneric;
public bool IsGenericParameter => Type.IsGenericParameter;
public bool IsStub => true;
public bool IsCompilerGenerated => Type.IsCompilerGenerated;

public Namespace Namespace => Type.Namespace;
public Assembly Assembly => Type.Assembly;

public IEnumerable<Attribute> Attributes =>
AttributeInstances.Select(instance => instance.Type);
public List<AttributeInstance> AttributeInstances => Type.AttributeInstances;

public List<ITypeDependency> Dependencies => Type.Dependencies;
public List<ITypeDependency> BackwardsDependencies => Type.BackwardsDependencies;
public IEnumerable<IType> ImplementedInterfaces => Type.ImplementedInterfaces;

public MemberList Members => Type.Members;
public List<GenericParameter> GenericParameters => Type.GenericParameters;

public override string ToString()
{
return FullName;
}

private bool Equals(Struct other)
{
return Equals(Type, other.Type);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}

if (ReferenceEquals(this, obj))
{
return true;
}

return obj.GetType() == GetType() && Equals((Struct)obj);
}

public override int GetHashCode()
{
return Type != null ? Type.GetHashCode() : 0;
}
}
}
24 changes: 23 additions & 1 deletion ArchUnitNET/Loader/TypeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,29 @@ bool isStub
}
if (typeDefinition == null)
{
throw new ArchLoaderException($"Could not resolve type {typeReference.FullName}");
// When assemblies are loaded by path, there are cases where a dependent type cannot be resolved because
// the assembly dependency is not loaded in the current application domain. In this case, we create a
// stub type.
return new TypeInstance<IType>(
new UnavailableType(
new Type(
typeReference.BuildFullName(),
typeReference.Name,
_assemblyRegistry.GetOrCreateAssembly(
typeReference.Module.Assembly.Name.FullName,
typeReference.Module.Assembly.FullName,
true,
null
),
_namespaceRegistry.GetOrCreateNamespace(typeReference.Namespace),
NotAccessible,
typeReference.IsNested,
typeReference.HasGenericParameters,
true,
typeReference.IsCompilerGenerated()
)
)
);
}

var typeName = typeDefinition.BuildFullName();
Expand Down
1 change: 1 addition & 0 deletions ArchUnitNETTests/ArchUnitNETTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ProjectReference Include="..\TestAssembly\TestAssembly.csproj" />
<ProjectReference Include="..\TestAssemblies\AttributeAssembly\AttributeAssembly.csproj" />
<ProjectReference Include="..\TestAssemblies\DependencyAssembly\DependencyAssembly.csproj" />
<ProjectReference Include="..\TestAssemblies\FilteredDirectoryLoaderTestAssembly\FilteredDirectoryLoaderTestAssembly.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\TestAssemblies\LoaderTestAssembly\LoaderTestAssembly.csproj" />
<ProjectReference
Include="..\TestAssemblies\OtherLoaderTestAssembly\OtherLoaderTestAssembly.csproj" />
Expand Down
28 changes: 28 additions & 0 deletions ArchUnitNETTests/Loader/ArchLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
//
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Linq;
using ArchUnitNET.Domain;
using ArchUnitNET.Domain.Extensions;
using ArchUnitNET.Loader;
using ArchUnitNET.xUnit;
using ArchUnitNETTests.Domain.Dependencies.Members;
Expand Down Expand Up @@ -96,5 +99,30 @@ public void TypesAreAssignedToCorrectAssemblies()
.ResideInAssembly(GetType().Assembly)
.Check(architecture);
}

[Fact]
public void UnavailableTypeTest()
{
// When loading an assembly from a file, there are situations where the assemblies dependencies are not
// available in the current AppDomain. This test checks that the loader does not throw an exception in this
// case.
var assemblyPath = AppDomain.CurrentDomain.BaseDirectory[
..AppDomain.CurrentDomain.BaseDirectory.IndexOf(
@"ArchUnitNETTests",
StringComparison.InvariantCulture
)
];
var architecture = new ArchLoader()
.LoadFilteredDirectory(
assemblyPath,
"FilteredDirectoryLoaderTestAssembly.dll",
System.IO.SearchOption.AllDirectories
)
.Build();
Assert.Single(architecture.Types);
var loggerType = architecture.ReferencedTypes.WhereFullNameIs("Serilog.ILogger");
Assert.NotNull(loggerType);
Assert.True(loggerType is UnavailableType);
}
}
}
1 change: 1 addition & 0 deletions TestAssemblies/AttributeAssembly/AttributeAssembly.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
13 changes: 13 additions & 0 deletions TestAssemblies/FilteredDirectoryLoaderTestAssembly/Class1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Serilog;

namespace FilteredDirectoryLoaderTestAssembly;

public class Class1
{
public ILogger logger;

public Class1()
{
this.logger = new LoggerConfiguration().CreateLogger();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FilteredDirectoryLoaderTestAssembly", "FilteredDirectoryLoaderTestAssembly.csproj", "{8597C220-0EC2-42AF-9675-C56607614773}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8597C220-0EC2-42AF-9675-C56607614773}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8597C220-0EC2-42AF-9675-C56607614773}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8597C220-0EC2-42AF-9675-C56607614773}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8597C220-0EC2-42AF-9675-C56607614773}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B166203B-6B5B-4BE6-B945-CA9FD03A6054}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
Loading