diff --git a/sources/NetArchTest/Condition_Special.cs b/sources/NetArchTest/Condition_Special.cs index bff471a..ccf864f 100644 --- a/sources/NetArchTest/Condition_Special.cs +++ b/sources/NetArchTest/Condition_Special.cs @@ -123,5 +123,26 @@ public ConditionList HaveMatchingTypeWithName(Func getMa AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveMatchingTypeWithName(context, inputTypes, getMatchingTypeName, true)); return CreateConditionList(); } + + + /// + /// Selects types that have at least one public constructor. + /// + /// An updated set of conditions that can be applied to a list of types. + public ConditionList HavePublicConstructor() + { + AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, true)); + return CreateConditionList(); + } + + /// + /// Selects types that do not have a public constructor. + /// + /// An updated set of conditions that can be applied to a list of types. + public ConditionList NotHavePublicConstructor() + { + AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, false)); + return CreateConditionList(); + } } } \ No newline at end of file diff --git a/sources/NetArchTest/Functions/FunctionDelegates_Special.cs b/sources/NetArchTest/Functions/FunctionDelegates_Special.cs index 48e83aa..8f162b1 100644 --- a/sources/NetArchTest/Functions/FunctionDelegates_Special.cs +++ b/sources/NetArchTest/Functions/FunctionDelegates_Special.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Mono.Cecil; +using Mono.Cecil.Rocks; using NetArchTest.Assemblies; using NetArchTest.RuleEngine; @@ -137,5 +138,23 @@ internal static IEnumerable HaveMatchingTypeWithName(FunctionSequenceE return input.Where(c => !exisitingTypes.Contains(getMatchingTypeName(c.Definition))); } } + + + internal static IEnumerable HavePublicConstructor(FunctionSequenceExecutionContext context, IEnumerable input, bool condition) + { + if (condition) + { + return input.Where(c => PublicConstructorExists(c.Definition)); + } + else + { + return input.Where(c => !PublicConstructorExists(c.Definition)); + } + + static bool PublicConstructorExists(TypeDefinition definition) + { + return definition.GetConstructors().Any(c => c.IsPublic); + } + } } } diff --git a/sources/NetArchTest/Predicate_Special.cs b/sources/NetArchTest/Predicate_Special.cs index e188c5a..c3be647 100644 --- a/sources/NetArchTest/Predicate_Special.cs +++ b/sources/NetArchTest/Predicate_Special.cs @@ -83,5 +83,26 @@ public PredicateList OnlyHaveNonNullableMembers() AddFunctionCall(x => FunctionDelegates.OnlyHaveNonNullableMembers(x, true)); return CreatePredicateList(); } + + + /// + /// Selects types that have at least one public instance constructor. + /// + /// An updated set of conditions that can be applied to a list of types. + public PredicateList HavePublicConstructor() + { + AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, true)); + return CreatePredicateList(); + } + + /// + /// Selects types that do not have public instance constructor. + /// + /// An updated set of conditions that can be applied to a list of types. + public PredicateList DoNotHavePublicConstructor() + { + AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, false)); + return CreatePredicateList(); + } } } \ No newline at end of file diff --git a/tests/NetArchTest.Rules.UnitTests/ConditionTests_Special.cs b/tests/NetArchTest.Rules.UnitTests/ConditionTests_Special.cs index 49e51a3..aa00bde 100644 --- a/tests/NetArchTest.Rules.UnitTests/ConditionTests_Special.cs +++ b/tests/NetArchTest.Rules.UnitTests/ConditionTests_Special.cs @@ -197,5 +197,33 @@ public void HaveMatchingTypeWithName_ShouldNot() Assert.True(result.IsSuccessful); } + + [Fact(DisplayName = "HavePublicConstructor")] + public void HavePublicConstructor() + { + var result = fixture.Types + .That() + .ResideInNamespace("NetArchTest.TestStructure.Constructors") + .And() + .HaveNameStartingWith("Public", "Default") + .Should() + .HavePublicConstructor().GetResult(); + + Assert.True(result.IsSuccessful); + } + + [Fact(DisplayName = "DoNotHavePublicConstructor")] + public void NotHavePublicConstructor() + { + var result = fixture.Types + .That() + .ResideInNamespace("NetArchTest.TestStructure.Constructors") + .And() + .DoNotHaveNameStartingWith("Public", "Default") + .Should() + .NotHavePublicConstructor().GetResult(); + + Assert.True(result.IsSuccessful); + } } } diff --git a/tests/NetArchTest.Rules.UnitTests/PredicateTests_Special.cs b/tests/NetArchTest.Rules.UnitTests/PredicateTests_Special.cs index 782687e..7732b18 100644 --- a/tests/NetArchTest.Rules.UnitTests/PredicateTests_Special.cs +++ b/tests/NetArchTest.Rules.UnitTests/PredicateTests_Special.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using NetArchTest.TestStructure.Constructors; using NetArchTest.TestStructure.Mutability; using NetArchTest.TestStructure.Nullable; using NetArchTest.TestStructure.Stateless; @@ -148,5 +149,35 @@ public void OnlyHaveNonNullableMembers() Assert.Contains(typeof(NonNullableClass3), result); Assert.Contains(typeof(NonNullableClass4), result); } + + + [Fact(DisplayName = "HavePublicConstructor")] + public void HavePublicConstructor() + { + var result = fixture.Types + .That() + .ResideInNamespace(namespaceof()) + .And() + .HavePublicConstructor().GetReflectionTypes(); + + Assert.Equal(3, result.Count()); + Assert.Contains(typeof(DefaultConstructor), result); + Assert.Contains(typeof(PublicConstructor), result); + Assert.Contains(typeof(PublicConstructorOneArgument), result); + } + + [Fact(DisplayName = "DoNotHavePublicConstructor")] + public void DoNotHavePublicConstructor() + { + var result = fixture.Types + .That() + .ResideInNamespace(namespaceof()) + .And() + .DoNotHavePublicConstructor().GetReflectionTypes(); + + Assert.Equal(2, result.Count()); + Assert.Contains(typeof(InternalConstructor), result); + Assert.Contains(typeof(PrivateConstructor), result); + } } } diff --git a/tests/NetArchTest.TestStructure/Constructors/DefaultConstructor.cs b/tests/NetArchTest.TestStructure/Constructors/DefaultConstructor.cs new file mode 100644 index 0000000..39752b0 --- /dev/null +++ b/tests/NetArchTest.TestStructure/Constructors/DefaultConstructor.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NetArchTest.TestStructure.Constructors +{ + internal class DefaultConstructor + { + } +} diff --git a/tests/NetArchTest.TestStructure/Constructors/InternalConstructor.cs b/tests/NetArchTest.TestStructure/Constructors/InternalConstructor.cs new file mode 100644 index 0000000..7e79539 --- /dev/null +++ b/tests/NetArchTest.TestStructure/Constructors/InternalConstructor.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NetArchTest.TestStructure.Constructors +{ + internal class InternalConstructor + { + internal InternalConstructor() + { + + } + } +} diff --git a/tests/NetArchTest.TestStructure/Constructors/PrivateConstructor.cs b/tests/NetArchTest.TestStructure/Constructors/PrivateConstructor.cs new file mode 100644 index 0000000..5d8764c --- /dev/null +++ b/tests/NetArchTest.TestStructure/Constructors/PrivateConstructor.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NetArchTest.TestStructure.Constructors +{ + internal class PrivateConstructor + { + + + private PrivateConstructor() + { + + } + } +} diff --git a/tests/NetArchTest.TestStructure/Constructors/PublicConstructor.cs b/tests/NetArchTest.TestStructure/Constructors/PublicConstructor.cs new file mode 100644 index 0000000..53ffa73 --- /dev/null +++ b/tests/NetArchTest.TestStructure/Constructors/PublicConstructor.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NetArchTest.TestStructure.Constructors +{ + internal class PublicConstructor + { + public PublicConstructor() + { + + } + } +} diff --git a/tests/NetArchTest.TestStructure/Constructors/PublicConstructorOneArgument.cs b/tests/NetArchTest.TestStructure/Constructors/PublicConstructorOneArgument.cs new file mode 100644 index 0000000..5c25992 --- /dev/null +++ b/tests/NetArchTest.TestStructure/Constructors/PublicConstructorOneArgument.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NetArchTest.TestStructure.Constructors +{ + internal class PublicConstructorOneArgument + { + + + public PublicConstructorOneArgument(int a) + { + + } + } +}