Skip to content
Open
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
8 changes: 4 additions & 4 deletions ArchUnitNET/Domain/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,22 +241,22 @@ public static Attribute GetAttributeOfType(this IType type, Class attributeClass

public static bool ResidesInNamespace(this IType e, string fullName)
{
return e.Namespace.FullNameEquals(fullName);
return e.Namespace != null && e.Namespace.FullNameEquals(fullName);
}

public static bool ResidesInNamespaceMatching(this IType e, string pattern)
{
return e.Namespace.FullNameMatches(pattern);
return e.Namespace != null && e.Namespace.FullNameMatches(pattern);
}

public static bool ResidesInAssembly(this IType e, string fullName)
{
return e.Assembly.FullNameEquals(fullName);
return e.Assembly != null && e.Assembly.FullNameEquals(fullName);
}

public static bool ResidesInAssemblyMatching(this IType e, string pattern)
{
return e.Assembly.FullNameMatches(pattern);
return e.Assembly != null && e.Assembly.FullNameMatches(pattern);
}

public static bool IsDeclaredAsFieldIn(this IType type, string fullName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,25 @@ Architecture architecture
return new OrderedArchitectureCondition<TRuleType>(Condition, description);
}

private static string DescribeNamespaceOf(IType type)
{
return type.Namespace == null
? "does not reside in a namespace"
: "does reside in " + type.Namespace.FullName;
}

private static string DescribeAssemblyOf(IType type)
{
return type.Assembly == null
? "does not reside in an assembly"
: "does reside in " + type.Assembly.FullName;
}

public static IOrderedCondition<TRuleType> ResideInNamespace(string fullName)
{
return new SimpleCondition<TRuleType>(
type => type.ResidesInNamespace(fullName),
obj => "does reside in " + obj.Namespace.FullName,
obj => DescribeNamespaceOf(obj),
"reside in namespace with full name \"" + fullName + "\""
);
}
Expand All @@ -309,7 +323,7 @@ public static IOrderedCondition<TRuleType> ResideInNamespaceMatching(string patt
{
return new SimpleCondition<TRuleType>(
type => type.ResidesInNamespaceMatching(pattern),
obj => "does reside in " + obj.Namespace.FullName,
obj => DescribeNamespaceOf(obj),
"reside in namespace with full name matching \"" + pattern + "\""
);
}
Expand All @@ -318,7 +332,7 @@ public static IOrderedCondition<TRuleType> ResideInAssembly(string fullName)
{
return new SimpleCondition<TRuleType>(
type => type.ResidesInAssembly(fullName),
obj => "does reside in " + obj.Assembly.FullName,
obj => DescribeAssemblyOf(obj),
"reside in assembly with full name \"" + fullName + "\""
);
}
Expand All @@ -327,7 +341,7 @@ public static IOrderedCondition<TRuleType> ResideInAssemblyMatching(string patte
{
return new SimpleCondition<TRuleType>(
type => type.ResidesInAssemblyMatching(pattern),
obj => "does reside in " + obj.Assembly.FullName,
obj => DescribeAssemblyOf(obj),
"reside in assembly with full name matching \"" + pattern + "\""
);
}
Expand All @@ -339,9 +353,9 @@ params System.Reflection.Assembly[] moreAssemblies
{
bool Condition(TRuleType ruleType, Architecture architecture)
{
return ruleType.Assembly.Equals(architecture.GetAssemblyOfAssembly(assembly))
return Equals(ruleType.Assembly, architecture.GetAssemblyOfAssembly(assembly))
|| moreAssemblies.Any(asm =>
ruleType.Assembly.Equals(architecture.GetAssemblyOfAssembly(asm))
Equals(ruleType.Assembly, architecture.GetAssemblyOfAssembly(asm))
);
}

Expand All @@ -352,7 +366,7 @@ bool Condition(TRuleType ruleType, Architecture architecture)

return new OrderedArchitectureCondition<TRuleType>(
Condition,
(type, architecture) => "does reside in " + type.Assembly.FullName,
(type, architecture) => DescribeAssemblyOf(type),
description
);
}
Expand All @@ -375,7 +389,7 @@ bool Condition(TRuleType ruleType)

return new SimpleCondition<TRuleType>(
Condition,
type => "does reside in " + type.Assembly.FullName,
type => DescribeAssemblyOf(type),
description
);
}
Expand Down Expand Up @@ -706,7 +720,7 @@ public static IOrderedCondition<TRuleType> NotResideInNamespace(string fullName)
{
return new SimpleCondition<TRuleType>(
type => !type.ResidesInNamespace(fullName),
obj => "does reside in " + obj.Namespace.FullName,
obj => DescribeNamespaceOf(obj),
"not reside in namespace with full name \"" + fullName + "\""
);
}
Expand All @@ -715,7 +729,7 @@ public static IOrderedCondition<TRuleType> NotResideInNamespaceMatching(string p
{
return new SimpleCondition<TRuleType>(
type => !type.ResidesInNamespaceMatching(pattern),
obj => "does reside in " + obj.Namespace.FullName,
obj => DescribeNamespaceOf(obj),
"not reside in namespace with full name matching \"" + pattern + "\""
);
}
Expand All @@ -724,7 +738,7 @@ public static IOrderedCondition<TRuleType> NotResideInAssembly(string fullName)
{
return new SimpleCondition<TRuleType>(
type => !type.ResidesInAssembly(fullName),
obj => "does reside in " + obj.Assembly.FullName,
obj => DescribeAssemblyOf(obj),
"not reside in assembly with full name \"" + fullName + "\""
);
}
Expand All @@ -733,7 +747,7 @@ public static IOrderedCondition<TRuleType> NotResideInAssemblyMatching(string pa
{
return new SimpleCondition<TRuleType>(
type => !type.ResidesInAssemblyMatching(pattern),
obj => "does reside in " + obj.Assembly.FullName,
obj => DescribeAssemblyOf(obj),
"not reside in assembly with full name matching \"" + pattern + "\""
);
}
Expand All @@ -745,9 +759,9 @@ params System.Reflection.Assembly[] moreAssemblies
{
bool Condition(TRuleType ruleType, Architecture architecture)
{
return !ruleType.Assembly.Equals(architecture.GetAssemblyOfAssembly(assembly))
return !Equals(ruleType.Assembly, architecture.GetAssemblyOfAssembly(assembly))
&& !moreAssemblies.Any(asm =>
ruleType.Assembly.Equals(architecture.GetAssemblyOfAssembly(asm))
Equals(ruleType.Assembly, architecture.GetAssemblyOfAssembly(asm))
);
}

Expand All @@ -758,7 +772,7 @@ bool Condition(TRuleType ruleType, Architecture architecture)

return new OrderedArchitectureCondition<TRuleType>(
Condition,
(type, architecture) => "does reside in " + type.Assembly.FullName,
(type, architecture) => DescribeAssemblyOf(type),
description
);
}
Expand All @@ -781,7 +795,7 @@ bool Condition(TRuleType ruleType)

return new SimpleCondition<TRuleType>(
Condition,
type => "does reside in " + type.Assembly.FullName,
type => DescribeAssemblyOf(type),
description
);
}
Expand Down
155 changes: 155 additions & 0 deletions ArchUnitNETTests/Domain/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
using System.Linq;
using ArchUnitNET.Domain;
using ArchUnitNET.Domain.Extensions;
using ArchUnitNET.Fluent.Extensions;
using Xunit;
using static ArchUnitNET.Fluent.ArchRuleDefinition;

namespace ArchUnitNETTests.Domain
{
public class FunctionPointerTests
{
private static readonly Architecture Architecture =
StaticTestArchitectures.ArchUnitNETTestArchitecture;

private readonly IType _functionPointer;

public FunctionPointerTests()
{
_functionPointer = Architecture
.GetClassOfType(typeof(ClassWithFunctionPointerField))
.GetFieldMembers()
.Single()
.Type;
}

[Fact]
public void FunctionPointerHasNoNamespaceOrAssembly()
{
Assert.IsType<FunctionPointer>(_functionPointer);
Assert.Contains(_functionPointer, Architecture.ReferencedTypes);
Assert.Null(_functionPointer.Namespace);
Assert.Null(_functionPointer.Assembly);
}

[Fact]
public void NamespaceExtensionsReturnFalseForTypeWithoutNamespace()
{
Assert.False(_functionPointer.ResidesInNamespace("System"));
Assert.False(_functionPointer.ResidesInNamespaceMatching(".*"));
}

[Fact]
public void AssemblyExtensionsReturnFalseForTypeWithoutAssembly()
{
Assert.False(_functionPointer.ResidesInAssembly("System"));
Assert.False(_functionPointer.ResidesInAssemblyMatching(".*"));
}

[Fact]
public void NamespacePredicatesHandleTypesWithoutNamespace()
{
var namespaceName = typeof(ClassWithFunctionPointerField).Namespace;
Assert.DoesNotContain(
_functionPointer,
Types(true).That().ResideInNamespace(namespaceName).GetObjects(Architecture)
);
Assert.DoesNotContain(
_functionPointer,
Types(true).That().ResideInNamespaceMatching(".*").GetObjects(Architecture)
);
Assert.Contains(
_functionPointer,
Types(true).That().DoNotResideInNamespace(namespaceName).GetObjects(Architecture)
);
Assert.Contains(
_functionPointer,
Types(true).That().DoNotResideInNamespaceMatching(".*").GetObjects(Architecture)
);
}

[Fact]
public void AssemblyPredicatesHandleTypesWithoutAssembly()
{
var assembly = typeof(ClassWithFunctionPointerField).Assembly;
Assert.DoesNotContain(
_functionPointer,
Types(true).That().ResideInAssembly(assembly.FullName).GetObjects(Architecture)
);
Assert.DoesNotContain(
_functionPointer,
Types(true).That().ResideInAssemblyMatching(".*").GetObjects(Architecture)
);
Assert.Contains(
_functionPointer,
Types(true).That().DoNotResideInAssembly(assembly.FullName).GetObjects(Architecture)
);
}

[Fact]
public void NamespaceConditionsReportTypesWithoutNamespace()
{
var functionPointers = Types(true).That().Are(_functionPointer);
AssertViolation(
functionPointers.Should().ResideInNamespace("System"),
"does not reside in a namespace"
);
AssertViolation(
functionPointers.Should().ResideInNamespaceMatching(".*"),
"does not reside in a namespace"
);
Assert.True(
functionPointers
.Should()
.NotResideInNamespace("System")
.HasNoViolations(Architecture)
);
}

[Fact]
public void AssemblyConditionsReportTypesWithoutAssembly()
{
var assembly = typeof(ClassWithFunctionPointerField).Assembly;
var functionPointers = Types(true).That().Are(_functionPointer);
AssertViolation(
functionPointers.Should().ResideInAssembly(assembly.FullName),
"does not reside in an assembly"
);
AssertViolation(
functionPointers.Should().ResideInAssemblyMatching(".*"),
"does not reside in an assembly"
);
AssertViolation(
functionPointers.Should().ResideInAssembly(assembly),
"does not reside in an assembly"
);
AssertViolation(
functionPointers
.Should()
.ResideInAssembly(Architecture.GetAssemblyOfAssembly(assembly)),
"does not reside in an assembly"
);
Assert.True(
functionPointers
.Should()
.NotResideInAssembly(assembly)
.HasNoViolations(Architecture)
);
}

private static void AssertViolation(
ArchUnitNET.Fluent.IArchRule rule,
string expectedDescription
)
{
var result = rule.Evaluate(Architecture).Single();
Assert.False(result.Passed);
Assert.Contains(expectedDescription, result.Description);
}
}

public unsafe class ClassWithFunctionPointerField
{
public delegate* <int, void> FunctionPointerField;
}
}
2 changes: 1 addition & 1 deletion ArchUnitNETTests/Loader/ArchLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public void SameFullNameInMultipleAssemblies()

types = ArchUnitNETTestArchitecture
.ReferencedTypes.Where(type =>
type.Namespace.FullName == "DuplicateClassAcrossAssemblies"
type.Namespace?.FullName == "DuplicateClassAcrossAssemblies"
)
.ToList();
Assert.Equal(2, types.Count);
Expand Down
Loading