diff --git a/ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs b/ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs
index b7822cdbd..baa0eac53 100644
--- a/ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs
+++ b/ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs
@@ -62,5 +62,25 @@ Architecture architecture
(arg.Item1, arg.Item2 is Type type ? architecture.GetITypeOfType(type) : arg.Item2)
);
}
+
+ ///
+ /// Creates a lookup function for the given collection of elements.
+ /// For smaller collections, it uses the Contains method of the collection directly.
+ /// For larger collections, it creates a HashSet for O(1) average time complexity lookups.
+ ///
+ ///
+ /// The type of elements in the collection.
+ ///
+ /// The collection of elements to create a lookup function for.
+ ///
+ /// A function that checks if an element is in the collection.
+ public static Func CreateLookupFn(ICollection elements)
+ {
+ if (elements.Count < 20)
+ {
+ return elements.Contains;
+ }
+ return new HashSet(elements).Contains;
+ }
}
}
diff --git a/ArchUnitNET/Domain/UnavailableType.cs b/ArchUnitNET/Domain/UnavailableType.cs
index f5dc33ef2..bbfe0f23c 100644
--- a/ArchUnitNET/Domain/UnavailableType.cs
+++ b/ArchUnitNET/Domain/UnavailableType.cs
@@ -42,7 +42,7 @@ public override string ToString()
return FullName;
}
- private bool Equals(Struct other)
+ private bool Equals(UnavailableType other)
{
return Equals(Type, other.Type);
}
diff --git a/ArchUnitNET/Fluent/ConditionManager.cs b/ArchUnitNET/Fluent/ConditionManager.cs
index b3b1147a9..fa8b70996 100644
--- a/ArchUnitNET/Fluent/ConditionManager.cs
+++ b/ArchUnitNET/Fluent/ConditionManager.cs
@@ -106,15 +106,34 @@ ICanBeEvaluated archRuleCreator
var filteredObjectsList = filteredObjects.ToList();
if (filteredObjectsList.IsNullOrEmpty() && !CheckEmpty())
{
- yield return new EvaluationResult(
- null,
- new StringIdentifier(""),
- false,
- "There are no objects matching the criteria",
- archRuleCreator,
- architecture
+ return new[]
+ {
+ new EvaluationResult(
+ null,
+ new StringIdentifier(""),
+ false,
+ "There are no objects matching the criteria",
+ archRuleCreator,
+ architecture
+ ),
+ };
+ }
+
+ if (_conditionElements.All(e => e.IsOrdered()))
+ {
+ var conditionResults = _conditionElements
+ .Select(conditionElement =>
+ conditionElement.Check(filteredObjectsList, architecture).ToList()
+ )
+ .ToList();
+ return filteredObjectsList.Select(
+ (t, i) =>
+ CreateEvaluationResult(
+ conditionResults.Select(results => results[i]),
+ architecture,
+ archRuleCreator
+ )
);
- yield break;
}
//rough heuristic - if we have small number of comparisons, we are fine with sequential search
@@ -129,14 +148,13 @@ ICanBeEvaluated archRuleCreator
)
.ToList();
- foreach (var t in filteredObjectsList)
- {
- yield return CreateEvaluationResult(
+ return filteredObjectsList.Select(t =>
+ CreateEvaluationResult(
FindResultsForObject(conditionResults, t),
architecture,
archRuleCreator
- );
- }
+ )
+ );
}
else
{
@@ -145,15 +163,13 @@ ICanBeEvaluated archRuleCreator
conditionElement.Check(filteredObjectsList, architecture).ToList()
)
.ToList();
-
- foreach (var t in filteredObjectsList)
- {
- yield return CreateEvaluationResult(
+ return filteredObjectsList.Select(t =>
+ CreateEvaluationResult(
FindResultsForObject(conditionResults, t),
architecture,
archRuleCreator
- );
- }
+ )
+ );
}
}
@@ -349,6 +365,11 @@ Architecture architecture
.Select(result => new ConditionElementResult(result, _logicalConjunction));
}
+ public bool IsOrdered()
+ {
+ return _condition is IOrderedCondition;
+ }
+
public bool CheckEmpty(bool currentResult)
{
if (_condition == null)
diff --git a/ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs b/ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs
index 39e2bad18..d588e1cc9 100644
--- a/ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs
+++ b/ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs
@@ -14,31 +14,6 @@ private readonly Func<
IEnumerable
> _condition;
- public ArchitectureCondition(
- Func condition,
- string description,
- string failDescription
- )
- {
- _condition = (ruleTypes, architecture) =>
- ruleTypes.Select(type => new ConditionResult(
- type,
- condition(type, architecture),
- failDescription
- ));
- Description = description;
- }
-
- public ArchitectureCondition(
- Func condition,
- string description
- )
- {
- _condition = (ruleTypes, architecture) =>
- ruleTypes.Select(type => condition(type, architecture));
- Description = description;
- }
-
public ArchitectureCondition(
Func, Architecture, IEnumerable> condition,
string description
@@ -48,21 +23,6 @@ string description
Description = description;
}
- public ArchitectureCondition(
- Func condition,
- Func dynamicFailDescription,
- string description
- )
- {
- _condition = (ruleTypes, architecture) =>
- ruleTypes.Select(type => new ConditionResult(
- type,
- condition(type, architecture),
- dynamicFailDescription(type, architecture)
- ));
- Description = description;
- }
-
public string Description { get; }
public IEnumerable Check(
diff --git a/ArchUnitNET/Fluent/Conditions/ExistsCondition.cs b/ArchUnitNET/Fluent/Conditions/ExistsCondition.cs
index 5eeb47ae8..6622e90a8 100644
--- a/ArchUnitNET/Fluent/Conditions/ExistsCondition.cs
+++ b/ArchUnitNET/Fluent/Conditions/ExistsCondition.cs
@@ -4,7 +4,7 @@
namespace ArchUnitNET.Fluent.Conditions
{
- public class ExistsCondition : ICondition
+ public class ExistsCondition : IOrderedCondition
where TRuleType : ICanBeAnalyzed
{
private readonly bool _valueIfExists;
diff --git a/ArchUnitNET/Fluent/Conditions/IOrderedCondition.cs b/ArchUnitNET/Fluent/Conditions/IOrderedCondition.cs
new file mode 100644
index 000000000..f2e6b17b0
--- /dev/null
+++ b/ArchUnitNET/Fluent/Conditions/IOrderedCondition.cs
@@ -0,0 +1,7 @@
+using ArchUnitNET.Domain;
+
+namespace ArchUnitNET.Fluent.Conditions
+{
+ public interface IOrderedCondition : ICondition
+ where TRuleType : ICanBeAnalyzed { }
+}
diff --git a/ArchUnitNET/Fluent/Conditions/OrderedArchitectureCondition.cs b/ArchUnitNET/Fluent/Conditions/OrderedArchitectureCondition.cs
new file mode 100644
index 000000000..0dc3b9d0e
--- /dev/null
+++ b/ArchUnitNET/Fluent/Conditions/OrderedArchitectureCondition.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ArchUnitNET.Domain;
+
+namespace ArchUnitNET.Fluent.Conditions
+{
+ public class OrderedArchitectureCondition
+ : ArchitectureCondition,
+ IOrderedCondition
+ where TRuleType : ICanBeAnalyzed
+ {
+ public OrderedArchitectureCondition(
+ Func condition,
+ string description,
+ string failDescription
+ )
+ : base(
+ (ruleTypes, architecture) =>
+ ruleTypes.Select(type => new ConditionResult(
+ type,
+ condition(type, architecture),
+ failDescription
+ )),
+ description
+ ) { }
+
+ public OrderedArchitectureCondition(
+ Func condition,
+ Func dynamicFailDescription,
+ string description
+ )
+ : base(
+ (ruleTypes, architecture) =>
+ ruleTypes.Select(type => new ConditionResult(
+ type,
+ condition(type, architecture),
+ dynamicFailDescription(type, architecture)
+ )),
+ description
+ ) { }
+
+ public OrderedArchitectureCondition(
+ Func condition,
+ string description
+ )
+ : base(
+ (ruleTypes, architecture) =>
+ ruleTypes.Select(type => condition(type, architecture)),
+ description
+ ) { }
+
+ public OrderedArchitectureCondition(
+ Func, Architecture, IEnumerable> condition,
+ string description
+ )
+ : base(condition, description) { }
+ }
+}
diff --git a/ArchUnitNET/Fluent/Conditions/SimpleCondition.cs b/ArchUnitNET/Fluent/Conditions/SimpleCondition.cs
index 871334a5f..fc7ca1502 100644
--- a/ArchUnitNET/Fluent/Conditions/SimpleCondition.cs
+++ b/ArchUnitNET/Fluent/Conditions/SimpleCondition.cs
@@ -5,7 +5,7 @@
namespace ArchUnitNET.Fluent.Conditions
{
- public class SimpleCondition : ICondition
+ public class SimpleCondition : IOrderedCondition
where TRuleType : ICanBeAnalyzed
{
private readonly Func _condition;
diff --git a/ArchUnitNET/Fluent/Syntax/Elements/ObjectConditionsDefinition.cs b/ArchUnitNET/Fluent/Syntax/Elements/ObjectConditionsDefinition.cs
index 52cb0b59d..b4e7f928b 100644
--- a/ArchUnitNET/Fluent/Syntax/Elements/ObjectConditionsDefinition.cs
+++ b/ArchUnitNET/Fluent/Syntax/Elements/ObjectConditionsDefinition.cs
@@ -5,6 +5,7 @@
using ArchUnitNET.Domain.Extensions;
using ArchUnitNET.Fluent.Conditions;
using JetBrains.Annotations;
+using static ArchUnitNET.Domain.Extensions.EnumerableExtensions;
using static ArchUnitNET.Domain.Visibility;
using Attribute = ArchUnitNET.Domain.Attribute;
@@ -26,28 +27,29 @@ IEnumerable Condition(
Architecture architecture
)
{
- var objectList = objectProvider.GetObjects(architecture).ToList();
- var typeList = ruleTypes.ToList();
- var passedObjects = objectList.OfType().Intersect(typeList).ToList();
- foreach (var failedObject in typeList.Except(passedObjects))
- {
- yield return new ConditionResult(
- failedObject,
- false,
- (sizedObjectProvider != null && sizedObjectProvider.Count == 0)
- ? "does exist"
- : "is not " + objectProvider.Description
- );
- }
-
- foreach (var passedObject in passedObjects)
+ var isAllowedObject = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (isAllowedObject(ruleType))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ yield return new ConditionResult(
+ ruleType,
+ false,
+ (sizedObjectProvider != null && sizedObjectProvider.Count == 0)
+ ? "does exist"
+ : "is not " + objectProvider.Description
+ );
+ }
}
}
-
var description = objectProvider.FormatDescription("not exist", "be", "be");
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition CallAny(IObjectProvider objectProvider)
@@ -57,27 +59,28 @@ IEnumerable Condition(
Architecture architecture
)
{
- var methodList = objectProvider.GetObjects(architecture).ToList();
- var typeList = ruleTypes.ToList();
- var passedObjects = typeList
- .Where(type => type.GetCalledMethods().Intersect(methodList).Any())
- .ToList();
- foreach (var failedObject in typeList.Except(passedObjects))
- {
- var calledMethods = failedObject.GetCalledMethods().ToList();
- var dynamicFailDescription =
- calledMethods.Count == 0
- ? "does not call any methods"
- : "only calls "
- + string.Join(
- " and ",
- calledMethods.Select(method => $"\"{method.FullName}\"")
- );
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
- foreach (var passedObject in passedObjects)
+ var isRequiredMethod = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (ruleType.GetCalledMethods().Any(isRequiredMethod))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var calledMethods = ruleType.GetCalledMethods().ToList();
+ var dynamicFailDescription =
+ calledMethods.Count == 0
+ ? "does not call any methods"
+ : "only calls "
+ + string.Join(
+ " and ",
+ calledMethods.Select(method => $"\"{method.FullName}\"")
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
+ }
}
}
var description = objectProvider.FormatDescription(
@@ -85,7 +88,7 @@ Architecture architecture
"call",
"call any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition DependOnAny(IObjectProvider objectProvider)
@@ -95,27 +98,28 @@ IEnumerable Condition(
Architecture architecture
)
{
- var typeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var passedObjects = ruleTypeList
- .Where(type => type.GetTypeDependencies().Intersect(typeList).Any())
- .ToList();
- foreach (var failedObject in ruleTypeList.Except(passedObjects))
- {
- var dependants = failedObject.GetTypeDependencies(architecture).ToList();
- var dynamicFailDescription =
- dependants.Count == 0
- ? "does not depend on any type"
- : "only depends on "
- + string.Join(
- " and ",
- dependants.Select(type => $"\"{type.FullName}\"")
- );
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
- foreach (var passedObject in passedObjects)
+ var isRequiredDependency = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (ruleType.GetTypeDependencies().Any(isRequiredDependency))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var dependants = ruleType.GetTypeDependencies(architecture).ToList();
+ var dynamicFailDescription =
+ dependants.Count == 0
+ ? "does not depend on any type"
+ : "only depends on "
+ + string.Join(
+ " and ",
+ dependants.Select(type => $"\"{type.FullName}\"")
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
+ }
}
}
var description = objectProvider.FormatDescription(
@@ -123,7 +127,7 @@ Architecture architecture
"depend on",
"depend on any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition FollowCustomCondition(
@@ -150,38 +154,37 @@ IEnumerable Condition(
Architecture architecture
)
{
- var typeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var failedObjects = ruleTypeList
- .Where(type => type.GetTypeDependencies(architecture).Except(typeList).Any())
- .ToList();
- foreach (var failedObject in failedObjects)
+ var isAllowedDependency = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- var dynamicFailDescription = "does depend on";
- var first = true;
- foreach (var type in failedObject.GetTypeDependencies().Except(typeList))
+ if (ruleType.GetTypeDependencies(architecture).All(isAllowedDependency))
{
- dynamicFailDescription += first
- ? " " + type.FullName
- : " and " + type.FullName;
- first = false;
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var dynamicFailDescription =
+ "does depend on "
+ + string.Join(
+ " and ",
+ ruleType
+ .GetTypeDependencies()
+ .Where(t => !isAllowedDependency(t))
+ .Distinct()
+ .Select(t => t.FullName)
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
}
-
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
-
- foreach (var passedObject in ruleTypeList.Except(failedObjects))
- {
- yield return new ConditionResult(passedObject, true);
}
}
-
var description = objectProvider.FormatDescription(
"have no dependencies",
"only depend on",
"only depend on"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveAnyAttributes(
@@ -193,37 +196,36 @@ IEnumerable Condition(
Architecture architecture
)
{
- var attributeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var passedObjects = ruleTypeList
- .Where(type => type.Attributes.Intersect(attributeList).Any())
- .ToList();
- foreach (var failedObject in ruleTypeList.Except(passedObjects))
- {
- var attributes = failedObject.Attributes.ToList();
- var failDescription =
- attributes.Count == 0
- ? "does not have any attributes"
- : "only has attributes "
- + string.Join(
- " and ",
- attributes.Select(attribute => $"\"{attribute.FullName}\"")
- );
- yield return new ConditionResult(failedObject, false, failDescription);
- }
-
- foreach (var passedObject in passedObjects)
+ var isRequiredAttribute = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (ruleType.Attributes.Any(isRequiredAttribute))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var attributes = ruleType.Attributes.ToList();
+ var dynamicFailDescription =
+ attributes.Count == 0
+ ? "does not have any attributes"
+ : "only has attributes "
+ + string.Join(
+ " and ",
+ attributes.Select(attribute => $"\"{attribute.FullName}\"")
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
+ }
}
}
-
var description = objectProvider.FormatDescription(
"have any of no attributes (impossible)",
"have",
"have any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition OnlyHaveAttributes(
@@ -235,38 +237,35 @@ IEnumerable Condition(
Architecture architecture
)
{
- var attributeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var failedObjects = ruleTypeList
- .Where(type => type.Attributes.Except(attributeList).Any())
- .ToList();
- foreach (var failedObject in failedObjects)
+ var isAllowedAttribute = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- var dynamicFailDescription = "does have attribute";
- var first = true;
- foreach (var attribute in failedObject.Attributes.Except(attributeList))
+ if (ruleType.Attributes.All(isAllowedAttribute))
{
- dynamicFailDescription += first
- ? " " + attribute.FullName
- : " and " + attribute.FullName;
- first = false;
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var dynamicFailDescription =
+ "does have attribute "
+ + string.Join(
+ " and ",
+ ruleType
+ .Attributes.Where(attr => !isAllowedAttribute(attr))
+ .Select(a => a.FullName)
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
}
-
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
-
- foreach (var passedObject in ruleTypeList.Except(failedObjects))
- {
- yield return new ConditionResult(passedObject, true);
}
}
-
var description = objectProvider.FormatDescription(
"have no attributes",
"only have",
"only have any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveAnyAttributesWithArguments(
@@ -324,7 +323,7 @@ Architecture architecture
"have any attributes with argument",
"have any attributes with arguments"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveAttributeWithArguments(
@@ -388,7 +387,7 @@ Architecture architecture
$"have attribute \"{attributeFullName}\" with argument",
$"have attribute \"{attributeFullName}\" with arguments"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveAnyAttributesWithNamedArguments(
@@ -449,7 +448,7 @@ Architecture architecture
"have any attributes with named arguments",
elementDescription: arg => $"\"{arg.Item1}={arg.Item2}\""
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveAttributeWithNamedArguments(
@@ -516,7 +515,7 @@ Architecture architecture
$"have attribute \"{attributeFullName}\" with named arguments",
elementDescription: arg => $"\"{arg.Item1}={arg.Item2}\""
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition HaveName(string name)
@@ -760,30 +759,30 @@ IEnumerable Condition(
Architecture architecture
)
{
- var objectList = objectProvider.GetObjects(architecture).ToList();
- var typeList = ruleTypes.ToList();
- var failedObjects = objectList.OfType().Intersect(typeList).ToList();
- foreach (var failedObject in failedObjects)
- {
- yield return new ConditionResult(
- failedObject,
- false,
- "is " + objectProvider.Description
- );
- }
-
- foreach (var passedObject in typeList.Except(failedObjects))
+ var objects = objectProvider.GetObjects(architecture).ToList();
+ var isForbiddenObject = CreateLookupFn(objects);
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (!isForbiddenObject(ruleType))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ yield return new ConditionResult(
+ ruleType,
+ false,
+ objects.Count == 0 ? "does exist" : "is " + objectProvider.Description
+ );
+ }
}
}
-
var description = objectProvider.FormatDescription(
"not be any of no objects (always true)",
"not be",
"not be"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotCallAny(IObjectProvider objectProvider)
@@ -793,32 +792,33 @@ IEnumerable Condition(
Architecture architecture
)
{
- var methodList = objectProvider.GetObjects(architecture).ToList();
- var typeList = ruleTypes.ToList();
- var failedObjects = typeList
- .Where(type => type.GetCalledMethods().Intersect(methodList).Any())
- .ToList();
- foreach (var failedObject in failedObjects)
- {
- var calledMethods = failedObject
- .GetCalledMethods()
- .Intersect(methodList)
- .Select(method => $"\"{method.FullName}\"");
- var dynamicFailDescription = "does call " + string.Join(" and ", calledMethods);
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
- foreach (var passedObject in typeList.Except(failedObjects))
+ var isForbiddenMethod = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (!ruleType.GetCalledMethods().Any(isForbiddenMethod))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var calledMethods = ruleType
+ .GetCalledMethods()
+ .Where(isForbiddenMethod)
+ .Select(method => $"\"{method.FullName}\"");
+ var dynamicFailDescription =
+ "does call " + string.Join(" and ", calledMethods);
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
+ }
}
}
-
var description = objectProvider.FormatDescription(
"not call any of no methods (always true)",
"not call",
"not call any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotDependOnAny(IObjectProvider objectProvider)
@@ -828,33 +828,34 @@ IEnumerable Condition(
Architecture architecture
)
{
- var typeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var failedObjects = ruleTypeList
- .Where(type => type.GetTypeDependencies().Intersect(typeList).Any())
- .ToList();
- foreach (var failedObject in failedObjects)
- {
- var dependants = failedObject
- .GetTypeDependencies()
- .Intersect(typeList)
- .Select(type => $"\"{type.FullName}\"");
- var dynamicFailDescription =
- "does depend on " + string.Join(" and ", dependants);
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
- foreach (var passedObject in ruleTypeList.Except(failedObjects))
+ var isForbiddenDependency = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- yield return new ConditionResult(passedObject, true);
+ if (!ruleType.GetTypeDependencies().Any(isForbiddenDependency))
+ {
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var dependants = ruleType
+ .GetTypeDependencies()
+ .Where(isForbiddenDependency)
+ .Distinct()
+ .Select(type => $"\"{type.FullName}\"");
+ var dynamicFailDescription =
+ "does depend on " + string.Join(" and ", dependants);
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
+ }
}
}
-
var description = objectProvider.FormatDescription(
"not depend on any of no types (always true)",
"not depend on",
"not depend on any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveAnyAttributes(
@@ -866,38 +867,34 @@ IEnumerable Condition(
Architecture architecture
)
{
- var attributeList = objectProvider.GetObjects(architecture).ToList();
- var ruleTypeList = ruleTypes.ToList();
- var failedObjects = ruleTypeList
- .Where(type => type.Attributes.Intersect(attributeList).Any())
- .ToList();
- foreach (var failedObject in failedObjects)
+ var isForbiddenAttribute = CreateLookupFn(
+ objectProvider.GetObjects(architecture).ToList()
+ );
+ foreach (var ruleType in ruleTypes)
{
- var dynamicFailDescription = "does have attribute";
- var first = true;
- foreach (var attribute in failedObject.Attributes.Intersect(attributeList))
+ if (!ruleType.Attributes.Any(isForbiddenAttribute))
{
- dynamicFailDescription += first
- ? " " + attribute.FullName
- : " and " + attribute.FullName;
- first = false;
+ yield return new ConditionResult(ruleType, true);
+ }
+ else
+ {
+ var attributes = ruleType.Attributes.Where(isForbiddenAttribute).ToList();
+ var dynamicFailDescription =
+ "does have attribute "
+ + string.Join(
+ " and ",
+ attributes.Select(attribute => attribute.FullName)
+ );
+ yield return new ConditionResult(ruleType, false, dynamicFailDescription);
}
-
- yield return new ConditionResult(failedObject, false, dynamicFailDescription);
- }
-
- foreach (var passedObject in ruleTypeList.Except(failedObjects))
- {
- yield return new ConditionResult(passedObject, true);
}
}
-
var description = objectProvider.FormatDescription(
"not have any of no attributes (always true)",
"not have",
"not have any"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveAnyAttributesWithArguments(
@@ -956,7 +953,7 @@ Architecture architecture
"not have any attributes with argument",
"not have any attributes with arguments"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveAttributeWithArguments(
@@ -1004,7 +1001,7 @@ Architecture architecture
$"not have attribute \"{attributeFullName}\" with argument",
$"not have attribute \"{attributeFullName}\" with arguments"
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveAnyAttributesWithNamedArguments(
@@ -1066,7 +1063,7 @@ Architecture architecture
"not have any attributes with named arguments",
elementDescription: arg => $"\"{arg.Item1}={arg.Item2}\""
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveAttributeWithNamedArguments(
@@ -1120,7 +1117,7 @@ Architecture architecture
$"not have attribute \"{attributeFullName}\" with named arguments",
elementDescription: arg => $"\"{arg.Item1}={arg.Item2}\""
);
- return new ArchitectureCondition(Condition, description);
+ return new OrderedArchitectureCondition(Condition, description);
}
public static ICondition NotHaveName(string name)
diff --git a/ArchUnitNET/Fluent/Syntax/Elements/Types/TypeConditionsDefinition.cs b/ArchUnitNET/Fluent/Syntax/Elements/Types/TypeConditionsDefinition.cs
index c4b1eb3d3..bfe0a5f6f 100644
--- a/ArchUnitNET/Fluent/Syntax/Elements/Types/TypeConditionsDefinition.cs
+++ b/ArchUnitNET/Fluent/Syntax/Elements/Types/TypeConditionsDefinition.cs
@@ -625,7 +625,7 @@ bool Condition(TRuleType ruleType, Architecture architecture)
(current, asm) => current + " or \"" + asm.FullName + "\""
);
- return new ArchitectureCondition(
+ return new OrderedArchitectureCondition(
Condition,
(type, architecture) => "does reside in " + type.Assembly.FullName,
description
@@ -1247,7 +1247,7 @@ bool Condition(TRuleType ruleType, Architecture architecture)
(current, asm) => current + " or \"" + asm.FullName + "\""
);
- return new ArchitectureCondition(
+ return new OrderedArchitectureCondition(
Condition,
(type, architecture) => "does reside in " + type.Assembly.FullName,
description