From 93d13f0f56d6e640adfb8b95f941da64b433540d Mon Sep 17 00:00:00 2001 From: Timo Springer Date: Fri, 19 Jul 2024 14:06:31 +0200 Subject: [PATCH 1/3] Added regex matching to slices. Grouped by appending all capture groups to string. --- .../Fluent/Slices/SliceRuleInitializer.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs b/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs index a6703b88..352966c0 100644 --- a/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs +++ b/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs @@ -6,6 +6,7 @@ // using System; +using System.Text.RegularExpressions; using ArchUnitNET.Domain; namespace ArchUnitNET.Fluent.Slices @@ -19,6 +20,58 @@ public SliceRuleInitializer(SliceRuleCreator ruleCreator) _ruleCreator = ruleCreator; } + /// + /// + /// Fullname is matched with regex. + /// Non matching Types are Ignored + /// Others are grouped by capture groups (append all captures to identifier string) + /// + /// + /// If true namespace fullname is matched. + /// Otherwise fullname of Type/Object is matched. + /// + /// + + public GivenSlices MatchingRegex( + string pattern, + bool match_namespace = false + ) + { + _ruleCreator.SetSliceAssignment( + new SliceAssignment( + t => + { + var match = Regex.Match(match_namespace ? t.Namespace.FullName : t.FullName, pattern); + if (!match.Success) return SliceIdentifier.Ignore(); + + string sliceName = ""; + if (match.Groups.Count == 1) + { + sliceName += match.Value; + } + for (int i = 1; i < match.Groups.Count; i++) + { + if(match.Groups[i].Captures.Count == 1) + { + sliceName += match.Groups[i]; + } + else + { + for(int j = 0; j < match.Groups[i].Captures.Count; j++) + { + sliceName += match.Groups[i].Captures[j]; + } + } + } + + return SliceIdentifier.Of(sliceName, null); + }, + "matching \"" + pattern + "\"" + ) + ); + return new GivenSlices(_ruleCreator); + } + /// /// /// From 0d62548a2592e84ab9050f4154b5d33fb775922c Mon Sep 17 00:00:00 2001 From: Timo Springer Date: Wed, 24 Jul 2024 13:38:10 +0200 Subject: [PATCH 2/3] Added tests for Slices with regex matching --- ArchUnitNETTests/Fluent/Slices/SlicesTests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs index 17148b4d..c186e62a 100644 --- a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs +++ b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs @@ -96,6 +96,38 @@ public void MatchingTest() ); } + [Fact] + public void MatchingRegexTest() + { + Assert.True( + SliceRuleDefinition + .Slices() + .MatchingRegex(@"(?:[^\.]*\.){2}([^\.]+).*", true) + .GetObjects(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture) + .ToList().Count > 5 + ); + + Assert.False( + SliceRuleDefinition + .Slices() + .MatchingRegex(@"TestAssembly\.Slices\.([^\.]+).*", true) + .GetObjects(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture) + .ToList() + .Select(slice => slice.Identifier.Identifier) + .Select(identifier => identifier.Contains(".")) + .Aggregate(false, (a, b) => a||b) + ); + + Assert.DoesNotContain("TestAssembly.Slices.Slice1", + SliceRuleDefinition + .Slices() + .MatchingRegex(@"TestAssembly\.Slices\.(?!Slice1)([^\.]+).*") + .GetObjects(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture) + .ToList() + .Select(slice => slice.Identifier.Identifier) + ); + } + [Fact] public void NotDependOnEachOtherTest() { From 86b8ac24e75dbc82ebd38f44fa73f0e0460d718f Mon Sep 17 00:00:00 2001 From: Timo Springer Date: Thu, 25 Jul 2024 16:01:29 +0200 Subject: [PATCH 3/3] Added Filtering using .Where() for GivenSlices --- ArchUnitNET/Fluent/Slices/GivenSlices.cs | 7 ++++ ArchUnitNET/Fluent/Slices/SliceRuleCreator.cs | 13 ++++++- ArchUnitNETTests/Fluent/Slices/SlicesTests.cs | 34 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ArchUnitNET/Fluent/Slices/GivenSlices.cs b/ArchUnitNET/Fluent/Slices/GivenSlices.cs index 8d1f5da0..44dbc6d9 100644 --- a/ArchUnitNET/Fluent/Slices/GivenSlices.cs +++ b/ArchUnitNET/Fluent/Slices/GivenSlices.cs @@ -5,6 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 // +using System; using System.Collections.Generic; using ArchUnitNET.Domain; @@ -31,5 +32,11 @@ public IEnumerable GetObjects(Architecture architecture) { return _ruleCreator.GetSlices(architecture); } + + public GivenSlices Where(Func filter) + { + _ruleCreator.AddFilter(filter); + return this; + } } } diff --git a/ArchUnitNET/Fluent/Slices/SliceRuleCreator.cs b/ArchUnitNET/Fluent/Slices/SliceRuleCreator.cs index 530b3554..7eb8cc25 100644 --- a/ArchUnitNET/Fluent/Slices/SliceRuleCreator.cs +++ b/ArchUnitNET/Fluent/Slices/SliceRuleCreator.cs @@ -22,6 +22,13 @@ private Func< > _evaluationFunc; private SliceAssignment _sliceAssignment; + private List> filters = new List>(); + + public void AddFilter(Func filter) + { + filters.Add(filter); + } + public SliceRuleCreator() { Description = "Slices"; @@ -71,9 +78,13 @@ public IEnumerable GetSlices(Architecture architecture) ); } - return _sliceAssignment + var slices = _sliceAssignment .Apply(architecture.Types) .Where(slice => !slice.Identifier.Ignored); + + filters.ForEach(filter => slices = slices.Where(filter)); + + return slices; } } } diff --git a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs index c186e62a..21be8ba6 100644 --- a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs +++ b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs @@ -128,6 +128,40 @@ public void MatchingRegexTest() ); } + [Fact] + public void WhereTest() + { + Assert.True( + SliceRuleDefinition + .Slices() + .Matching("TestAssembly.Slices.Slice3.(*)") + .Where(slice => slice.Identifier.Identifier.Contains("Group1")) + .Where(slice => true) + .GetObjects(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture) + .Count() == 1 + ); + + SliceRuleDefinition + .Slices() + .Matching("TestAssembly.Slices.(**)") + .Where(slice => !slice.Identifier.Identifier.Contains("Slice3")) + .Where(slice => !slice.Identifier.Identifier.Contains("Slice2")) + .Should() + .NotDependOnEachOther() + .Check(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture); + + Assert.True( + SliceRuleDefinition + .Slices() + .Matching("TestAssembly.Slices.(**)") + .Where(slice => !slice.Identifier.Identifier.Contains("Slice3")) + .Where(slice => !slice.Identifier.Identifier.Contains("Slice2")) + .Should() + .NotDependOnEachOther() + .HasNoViolations(StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture) + ); + } + [Fact] public void NotDependOnEachOtherTest() {