Skip to content

Commit fd7746f

Browse files
committed
Add HaveAnyParameters and NotHaveAnyParameters conditions for MethodMembers
- Add HaveAnyParameters() condition to check if methods have parameters - Add NotHaveAnyParameters() condition to check if methods have no parameters - Add corresponding methods to IMethodMemberConditions interface - Add comprehensive test coverage for both conditions - Test both regular methods and constructors - Verify failure descriptions in violation cases - Use correct IL method names (.ctor) for constructor tests - Remove redundant test cases that provided no additional value The new conditions enable architectural rules to enforce parameter requirements on methods and constructors, complementing existing method member conditions. Signed-off-by: Ahmed Mohamed El Ahmar <ahmedmohamedelahmar@gmail.com>
1 parent 1af36ff commit fd7746f

File tree

9 files changed

+273
-162
lines changed

9 files changed

+273
-162
lines changed

ArchUnitNET/Fluent/Syntax/Elements/Members/MethodMembers/IMethodMemberConditions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ public interface IMethodMemberConditions<out TReturnType, out TRuleType>
2828
TReturnType HaveReturnType(IObjectProvider<IType> types);
2929
TReturnType HaveReturnType(Type type, params Type[] moreTypes);
3030
TReturnType HaveReturnType(IEnumerable<Type> types);
31+
TReturnType HaveAnyParameters();
3132

3233
//Negations
3334

3435
TReturnType BeNoConstructor();
3536
TReturnType NotBeVirtual();
37+
TReturnType NotHaveAnyParameters();
3638

3739
TReturnType NotBeCalledBy(IType firstType, params IType[] moreTypes);
3840
TReturnType NotBeCalledBy(Type type, params Type[] moreTypes);

ArchUnitNET/Fluent/Syntax/Elements/Members/MethodMembers/MethodMemberConditionsDefinition.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,5 +1011,31 @@ bool Condition(MethodMember member)
10111011
description
10121012
);
10131013
}
1014+
1015+
/// <summary>
1016+
/// Selects method members that have any parameters
1017+
/// </summary>
1018+
/// <returns>A condition that can be applied to method members</returns>
1019+
public static ICondition<MethodMember> HaveAnyParameters()
1020+
{
1021+
return new SimpleCondition<MethodMember>(
1022+
method => method.Parameters.Any(),
1023+
"have any parameters",
1024+
"does not have any parameters"
1025+
);
1026+
}
1027+
1028+
/// <summary>
1029+
/// Selects method members that do not have any parameters (parameterless)
1030+
/// </summary>
1031+
/// <returns>A condition that can be applied to method members</returns>
1032+
public static ICondition<MethodMember> NotHaveAnyParameters()
1033+
{
1034+
return new SimpleCondition<MethodMember>(
1035+
method => !method.Parameters.Any(),
1036+
"not have any parameters",
1037+
"has parameters"
1038+
);
1039+
}
10141040
}
10151041
}

ArchUnitNET/Fluent/Syntax/Elements/Members/MethodMembers/MethodMembersShould.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,5 +297,18 @@ public MethodMembersShouldConjunction NotHaveReturnType(IEnumerable<Type> types)
297297
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.NotHaveReturnType(types));
298298
return new MethodMembersShouldConjunction(_ruleCreator);
299299
}
300+
301+
302+
public MethodMembersShouldConjunction HaveAnyParameters()
303+
{
304+
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.HaveAnyParameters());
305+
return new MethodMembersShouldConjunction(_ruleCreator);
306+
}
307+
308+
public MethodMembersShouldConjunction NotHaveAnyParameters()
309+
{
310+
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.NotHaveAnyParameters());
311+
return new MethodMembersShouldConjunction(_ruleCreator);
312+
}
300313
}
301314
}

ArchUnitNET/Fluent/Syntax/Elements/Types/Classes/ClassConditionsDefinition.cs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Linq;
22
using ArchUnitNET.Domain;
3-
using ArchUnitNET.Domain.Extensions;
43
using ArchUnitNET.Fluent.Conditions;
54

65
namespace ArchUnitNET.Fluent.Syntax.Elements.Types.Classes
@@ -44,16 +43,6 @@ public static ICondition<Class> BeImmutable()
4443
"is not immutable"
4544
);
4645
}
47-
48-
public static ICondition<Class> HavePrivateParameterlessConstructor()
49-
{
50-
return new SimpleCondition<Class>(
51-
cls => (cls.IsAbstract.HasValue && cls.IsAbstract.Value) || cls.GetConstructors().Any(c =>
52-
c.Visibility == Visibility.Private && !c.Parameters.Any()),
53-
"have private parameterless constructor",
54-
"does not have private parameterless constructor"
55-
);
56-
}
5746

5847
//Negations
5948

@@ -92,15 +81,5 @@ public static ICondition<Class> NotBeImmutable()
9281
"is immutable"
9382
);
9483
}
95-
96-
public static ICondition<Class> NotHavePrivateParameterlessConstructor()
97-
{
98-
return new SimpleCondition<Class>(
99-
cls => (cls.IsAbstract.HasValue && cls.IsAbstract.Value) || !cls.GetConstructors().Any(c =>
100-
c.Visibility == Visibility.Private && !c.Parameters.Any()),
101-
"not have private parameterless constructor",
102-
"has private parameterless constructor"
103-
);
104-
}
10584
}
10685
}

ArchUnitNET/Fluent/Syntax/Elements/Types/Classes/ClassesShould.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ public ClassesShouldConjunction BeImmutable()
3333
return new ClassesShouldConjunction(_ruleCreator);
3434
}
3535

36-
public ClassesShouldConjunction HavePrivateParameterlessConstructor()
37-
{
38-
_ruleCreator.AddCondition(ClassConditionsDefinition.HavePrivateParameterlessConstructor());
39-
return new ClassesShouldConjunction(_ruleCreator);
40-
}
41-
4236
//Negations
4337

4438
public ClassesShouldConjunction NotBeAbstract()
@@ -64,11 +58,5 @@ public ClassesShouldConjunction NotBeImmutable()
6458
_ruleCreator.AddCondition(ClassConditionsDefinition.NotBeImmutable());
6559
return new ClassesShouldConjunction(_ruleCreator);
6660
}
67-
68-
public ClassesShouldConjunction NotHavePrivateParameterlessConstructor()
69-
{
70-
_ruleCreator.AddCondition(ClassConditionsDefinition.NotHavePrivateParameterlessConstructor());
71-
return new ClassesShouldConjunction(_ruleCreator);
72-
}
7361
}
7462
}

ArchUnitNETTests/Fluent/Syntax/Elements/ClassPrivateConstructorConditionTests.cs

Lines changed: 0 additions & 73 deletions
This file was deleted.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using System.Linq;
2+
using ArchUnitNET.Domain;
3+
using ArchUnitNET.Loader;
4+
using TestAssembly.Domain.Methods;
5+
using Xunit;
6+
using static ArchUnitNET.Fluent.ArchRuleDefinition;
7+
8+
namespace ArchUnitNETTests.Fluent.Syntax.Elements;
9+
10+
public class MethodParameterConditionTests
11+
{
12+
private static readonly Architecture Architecture =
13+
new ArchLoader().LoadAssembly(typeof(ClassWithPrivateParameterlessConstructor).Assembly).Build();
14+
15+
[Fact]
16+
public void HaveAnyParameters_MethodWithParameters_DoesNotViolate()
17+
{
18+
var rule = MethodMembers()
19+
.That()
20+
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
21+
.And()
22+
.HaveName("MethodWithParameters(System.String,System.Int32)")
23+
.Should()
24+
.HaveAnyParameters();
25+
26+
Assert.True(rule.HasNoViolations(Architecture));
27+
}
28+
29+
[Fact]
30+
public void HaveAnyParameters_MethodWithoutParameters_Violates()
31+
{
32+
var rule = MethodMembers()
33+
.That()
34+
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
35+
.And()
36+
.HaveName("MethodWithoutParameters()")
37+
.Should()
38+
.HaveAnyParameters();
39+
40+
Assert.False(rule.HasNoViolations(Architecture));
41+
42+
var evaluation = rule.Evaluate(Architecture);
43+
var violations = evaluation.ToList();
44+
Assert.Single(violations);
45+
Assert.Contains("does not have any parameters", violations.First().Description);
46+
}
47+
48+
[Fact]
49+
public void NotHaveAnyParameters_MethodWithoutParameters_DoesNotViolate()
50+
{
51+
var rule = MethodMembers()
52+
.That()
53+
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
54+
.And().HaveName("PrivateMethodWithoutParameters()")
55+
.Should().NotHaveAnyParameters();
56+
57+
Assert.True(rule.HasNoViolations(Architecture));
58+
}
59+
60+
[Fact]
61+
public void NotHaveAnyParameters_MethodWithParameters_Violates()
62+
{
63+
var rule = MethodMembers()
64+
.That().HaveName("MethodWithParameters(System.String,System.Int32)")
65+
.Should().NotHaveAnyParameters();
66+
67+
Assert.False(rule.HasNoViolations(Architecture));
68+
69+
var evaluation = rule.Evaluate(Architecture);
70+
var violations = evaluation.ToList();
71+
Assert.Single(violations);
72+
Assert.Contains("has parameters", violations.First().Description);
73+
}
74+
75+
[Fact]
76+
public void HaveAnyParameters_ConstructorWithParameters_DoesNotViolate()
77+
{
78+
var rule = MethodMembers()
79+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithOnlyParameterizedConstructors)))
80+
.And().AreConstructors()
81+
.Should().HaveAnyParameters();
82+
83+
Assert.True(rule.HasNoViolations(Architecture));
84+
}
85+
86+
[Fact]
87+
public void HaveAnyParameters_ParameterlessConstructor_Violates()
88+
{
89+
var rule = MethodMembers()
90+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPublicParameterlessConstructor)))
91+
.And().AreConstructors()
92+
.And().HaveName(".ctor()")
93+
.Should().HaveAnyParameters();
94+
95+
Assert.False(rule.HasNoViolations(Architecture));
96+
}
97+
98+
[Fact]
99+
public void PrivateConstructorWithoutParameters_CompositeRule_DoesNotViolate()
100+
{
101+
var rule = MethodMembers()
102+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPrivateParameterlessConstructor)))
103+
.And().AreConstructors()
104+
.And().ArePrivate()
105+
.Should().NotHaveAnyParameters();
106+
107+
Assert.True(rule.HasNoViolations(Architecture));
108+
}
109+
110+
[Fact]
111+
public void PublicConstructorWithParameters_CompositeRule_DoesNotViolate()
112+
{
113+
var rule = MethodMembers()
114+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPrivateParameterlessConstructor)))
115+
.And().AreConstructors()
116+
.And().ArePublic()
117+
.Should().HaveAnyParameters();
118+
119+
Assert.True(rule.HasNoViolations(Architecture));
120+
}
121+
122+
[Fact]
123+
public void PrivateMethodWithoutParameters_DoesNotViolate()
124+
{
125+
var rule = MethodMembers()
126+
.That()
127+
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
128+
.And()
129+
.HaveName("PrivateMethodWithoutParameters()")
130+
.And()
131+
.ArePrivate()
132+
.Should()
133+
.NotHaveAnyParameters();
134+
135+
Assert.True(rule.HasNoViolations(Architecture));
136+
}
137+
138+
[Fact]
139+
public void SpecificClass_AllConstructorsHaveParameters_DoesNotViolate()
140+
{
141+
var rule = MethodMembers()
142+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithOnlyParameterizedConstructors)))
143+
.And().AreConstructors()
144+
.Should().HaveAnyParameters();
145+
146+
Assert.True(rule.HasNoViolations(Architecture));
147+
}
148+
149+
[Fact]
150+
public void SpecificClass_HasParameterlessConstructor_Violates()
151+
{
152+
var rule = MethodMembers()
153+
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPublicParameterlessConstructor)))
154+
.And().AreConstructors()
155+
.Should().HaveAnyParameters();
156+
157+
Assert.False(rule.HasNoViolations(Architecture));
158+
}
159+
}

0 commit comments

Comments
 (0)