Skip to content

Commit

Permalink
Merge pull request #333 from TNG/325-ensure-no-calls-between-modules-…
Browse files Browse the repository at this point in the history
…in-a-modulith
  • Loading branch information
alexanderlinne authored Jan 13, 2025
2 parents 88f48ea + 0ccf818 commit 2076193
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 1 deletion.
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 <[email protected]>
// Copyright 2019 Fritz Brandhuber <[email protected]>
// Copyright 2020 Pavel Fischer <[email protected]>
//
// 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>

0 comments on commit 2076193

Please sign in to comment.