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
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ public interface IMethodMemberConditions<out TReturnType, out TRuleType>
TReturnType HaveReturnType(IObjectProvider<IType> types);
TReturnType HaveReturnType(Type type, params Type[] moreTypes);
TReturnType HaveReturnType(IEnumerable<Type> types);
TReturnType HaveAnyParameters();

//Negations

TReturnType BeNoConstructor();
TReturnType NotBeVirtual();
TReturnType NotHaveAnyParameters();

TReturnType NotBeCalledBy(IType firstType, params IType[] moreTypes);
TReturnType NotBeCalledBy(Type type, params Type[] moreTypes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1011,5 +1011,31 @@ bool Condition(MethodMember member)
description
);
}

/// <summary>
/// Selects method members that have any parameters
/// </summary>
/// <returns>A condition that can be applied to method members</returns>
public static ICondition<MethodMember> HaveAnyParameters()
{
return new SimpleCondition<MethodMember>(
method => method.Parameters.Any(),
"have any parameters",
"does not have any parameters"
);
}

/// <summary>
/// Selects method members that do not have any parameters (parameterless)
/// </summary>
/// <returns>A condition that can be applied to method members</returns>
public static ICondition<MethodMember> NotHaveAnyParameters()
{
return new SimpleCondition<MethodMember>(
method => !method.Parameters.Any(),
"not have any parameters",
"has parameters"
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,18 @@ public MethodMembersShouldConjunction NotHaveReturnType(IEnumerable<Type> types)
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.NotHaveReturnType(types));
return new MethodMembersShouldConjunction(_ruleCreator);
}


public MethodMembersShouldConjunction HaveAnyParameters()
{
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.HaveAnyParameters());
return new MethodMembersShouldConjunction(_ruleCreator);
}

public MethodMembersShouldConjunction NotHaveAnyParameters()
{
_ruleCreator.AddCondition(MethodMemberConditionsDefinition.NotHaveAnyParameters());
return new MethodMembersShouldConjunction(_ruleCreator);
}
}
}
2 changes: 1 addition & 1 deletion ArchUnitNETTests/ArchUnitNETTests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<LangVersion>default</LangVersion>
<Company>TNG Technology Consulting GmbH</Company>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using System.Linq;
using ArchUnitNET.Domain;
using ArchUnitNET.Loader;
using TestAssembly.Domain.Methods;
using Xunit;
using static ArchUnitNET.Fluent.ArchRuleDefinition;

namespace ArchUnitNETTests.Fluent.Syntax.Elements;

public class MethodParameterConditionTests
{
private static readonly Architecture Architecture =
new ArchLoader().LoadAssembly(typeof(ClassWithPrivateParameterlessConstructor).Assembly).Build();

[Fact]
public void HaveAnyParameters_MethodWithParameters_DoesNotViolate()
{
var rule = MethodMembers()
.That()
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
.And()
.HaveName("MethodWithParameters(System.String,System.Int32)")
.Should()
.HaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void HaveAnyParameters_MethodWithoutParameters_Violates()
{
var rule = MethodMembers()
.That()
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
.And()
.HaveName("MethodWithoutParameters()")
.Should()
.HaveAnyParameters();

Assert.False(rule.HasNoViolations(Architecture));

var evaluation = rule.Evaluate(Architecture);
var violations = evaluation.ToList();
Assert.Single(violations);
Assert.Contains("does not have any parameters", violations.First().Description);
}

[Fact]
public void NotHaveAnyParameters_MethodWithoutParameters_DoesNotViolate()
{
var rule = MethodMembers()
.That()
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
.And().HaveName("PrivateMethodWithoutParameters()")
.Should().NotHaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void NotHaveAnyParameters_MethodWithParameters_Violates()
{
var rule = MethodMembers()
.That().HaveName("MethodWithParameters(System.String,System.Int32)")
.Should().NotHaveAnyParameters();

Assert.False(rule.HasNoViolations(Architecture));

var evaluation = rule.Evaluate(Architecture);
var violations = evaluation.ToList();
Assert.Single(violations);
Assert.Contains("has parameters", violations.First().Description);
}

[Fact]
public void HaveAnyParameters_ConstructorWithParameters_DoesNotViolate()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithOnlyParameterizedConstructors)))
.And().AreConstructors()
.Should().HaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void HaveAnyParameters_ParameterlessConstructor_Violates()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPublicParameterlessConstructor)))
.And().AreConstructors()
.And().HaveName(".ctor()")
.Should().HaveAnyParameters();

Assert.False(rule.HasNoViolations(Architecture));
}

[Fact]
public void PrivateConstructorWithoutParameters_CompositeRule_DoesNotViolate()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPrivateParameterlessConstructor)))
.And().AreConstructors()
.And().ArePrivate()
.Should().NotHaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void PublicConstructorWithParameters_CompositeRule_DoesNotViolate()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPrivateParameterlessConstructor)))
.And().AreConstructors()
.And().ArePublic()
.Should().HaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void PrivateMethodWithoutParameters_DoesNotViolate()
{
var rule = MethodMembers()
.That()
.AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithMethods)))
.And()
.HaveName("PrivateMethodWithoutParameters()")
.And()
.ArePrivate()
.Should()
.NotHaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void SpecificClass_AllConstructorsHaveParameters_DoesNotViolate()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithOnlyParameterizedConstructors)))
.And().AreConstructors()
.Should().HaveAnyParameters();

Assert.True(rule.HasNoViolations(Architecture));
}

[Fact]
public void SpecificClass_HasParameterlessConstructor_Violates()
{
var rule = MethodMembers()
.That().AreDeclaredIn(Classes().That().HaveName(nameof(ClassWithPublicParameterlessConstructor)))
.And().AreConstructors()
.Should().HaveAnyParameters();

Assert.False(rule.HasNoViolations(Architecture));
}
}
73 changes: 73 additions & 0 deletions TestAssembly/Domain/Methods/MethodParameterTestClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace TestAssembly.Domain.Methods;

public class ClassWithPrivateParameterlessConstructor
{
// Private parameterless constructor
private ClassWithPrivateParameterlessConstructor()
{
}

// Public constructor with parameters
public ClassWithPrivateParameterlessConstructor(string value)
{
Value = value;
}

public string Value { get; set; }
}

public class ClassWithPublicParameterlessConstructor
{
// Public parameterless constructor
public ClassWithPublicParameterlessConstructor()
{
}

// Public constructor with parameters
public ClassWithPublicParameterlessConstructor(int number)
{
Number = number;
}

public int Number { get; set; }
}

public class ClassWithOnlyParameterizedConstructors
{
// Only constructors with parameters
public ClassWithOnlyParameterizedConstructors(string name)
{
Name = name;
}

public ClassWithOnlyParameterizedConstructors(string name, int id)
{
Name = name;
Id = id;
}

public string Name { get; set; }
public int Id { get; set; }
}

public class ClassWithMethods
{
public ClassWithMethods()
{
}

// Method without parameters
public void MethodWithoutParameters()
{
}

// Method with parameters
public void MethodWithParameters(string input, int count)
{
}

// Private method without parameters
private void PrivateMethodWithoutParameters()
{
}
}