Skip to content

Commit 35d3bb2

Browse files
committed
add rules: HaveParameterlessConstructor/ DoNotHaveParameterlessConstructor
1 parent de256a5 commit 35d3bb2

File tree

6 files changed

+136
-5
lines changed

6 files changed

+136
-5
lines changed

sources/NetArchTest/Condition_Special.cs

+22-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public ConditionList HaveMatchingTypeWithName(Func<TypeDefinition, string> getMa
126126

127127

128128
/// <summary>
129-
/// Selects types that have at least one public constructor.
129+
/// Selects types that have at least one instance public constructor.
130130
/// </summary>
131131
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
132132
public ConditionList HavePublicConstructor()
@@ -136,13 +136,33 @@ public ConditionList HavePublicConstructor()
136136
}
137137

138138
/// <summary>
139-
/// Selects types that do not have a public constructor.
139+
/// Selects types that do not have a instance public constructor.
140140
/// </summary>
141141
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
142142
public ConditionList NotHavePublicConstructor()
143143
{
144144
AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, false));
145145
return CreateConditionList();
146146
}
147+
148+
/// <summary>
149+
/// Selects types that have at least one instance parameterless constructor.
150+
/// </summary>
151+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
152+
public ConditionList HaveParameterlessConstructor()
153+
{
154+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveParameterlessConstructor(context, inputTypes, true));
155+
return CreateConditionList();
156+
}
157+
158+
/// <summary>
159+
/// Selects types that do not have a instance parameterless constructor.
160+
/// </summary>
161+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
162+
public ConditionList NotHaveParameterlessConstructor()
163+
{
164+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveParameterlessConstructor(context, inputTypes, false));
165+
return CreateConditionList();
166+
}
147167
}
148168
}

sources/NetArchTest/Functions/FunctionDelegates_Special.cs

+18-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,24 @@ internal static IEnumerable<TypeSpec> HavePublicConstructor(FunctionSequenceExec
153153

154154
static bool PublicConstructorExists(TypeDefinition definition)
155155
{
156-
return definition.GetConstructors().Any(c => c.IsPublic);
156+
return definition.GetConstructors().Any(c => c.IsPublic && !c.IsStatic);
157+
}
158+
}
159+
160+
internal static IEnumerable<TypeSpec> HaveParameterlessConstructor(FunctionSequenceExecutionContext context, IEnumerable<TypeSpec> input, bool condition)
161+
{
162+
if (condition)
163+
{
164+
return input.Where(c => ParameterlessConstructorExists(c.Definition));
165+
}
166+
else
167+
{
168+
return input.Where(c => !ParameterlessConstructorExists(c.Definition));
169+
}
170+
171+
static bool ParameterlessConstructorExists(TypeDefinition definition)
172+
{
173+
return definition.GetConstructors().Any(c => c.HasParameters == false && !c.IsStatic);
157174
}
158175
}
159176
}

sources/NetArchTest/Predicate_Special.cs

+21
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,26 @@ public PredicateList DoNotHavePublicConstructor()
104104
AddFunctionCall((context, inputTypes) => FunctionDelegates.HavePublicConstructor(context, inputTypes, false));
105105
return CreatePredicateList();
106106
}
107+
108+
109+
/// <summary>
110+
/// Selects types that have at least one instance parameterless constructor.
111+
/// </summary>
112+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
113+
public PredicateList HaveParameterlessConstructor()
114+
{
115+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveParameterlessConstructor(context, inputTypes, true));
116+
return CreatePredicateList();
117+
}
118+
119+
/// <summary>
120+
/// Selects types that do not have public instance parameterless constructor.
121+
/// </summary>
122+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
123+
public PredicateList DoNotHaveParameterlessConstructor()
124+
{
125+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveParameterlessConstructor(context, inputTypes, false));
126+
return CreatePredicateList();
127+
}
107128
}
108129
}

tests/NetArchTest.Rules.UnitTests/ConditionTests_Special.cs

+28
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,33 @@ public void NotHavePublicConstructor()
225225

226226
Assert.True(result.IsSuccessful);
227227
}
228+
229+
[Fact(DisplayName = "HaveParameterlessConstructor")]
230+
public void HaveParameterlessConstructor()
231+
{
232+
var result = fixture.Types
233+
.That()
234+
.ResideInNamespace("NetArchTest.TestStructure.Constructors")
235+
.And()
236+
.DoNotHaveNameEndingWith("Argument")
237+
.Should()
238+
.HaveParameterlessConstructor().GetResult();
239+
240+
Assert.True(result.IsSuccessful);
241+
}
242+
243+
[Fact(DisplayName = "NotHaveParameterlessConstructor")]
244+
public void NotHaveParameterlessConstructor()
245+
{
246+
var result = fixture.Types
247+
.That()
248+
.ResideInNamespace("NetArchTest.TestStructure.Constructors")
249+
.And()
250+
.HaveNameEndingWith("Argument")
251+
.Should()
252+
.NotHaveParameterlessConstructor().GetResult();
253+
254+
Assert.True(result.IsSuccessful);
255+
}
228256
}
229257
}

tests/NetArchTest.Rules.UnitTests/PredicateTests_Special.cs

+33-2
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,40 @@ public void DoNotHavePublicConstructor()
175175
.And()
176176
.DoNotHavePublicConstructor().GetReflectionTypes();
177177

178-
Assert.Equal(2, result.Count());
178+
Assert.Equal(3, result.Count());
179179
Assert.Contains<Type>(typeof(InternalConstructor), result);
180-
Assert.Contains<Type>(typeof(PrivateConstructor), result);
180+
Assert.Contains<Type>(typeof(PrivateConstructor), result);
181+
Assert.Contains<Type>(typeof(StaticConstructor), result);
182+
}
183+
184+
[Fact(DisplayName = "HaveParameterlessConstructor")]
185+
public void HaveParameterlessConstructor()
186+
{
187+
var result = fixture.Types
188+
.That()
189+
.ResideInNamespace(namespaceof<PublicConstructor>())
190+
.And()
191+
.HaveParameterlessConstructor().GetReflectionTypes();
192+
193+
Assert.Equal(5, result.Count());
194+
Assert.Contains<Type>(typeof(DefaultConstructor), result);
195+
Assert.Contains<Type>(typeof(InternalConstructor), result);
196+
Assert.Contains<Type>(typeof(PrivateConstructor), result);
197+
Assert.Contains<Type>(typeof(PublicConstructor), result);
198+
Assert.Contains<Type>(typeof(StaticConstructor), result);
199+
}
200+
201+
[Fact(DisplayName = "DoNotHaveParameterlessConstructor")]
202+
public void DoNotHaveParameterlessConstructor()
203+
{
204+
var result = fixture.Types
205+
.That()
206+
.ResideInNamespace(namespaceof<PublicConstructor>())
207+
.And()
208+
.DoNotHaveParameterlessConstructor().GetReflectionTypes();
209+
210+
Assert.Equal(1, result.Count());
211+
Assert.Contains<Type>(typeof(PublicConstructorOneArgument), result);
181212
}
182213
}
183214
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace NetArchTest.TestStructure.Constructors
6+
{
7+
internal class StaticConstructor
8+
{
9+
StaticConstructor()
10+
{
11+
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)