diff --git a/ArchUnitNET/Domain/PlantUml/Export/PlantUmlDiagram.cs b/ArchUnitNET/Domain/PlantUml/Export/PlantUmlDiagram.cs index 7d0e01167..a2af58e78 100644 --- a/ArchUnitNET/Domain/PlantUml/Export/PlantUmlDiagram.cs +++ b/ArchUnitNET/Domain/PlantUml/Export/PlantUmlDiagram.cs @@ -57,13 +57,14 @@ public string GetPlantUmlString(RenderOptions renderOptions) /// /// /// A slice is identified in the diagram by its name, but not every name is a valid id. - /// PlantUML rejects "[Inner] as App.Outer+Inner" and "Container(App.Orders.*.Http, ...)" - /// as syntax errors, and slice names can contain such characters: SlicedBy names slices - /// after type names such as "Outer+Inner" or "List`1", and a hand-built SliceIdentifier - /// can be called anything. No character that a namespace cannot contain works in their - /// place either, so the id is made from the name with those characters replaced by "_", - /// and suffixed until it clashes with no other name in the diagram. The name itself stays - /// the label, and slices whose names are valid ids keep them. + /// PlantUML rejects "[Inner] as App.Outer+Inner" and "Container(Slice Orders, ...)" as + /// syntax errors, and slice names can contain such characters: every slice description + /// starts with "Slice " and joins several parts with " - ", SlicedBy names slices after + /// type names such as "Outer+Inner" or "List`1", and a hand-built SliceIdentifier can be + /// called anything. No character that a namespace cannot contain works in their place either, so + /// the id is made from the name with those characters replaced by "_", and suffixed until + /// it clashes with no other name in the diagram. The name itself stays the label, and + /// slices whose names are valid ids keep them. /// private static void AssignAliases(IReadOnlyCollection elements) { diff --git a/ArchUnitNET/Domain/PlantUml/Export/PlantUmlFileBuilder.cs b/ArchUnitNET/Domain/PlantUml/Export/PlantUmlFileBuilder.cs index fc758aa6f..ef647c043 100644 --- a/ArchUnitNET/Domain/PlantUml/Export/PlantUmlFileBuilder.cs +++ b/ArchUnitNET/Domain/PlantUml/Export/PlantUmlFileBuilder.cs @@ -728,12 +728,14 @@ private void ReplaceCirclesWithAppropriateDependencyType() /// nested slice is therefore drawn under its qualified name, the namespace its types /// matched before the first capture group followed by its /// , e.g. "App.Orders.Http", with that namespace - /// as its root package. Every other slice is drawn under its description, without a - /// package. + /// as its root package. Every other slice is drawn under its description, e.g. + /// "Slice Orders - Http", without a package. /// /// - /// Qualified names of one pattern are distinct, but a description can coincide with a - /// qualified name. Drawing two slices as one node would be wrong, so that is rejected. + /// A description always contains a space and a qualified name never does, so the two + /// can't be mistaken for each other, and qualified names of one pattern are distinct. + /// Descriptions can still coincide, for a custom slice whose part contains " - ". + /// Drawing two slices as one node would be wrong, so that is rejected. /// /// /// @@ -757,11 +759,11 @@ private void AssignDiagramNames(bool nestSlicesInPackages) if (slicesByName.TryGetValue(diagramName.Name, out var other)) { throw new ArgumentException( - "The slices \"" - + other.Identifier.Identifier - + "\" and \"" - + slice.Identifier.Identifier - + "\" would both be drawn as \"" + "The slices with parts " + + FormatParts(other) + + " and " + + FormatParts(slice) + + " would both be drawn as \"" + diagramName.Name + "\"." ); @@ -772,6 +774,13 @@ private void AssignDiagramNames(bool nestSlicesInPackages) } } + private static string FormatParts(Slice slice) + { + return "[" + + string.Join(", ", slice.Identifier.Parts.Select(part => "\"" + part + "\"")) + + "]"; + } + /// The name the diagram draws a slice under; see . private string NameOf(Slice slice) { diff --git a/ArchUnitNET/Domain/SliceIdentifier.cs b/ArchUnitNET/Domain/SliceIdentifier.cs index 8dc528989..fc1090391 100644 --- a/ArchUnitNET/Domain/SliceIdentifier.cs +++ b/ArchUnitNET/Domain/SliceIdentifier.cs @@ -1,28 +1,48 @@ -using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; namespace ArchUnitNET.Domain { - public class SliceIdentifier : StringIdentifier, IHasDescription + /// + /// Identifies a slice by its parts: for a slice pattern, the values its capture groups + /// captured, in group order. Two identifiers are the same slice exactly when their parts are + /// equal and both are ignored or both are not. + /// + public class SliceIdentifier : IHasDescription { public static readonly SliceIdentifierComparer Comparer = new SliceIdentifierComparer(); public readonly bool Ignored; private SliceIdentifier( - string identifier, + IReadOnlyList parts, bool ignored, int? countOfAsteriskInPattern = null, string matchedPrefix = null, string diagramPath = null ) - : base(identifier) { + Parts = parts; Ignored = ignored; CountOfAsteriskInPattern = countOfAsteriskInPattern; MatchedPrefix = matchedPrefix; DiagramPath = diagramPath; } - public string Description => Identifier; + /// + /// What identifies the slice: for a slice pattern, the values its capture groups + /// captured, in group order. "App.(**)" over "App.Orders.Web" gives + /// [Orders.Web]. + /// + public IReadOnlyList Parts { get; } + + /// + /// The slice's name, built from its parts: "Slice " followed by the parts joined with + /// " - ", e.g. "Slice Orders - Http". It depends on the parts only, so equal slices always + /// have the same name. + /// + public string Description => "Slice " + string.Join(" - ", Parts); /// /// The part of the type's namespace the pattern matched before the first capture group, @@ -44,9 +64,31 @@ private SliceIdentifier( public readonly int? CountOfAsteriskInPattern; - public static SliceIdentifier Of(string identifier, int? countOfAsteriskInPattern = null) + /// + /// Creates an identifier for a slice with a single part, the same slice as + /// Of(new[] { part }). + /// + /// + /// The slice's only part: a custom SliceAssignment that returns identifiers with the + /// same part for two types puts them into the same slice. + /// + /// + /// The number of "(*)" groups in the pattern, if the slice comes from one. + /// + public static SliceIdentifier Of(string part, int? countOfAsteriskInPattern = null) + { + return new SliceIdentifier(CheckParts(new[] { part }), false, countOfAsteriskInPattern); + } + + /// + /// Creates an identifier for the slice with the given parts. Identifiers with equal parts, + /// in the same order, belong to the same slice. + /// + /// The parts, at least one; none of them may be null. + /// There are no parts, or one of them is null. + public static SliceIdentifier Of(IEnumerable parts) { - return new SliceIdentifier(identifier, false, countOfAsteriskInPattern); + return new SliceIdentifier(CheckParts(parts), false); } /// @@ -54,14 +96,14 @@ public static SliceIdentifier Of(string identifier, int? countOfAsteriskInPatter /// pattern matched, which diagrams use to nest the slice. /// internal static SliceIdentifier OfMatch( - string identifier, + IEnumerable parts, int? countOfAsteriskInPattern, string matchedPrefix, string diagramPath ) { return new SliceIdentifier( - identifier, + CheckParts(parts), false, countOfAsteriskInPattern, matchedPrefix, @@ -71,14 +113,34 @@ string diagramPath public static SliceIdentifier Ignore() { - return new SliceIdentifier("Ignored", true); + return new SliceIdentifier(new[] { "Ignored" }, true); + } + + private static IReadOnlyList CheckParts(IEnumerable parts) + { + if (parts == null) + { + throw new ArgumentNullException(nameof(parts)); + } + + var list = parts.ToList(); + if (list.Count == 0) + { + throw new ArgumentException("A slice needs at least one part.", nameof(parts)); + } + + if (list.Any(part => part == null)) + { + throw new ArgumentException("A slice part can't be null.", nameof(parts)); + } + + return list.AsReadOnly(); } /// - /// Is true when the two SliceIdentifiers belong to the same slice + /// Whether the two identifiers belong to the same slice: both ignored, or both not + /// ignored with the same parts. /// - /// - /// public bool CompareTo(SliceIdentifier other) { if (other == null) @@ -87,12 +149,12 @@ public bool CompareTo(SliceIdentifier other) } return Ignored && other.Ignored - || !Ignored && !other.Ignored && Identifier == other.Identifier; + || !Ignored && !other.Ignored && Parts.SequenceEqual(other.Parts); } private bool Equals(SliceIdentifier other) { - return Identifier == other.Identifier && Ignored == other.Ignored; + return Ignored == other.Ignored && Parts.SequenceEqual(other.Parts); } public override bool Equals(object obj) @@ -114,10 +176,19 @@ public override int GetHashCode() { unchecked { - var hashCode = 397 ^ Identifier.GetHashCode(); - hashCode = (hashCode * 397) ^ Ignored.GetHashCode(); + var hashCode = Ignored.GetHashCode(); + foreach (var part in Parts) + { + hashCode = (hashCode * 397) ^ part.GetHashCode(); + } + return hashCode; } } + + public override string ToString() + { + return Description; + } } } diff --git a/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs b/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs index 1482a6602..8db081cf7 100644 --- a/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs +++ b/ArchUnitNET/Fluent/Slices/SliceRuleInitializer.cs @@ -170,7 +170,7 @@ private static SliceIdentifier AssignFunc( // What the pattern captured is both what identifies the slice and the path a // diagram nests it along. return SliceIdentifier.OfMatch( - sliceString, + new[] { sliceString }, countOfSingleAsterisk, matchedPrefix, sliceString diff --git a/ArchUnitNET/Fluent/Slices/SlicesShould.cs b/ArchUnitNET/Fluent/Slices/SlicesShould.cs index 5e1fc1cfa..c67c60874 100644 --- a/ArchUnitNET/Fluent/Slices/SlicesShould.cs +++ b/ArchUnitNET/Fluent/Slices/SlicesShould.cs @@ -91,7 +91,7 @@ Architecture architecture } var cycleIdentifier = new EnumerableIdentifier( - cycle.Contents.Select(slice => slice.Identifier) + cycle.Contents.Select(slice => new StringIdentifier(slice.Description)) ); yield return new EvaluationResult( cycle, @@ -106,7 +106,7 @@ Architecture architecture else { var slicesIdentifier = new EnumerableIdentifier( - slicesList.Select(slice => slice.Identifier) + slicesList.Select(slice => new StringIdentifier(slice.Description)) ); yield return new EvaluationResult( slicesList, @@ -166,7 +166,7 @@ Architecture architecture yield return new EvaluationResult( slice, - slice.Identifier, + new StringIdentifier(slice.Description), passed, description, archRule, diff --git a/ArchUnitNETTests/ArchUnitNET/Storage/CustomPathFrozenRules.json b/ArchUnitNETTests/ArchUnitNET/Storage/CustomPathFrozenRules.json index 9216791d3..ceb002561 100644 --- a/ArchUnitNETTests/ArchUnitNET/Storage/CustomPathFrozenRules.json +++ b/ArchUnitNETTests/ArchUnitNET/Storage/CustomPathFrozenRules.json @@ -15,12 +15,12 @@ { "ArchRuleDescription": "Slices matching \"SlicesTestAssembly.MultipleSubnamespaces.(**)\" should not depend on each other", "Violations": [ - "Slice3", - "Slice3.Group1", - "Slice2", - "Slice2.Service", - "Slice1", - "Slice1.Service" + "Slice Slice3", + "Slice Slice3.Group1", + "Slice Slice2", + "Slice Slice2.Service", + "Slice Slice1", + "Slice Slice1.Service" ] } ] \ No newline at end of file diff --git a/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.json b/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.json index 5e4531c65..93b5d4c34 100644 --- a/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.json +++ b/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.json @@ -21,12 +21,12 @@ { "ArchRuleDescription": "Slices matching \"SlicesTestAssembly.MultipleSubnamespaces.(**)\" should not depend on each other", "Violations": [ - "Slice3", - "Slice3.Group1", - "Slice2", - "Slice2.Service", - "Slice1", - "Slice1.Service" + "Slice Slice3", + "Slice Slice3.Group1", + "Slice Slice2", + "Slice Slice2.Service", + "Slice Slice1", + "Slice Slice1.Service" ] }, { diff --git a/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.xml b/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.xml index c0905ff78..785f1107e 100644 --- a/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.xml +++ b/ArchUnitNETTests/ArchUnitNET/Storage/FrozenRules.xml @@ -12,11 +12,11 @@ ArchUnitNETTests.Fluent.FreezeTests+Violation - Slice3 - Slice3.Group1 - Slice2 - Slice2.Service - Slice1 - Slice1.Service + Slice Slice3 + Slice Slice3.Group1 + Slice Slice2 + Slice Slice2.Service + Slice Slice1 + Slice Slice1.Service \ No newline at end of file diff --git a/ArchUnitNETTests/Domain/PlantUml/PlantUmlSliceDiagramTests.cs b/ArchUnitNETTests/Domain/PlantUml/PlantUmlSliceDiagramTests.cs index d3f13c11b..a02feb79b 100644 --- a/ArchUnitNETTests/Domain/PlantUml/PlantUmlSliceDiagramTests.cs +++ b/ArchUnitNETTests/Domain/PlantUml/PlantUmlSliceDiagramTests.cs @@ -154,9 +154,8 @@ public Task BuildUmlBySlicesFocusOn_Matching_ColorsFocusedSlices() { // Slices that are not nested have no namespace, so the focused ones take // PlantUmlSlice.BuildString's namespace-less branch with a colour set -- the only - // path on which the exporter renders "[Slice1] #99ffd1" rather than a package. - // They are drawn under their description, which carries no Root prefix, hence the - // bare focus string. + // path on which the exporter renders "[Slice Slice1] #99ffd1" rather than a package. + // They are drawn under their description, which "Slice1" is contained in. var slices = SortedSlices(SliceRuleDefinition.Slices().Matching(Root + "(**)")); var uml = new PlantUmlFileBuilder() .WithDependenciesFromFocusOn(slices, "Slice1") @@ -371,9 +370,9 @@ public void BuildUmlBySlices_SameSlicesDrawnFlatAndNested() var nested = new PlantUmlFileBuilder().WithDependenciesFrom(slices, Nested).AsString(); Assert.DoesNotContain("package", flat); - Assert.Contains("[Slice1.Service]", flat); + Assert.Contains("[Slice Slice1] as Slice_Slice1", flat); Assert.Contains("package \"SlicesTestAssembly.MultipleSubnamespaces\"", nested); - Assert.DoesNotContain("[Slice1.Service]", nested); + Assert.DoesNotContain("Slice Slice1", nested); } // --- Two slices may not share a node ---------------------------------------------- @@ -381,20 +380,18 @@ public void BuildUmlBySlices_SameSlicesDrawnFlatAndNested() [Fact] public void BuildUmlBySlices_SameDiagramName_Throws() { - // A slice that is not nested is drawn under its description, which here is the - // qualified name a nested slice is drawn under. - var slices = SortedSlices(SliceRuleDefinition.Slices().Matching(Root + "(**)")) - .Concat( - new[] { new Slice(SliceIdentifier.Of(Root + "Slice1"), Array.Empty()) } - ) - .ToList(); + // Different slices, both described "Slice A - B". + var slices = new[] + { + new Slice(SliceIdentifier.Of(new[] { "A - B" }), Array.Empty()), + new Slice(SliceIdentifier.Of(new[] { "A", "B" }), Array.Empty()), + }; var ex = Assert.Throws(() => - new PlantUmlFileBuilder().WithDependenciesFrom(slices, Nested) + new PlantUmlFileBuilder().WithDependenciesFrom(slices) ); Assert.Equal( - "The slices \"Slice1\" and \"SlicesTestAssembly.MultipleSubnamespaces.Slice1\" " - + "would both be drawn as \"SlicesTestAssembly.MultipleSubnamespaces.Slice1\".", + "The slices with parts [\"A - B\"] and [\"A\", \"B\"] would both be drawn as \"Slice A - B\".", ex.Message ); } diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlicesFocusOn_Matching_ColorsFocusedSlices.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlicesFocusOn_Matching_ColorsFocusedSlices.verified.txt index b96ed6505..efeb37eb4 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlicesFocusOn_Matching_ColorsFocusedSlices.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlicesFocusOn_Matching_ColorsFocusedSlices.verified.txt @@ -4,12 +4,12 @@ HIDE_STEREOTYPE() -[Slice1] #99ffd1 -[Slice1.Service] #99ffd1 -[Slice2] -[Slice2.Service] -[Slice3] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice3] --|> [Slice1] +[Slice Slice1] as Slice_Slice1 #99ffd1 +[Slice Slice1.Service] as Slice_Slice1.Service #99ffd1 +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice3] --|> [Slice_Slice1] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_C4Style.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_C4Style.verified.txt index 851e24568..9b02ce5b4 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_C4Style.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_C4Style.verified.txt @@ -4,19 +4,19 @@ HIDE_STEREOTYPE() -Container(Slice1, Slice1) -Container(Slice1.Service, Slice1.Service) -Container(Slice2, Slice2) -Container(Slice2.Service, Slice2.Service) -Container(Slice3, Slice3) -Container(Slice3.Group1, Slice3.Group1) -Container(Slice3.Group1.Inner, Slice3.Group1.Inner) -Container(Slice3.Group2, Slice3.Group2) -Container(Slice3.Group2.Inner, Slice3.Group2.Inner) -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] -[Slice3.Group1] --|> [Slice3] +Container(Slice_Slice1, Slice Slice1) +Container(Slice_Slice1.Service, Slice Slice1.Service) +Container(Slice_Slice2, Slice Slice2) +Container(Slice_Slice2.Service, Slice Slice2.Service) +Container(Slice_Slice3, Slice Slice3) +Container(Slice_Slice3.Group1, Slice Slice3.Group1) +Container(Slice_Slice3.Group1.Inner, Slice Slice3.Group1.Inner) +Container(Slice_Slice3.Group2, Slice Slice3.Group2) +Container(Slice_Slice3.Group2.Inner, Slice Slice3.Group2.Inner) +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] +[Slice_Slice3.Group1] --|> [Slice_Slice3] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DirectCircle_RendersCircleDependency.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DirectCircle_RendersCircleDependency.verified.txt index ffc596323..846b74ca6 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DirectCircle_RendersCircleDependency.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DirectCircle_RendersCircleDependency.verified.txt @@ -4,7 +4,7 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice2] -[Slice1] <-[#red]> [Slice2] +[Slice Slice1] as Slice_Slice1 +[Slice Slice2] as Slice_Slice2 +[Slice_Slice1] <-[#red]> [Slice_Slice2] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DoubleAsterisk.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DoubleAsterisk.verified.txt index b33b9dcab..92de1e097 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DoubleAsterisk.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_DoubleAsterisk.verified.txt @@ -4,19 +4,19 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice3.Group1.Inner] -[Slice3.Group2] -[Slice3.Group2.Inner] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] -[Slice3.Group1] --|> [Slice3] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice Slice3.Group1.Inner] as Slice_Slice3.Group1.Inner +[Slice Slice3.Group2] as Slice_Slice3.Group2 +[Slice Slice3.Group2.Inner] as Slice_Slice3.Group2.Inner +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] +[Slice_Slice3.Group1] --|> [Slice_Slice3] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_ExcludeNodesWithoutDependencies.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_ExcludeNodesWithoutDependencies.verified.txt index c5667533f..5baf30abd 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_ExcludeNodesWithoutDependencies.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_ExcludeNodesWithoutDependencies.verified.txt @@ -4,16 +4,16 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] -[Slice3.Group1] --|> [Slice3] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] +[Slice_Slice3.Group1] --|> [Slice_Slice3] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_LimitDependencies_Compact.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_LimitDependencies_Compact.verified.txt index 991ec5378..4d06a235e 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_LimitDependencies_Compact.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_LimitDependencies_Compact.verified.txt @@ -4,17 +4,17 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice3.Group1.Inner] -[Slice3.Group2] -[Slice3.Group2.Inner] -[Slice1] --> [Slice2] -[Slice1.Service] --> [Slice2.Service] -[Slice2] --> [Slice3] -[Slice3] --> [Slice1] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice Slice3.Group1.Inner] as Slice_Slice3.Group1.Inner +[Slice Slice3.Group2] as Slice_Slice3.Group2 +[Slice Slice3.Group2.Inner] as Slice_Slice3.Group2.Inner +[Slice_Slice1] --> [Slice_Slice2] +[Slice_Slice1.Service] --> [Slice_Slice2.Service] +[Slice_Slice2] --> [Slice_Slice3] +[Slice_Slice3] --> [Slice_Slice1] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_MultipleCaptureGroups.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_MultipleCaptureGroups.verified.txt index 041ebd608..8e5c21f27 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_MultipleCaptureGroups.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_MultipleCaptureGroups.verified.txt @@ -4,17 +4,17 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice3.Group2] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] -[Slice3.Group1] --|> [Slice3] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice Slice3.Group2] as Slice_Slice3.Group2 +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] +[Slice_Slice3.Group1] --|> [Slice_Slice3] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_NonContiguousCaptureGroups.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_NonContiguousCaptureGroups.verified.txt index 041ebd608..8e5c21f27 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_NonContiguousCaptureGroups.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_NonContiguousCaptureGroups.verified.txt @@ -4,17 +4,17 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice3.Group2] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] -[Slice3.Group1] --|> [Slice3] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice Slice3.Group2] as Slice_Slice3.Group2 +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] +[Slice_Slice3.Group1] --|> [Slice_Slice3] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_SingleAsterisk.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_SingleAsterisk.verified.txt index c37caedd7..a4f69a9d3 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_SingleAsterisk.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_SingleAsterisk.verified.txt @@ -4,10 +4,10 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice2] -[Slice3] -[Slice1] --|> [Slice2] -[Slice2] --|> [Slice3] -[Slice3] --|> [Slice1] +[Slice Slice1] as Slice_Slice1 +[Slice Slice2] as Slice_Slice2 +[Slice Slice3] as Slice_Slice3 +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] @enduml diff --git a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_WithDependencyFilter.verified.txt b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_WithDependencyFilter.verified.txt index 969b504e8..61a2c05ad 100644 --- a/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_WithDependencyFilter.verified.txt +++ b/ArchUnitNETTests/Domain/PlantUml/Snapshots/PlantUmlSliceDiagramTests.BuildUmlBySlices_WithDependencyFilter.verified.txt @@ -4,18 +4,18 @@ HIDE_STEREOTYPE() -[Slice1] -[Slice1.Service] -[Slice2] -[Slice2.Service] -[Slice3] -[Slice3.Group1] -[Slice3.Group1.Inner] -[Slice3.Group2] -[Slice3.Group2.Inner] -[Slice1] --|> [Slice2] -[Slice1.Service] --|> [Slice2.Service] -[Slice2] --|> [Slice3] -[Slice2.Service] --|> [Slice3] -[Slice3] --|> [Slice1] +[Slice Slice1] as Slice_Slice1 +[Slice Slice1.Service] as Slice_Slice1.Service +[Slice Slice2] as Slice_Slice2 +[Slice Slice2.Service] as Slice_Slice2.Service +[Slice Slice3] as Slice_Slice3 +[Slice Slice3.Group1] as Slice_Slice3.Group1 +[Slice Slice3.Group1.Inner] as Slice_Slice3.Group1.Inner +[Slice Slice3.Group2] as Slice_Slice3.Group2 +[Slice Slice3.Group2.Inner] as Slice_Slice3.Group2.Inner +[Slice_Slice1] --|> [Slice_Slice2] +[Slice_Slice1.Service] --|> [Slice_Slice2.Service] +[Slice_Slice2] --|> [Slice_Slice3] +[Slice_Slice2.Service] --|> [Slice_Slice3] +[Slice_Slice3] --|> [Slice_Slice1] @enduml diff --git a/ArchUnitNETTests/Fluent/Slices/SliceDomainTests.cs b/ArchUnitNETTests/Fluent/Slices/SliceDomainTests.cs index 0c2b92e02..f61fc8927 100644 --- a/ArchUnitNETTests/Fluent/Slices/SliceDomainTests.cs +++ b/ArchUnitNETTests/Fluent/Slices/SliceDomainTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using ArchUnitNET.Domain; using ArchUnitNET.Domain.Extensions; @@ -65,7 +65,7 @@ public void Slice_ToString_ReturnsDescription() { var slice = new Slice(SliceIdentifier.Of("SomeSlice"), Array.Empty()); - Assert.Equal("SomeSlice", slice.ToString()); + Assert.Equal("Slice SomeSlice", slice.ToString()); Assert.Equal(slice.Description, slice.ToString()); } @@ -104,6 +104,14 @@ public void SliceIdentifier_CompareTo_Null_ReturnsFalse() Assert.False(SliceIdentifier.Of("A").CompareTo(null)); } + [Fact] + public void SliceIdentifier_CompareTo_OneIgnored_ReturnsFalse() + { + // Same parts, so only the Ignored flag tells the two apart. + Assert.False(SliceIdentifier.Of("Ignored").CompareTo(SliceIdentifier.Ignore())); + Assert.False(SliceIdentifier.Ignore().CompareTo(SliceIdentifier.Of("Ignored"))); + } + [Fact] public void SliceIdentifier_Equals_Branches() { @@ -116,15 +124,132 @@ public void SliceIdentifier_Equals_Branches() Assert.False(identifier.Equals(SliceIdentifier.Of("B"))); } + [Fact] + public void SliceIdentifier_Equals_ComparesParts() + { + var identifier = SliceIdentifier.Of(new[] { "A", "B" }); + + Assert.Equal(SliceIdentifier.Of(new[] { "A", "B" }), identifier); + Assert.Equal( + SliceIdentifier.Of(new[] { "A", "B" }).GetHashCode(), + identifier.GetHashCode() + ); + Assert.NotEqual(SliceIdentifier.Of(new[] { "B", "A" }), identifier); + Assert.NotEqual(SliceIdentifier.Of("A.B"), identifier); + Assert.NotEqual(SliceIdentifier.Of(new[] { "A", "B", "C" }), identifier); + } + [Fact] public void SliceIdentifier_Equals_IgnoresDiagramData() { // Where a diagram draws the slice is no part of its identity. - var nested = SliceIdentifier.OfMatch("A.B", null, "X.", "A.B"); + var nested = SliceIdentifier.OfMatch(new[] { "A", "B" }, null, "X.", "A.B"); + + Assert.Equal(SliceIdentifier.Of(new[] { "A", "B" }), nested); + Assert.Equal( + SliceIdentifier.Of(new[] { "A", "B" }).GetHashCode(), + nested.GetHashCode() + ); + Assert.Equal("Slice A - B", nested.Description); + } + + [Fact] + public void SliceIdentifier_OfString_IsASingleSlicePart() + { + var ofString = SliceIdentifier.Of("Orders"); + var ofParts = SliceIdentifier.Of(new[] { "Orders" }); + + Assert.Equal(new[] { "Orders" }, ofString.Parts); + Assert.Equal(ofParts, ofString); + Assert.Equal("Slice Orders", ofString.Description); + Assert.Equal("Slice Orders", ofParts.Description); + } + + [Fact] + public void SliceIdentifier_Description_PrefixesTheJoinedParts() + { + Assert.Equal("Slice Orders.Web", SliceIdentifier.Of("Orders.Web").Description); + Assert.Equal( + "Slice Orders - Http", + SliceIdentifier.Of(new[] { "Orders", "Http" }).Description + ); + } + + [Fact] + public void SliceIdentifier_Of_RejectsMissingParts() + { + Assert.Throws(() => + SliceIdentifier.Of((System.Collections.Generic.IEnumerable)null) + ); + Assert.Throws(() => SliceIdentifier.Of(new string[0])); + Assert.Throws(() => SliceIdentifier.Of(new[] { "A", null })); + } + + [Fact] + public void SliceIdentifier_PartsContainingTheSeparator_AreADifferentSlice() + { + // Both are described "Slice A - B", but they are different slices. + var onePart = SliceIdentifier.Of(new[] { "A - B" }); + var twoParts = SliceIdentifier.Of(new[] { "A", "B" }); + + Assert.Equal(onePart.Description, twoParts.Description); + Assert.NotEqual(onePart, twoParts); + Assert.False(SliceIdentifier.Comparer.Equals(onePart, twoParts)); + } + + [Fact] + public void SliceIdentifier_ToString_IsTheDescription() + { + Assert.Equal("Slice Orders", SliceIdentifier.Of("Orders").ToString()); + } + + // --- Violation keys, which violation stores keep --------------------------------- + + [Fact] + public void ViolationKey_IsTheDescription() + { + var keys = SliceRuleDefinition + .Slices() + .Matching(Root + "(*)") + .Should() + .NotDependOnEachOther() + .Evaluate(Architecture) + .Select(result => result.EvaluatedObjectIdentifier.Identifier); + + Assert.Contains("Slice Slice1", keys); + } + + [Fact] + public void ViolationKey_OfSeveralParts_IsTheDescription() + { + // Patterns capture a single part, so a custom assignment builds several. + var creator = new SliceRuleCreator(); + creator.SetSliceAssignment( + new SliceAssignment( + type => SliceIdentifier.Of(new[] { "Custom", type.Name }), + "by name" + ) + ); + + var keys = new SlicesShould(creator) + .NotDependOnEachOther() + .Evaluate(Architecture) + .Select(result => result.EvaluatedObjectIdentifier.Identifier); + + Assert.Contains("Slice Custom - Slice1Class", keys); + } + + // --- SlicedBy ------------------------------------------------------------------ + + [Fact] + public void SlicedBy_NamesSlicesAfterTheTypeLikeEveryOtherSlice() + { + var type = Architecture.GetClassOfType(typeof(MixedTypesClass)); + + var slice = Assert.Single(new IType[] { type }.SlicedBy("")); - Assert.Equal(SliceIdentifier.Of("A.B"), nested); - Assert.Equal(SliceIdentifier.Of("A.B").GetHashCode(), nested.GetHashCode()); - Assert.Equal("A.B", nested.Description); + Assert.Equal(new[] { type.FullName }, slice.Identifier.Parts); + Assert.Equal("Slice " + type.FullName, slice.Description); } [Fact] diff --git a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs index 232cb4a2b..67290d3ba 100644 --- a/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs +++ b/ArchUnitNETTests/Fluent/Slices/SlicesTests.cs @@ -176,15 +176,15 @@ public void Matching_SingleAsterisk_CapturesEveryDepth() Assert.Equal( new[] { - "Slice1", - "Slice1.Service", - "Slice2", - "Slice2.Service", - "Slice3", - "Slice3.Group1", - "Slice3.Group1.Inner", - "Slice3.Group2", - "Slice3.Group2.Inner", + "Slice Slice1", + "Slice Slice1.Service", + "Slice Slice2", + "Slice Slice2.Service", + "Slice Slice3", + "Slice Slice3.Group1", + "Slice Slice3.Group1.Inner", + "Slice Slice3.Group2", + "Slice Slice3.Group2.Inner", }, Descriptions(Root + "(*)") ); @@ -199,7 +199,10 @@ public void Matching_SingleAsteriskDotDot_CapturesEveryDepth() [Fact] public void Matching_DoubleAsteriskDotDot_FoldsSubnamespacesIntoParent() { - Assert.Equal(new[] { "Slice1", "Slice2", "Slice3" }, Descriptions(Root + "(**)..")); + Assert.Equal( + new[] { "Slice Slice1", "Slice Slice2", "Slice Slice3" }, + Descriptions(Root + "(**)..") + ); } /// @@ -227,8 +230,8 @@ public void Matching_DoubleAsteriskDotDot_DropsTypesDirectlyInCapturedNamespace( .ToArray() ); - Assert.Equal(new[] { Root + "Slice1.Service.Service1Class" }, types["Slice1"]); - Assert.Equal(new[] { Root + "Slice2.Service.Service2Class" }, types["Slice2"]); + Assert.Equal(new[] { Root + "Slice1.Service.Service1Class" }, types["Slice Slice1"]); + Assert.Equal(new[] { Root + "Slice2.Service.Service2Class" }, types["Slice Slice2"]); Assert.Equal( new[] { @@ -237,7 +240,7 @@ public void Matching_DoubleAsteriskDotDot_DropsTypesDirectlyInCapturedNamespace( Root + "Slice3.Group2.Group2Class", Root + "Slice3.Group2.Inner.Inner2Class", }, - types["Slice3"] + types["Slice Slice3"] ); } @@ -276,7 +279,7 @@ public void DuplicatePrefixSegment_CapturesAfterTheFirstOccurrenceOfThePrefix() .ToList(); Assert.Single(slices); - Assert.Equal("DuplicatePrefix.Sub", slices[0].Description); + Assert.Equal("Slice DuplicatePrefix.Sub", slices[0].Description); } // --- ".." semantics ------------------------------------------------------------- @@ -287,11 +290,11 @@ public void DotDot_BetweenCaptureGroups_CapturesEveryDepth() Assert.Equal( new[] { - "Alpha.Service", - "AlphaService", - "Outer.Inner", - "Outer.Mid.Inner", - "Single", + "Slice Alpha.Service", + "Slice AlphaService", + "Slice Outer.Inner", + "Slice Outer.Mid.Inner", + "Slice Single", }, Descriptions(DotDot + "(*)..(*)") ); @@ -303,11 +306,11 @@ public void DotDot_BeforeLiteral_CapturesEveryDepth() Assert.Equal( new[] { - "Alpha.Service", - "AlphaService", - "Outer.Inner", - "Outer.Mid.Inner", - "Single", + "Slice Alpha.Service", + "Slice AlphaService", + "Slice Outer.Inner", + "Slice Outer.Mid.Inner", + "Slice Single", }, Descriptions(DotDot + "(*)..Service") ); @@ -328,8 +331,8 @@ public void DotDot_BeforeLiteral_GivesAlphaServiceAndAlphaDotServiceDistinctSlic // holding exactly the one type it's made of. This is not evidence the matcher tells // the two shapes apart -- it would look identical if it ignored segment boundaries // entirely. - Assert.Single(slices.Single(slice => slice.Description == "AlphaService").Types); - Assert.Single(slices.Single(slice => slice.Description == "Alpha.Service").Types); + Assert.Single(slices.Single(slice => slice.Description == "Slice AlphaService").Types); + Assert.Single(slices.Single(slice => slice.Description == "Slice Alpha.Service").Types); } // --- failure messages ----------------------------------------------------------- diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_FluentDefinition_CombinesEvaluationAndDescription.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_FluentDefinition_CombinesEvaluationAndDescription.verified.txt index 15d5cc49f..7c6f6bb58 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_FluentDefinition_CombinesEvaluationAndDescription.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_FluentDefinition_CombinesEvaluationAndDescription.verified.txt @@ -21,11 +21,11 @@ All Evaluations passed Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles and Types that have full name "SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: True @@ -33,11 +33,11 @@ Description: SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass pa Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_WithArchRule_CombinesEvaluationAndDescription.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_WithArchRule_CombinesEvaluationAndDescription.verified.txt index c22e38343..f13e66cbd 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_WithArchRule_CombinesEvaluationAndDescription.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.And_WithArchRule_CombinesEvaluationAndDescription.verified.txt @@ -26,11 +26,11 @@ Message: Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles and Types that have name "NotTheNameOfAnyObject" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: False @@ -38,11 +38,11 @@ Description: There are no objects matching the criteria Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_FluentDefinition_CombinesEvaluationAndDescription.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_FluentDefinition_CombinesEvaluationAndDescription.verified.txt index 14faa3188..acbf6584a 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_FluentDefinition_CombinesEvaluationAndDescription.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_FluentDefinition_CombinesEvaluationAndDescription.verified.txt @@ -3,21 +3,21 @@ Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class @@ -28,11 +28,11 @@ Slice3 -> Slice1 Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles or Types that have full name "SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: True @@ -40,11 +40,11 @@ Description: SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass pa Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class @@ -55,11 +55,11 @@ Slice3 -> Slice1 Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles or Types that have name "NotTheNameOfAnyObject" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: False @@ -67,11 +67,11 @@ Description: There are no objects matching the criteria Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_WithArchRule_CombinesEvaluationAndDescription.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_WithArchRule_CombinesEvaluationAndDescription.verified.txt index 42340d70c..c2a19f195 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_WithArchRule_CombinesEvaluationAndDescription.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SliceRuleCombinationTests.Or_WithArchRule_CombinesEvaluationAndDescription.verified.txt @@ -3,11 +3,11 @@ Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles or Types that have full name "SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: True @@ -15,11 +15,11 @@ Description: SlicesTestAssembly.DotDotSemantics.Outer.Mid.Inner.MidInnerClass pa Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class @@ -30,11 +30,11 @@ Slice3 -> Slice1 Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles or Types that have name "NotTheNameOfAnyObject" should exist Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: False @@ -42,11 +42,11 @@ Description: There are no objects matching the criteria Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_MultipleSubnamespaces_ReportsEveryCycle.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_MultipleSubnamespaces_ReportsEveryCycle.verified.txt index b15623362..88b409548 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_MultipleSubnamespaces_ReportsEveryCycle.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_MultipleSubnamespaces_ReportsEveryCycle.verified.txt @@ -1,21 +1,21 @@ Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles Result: False Description: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should be free of cycles" failed: Cycle found: -Slice2 -> Slice3 +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -Slice3 -> Slice1 +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_WithCycle_ReturnsDescriptiveCycleMessage.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_WithCycle_ReturnsDescriptiveCycleMessage.verified.txt index 03a2b704c..0bb65e78b 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_WithCycle_ReturnsDescriptiveCycleMessage.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.BeFreeOfCycles_WithCycle_ReturnsDescriptiveCycleMessage.verified.txt @@ -1,17 +1,17 @@ Query: Slices matching "SlicesTestAssembly.DirectCircle.(*)" should be free of cycles Result: False Description: Cycle found: -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.DirectCircle.Slice1.Slice1Class -> SlicesTestAssembly.DirectCircle.Slice2.Slice2Class -Slice2 -> Slice1 +Slice Slice2 -> Slice Slice1 SlicesTestAssembly.DirectCircle.Slice2.Slice2Class -> SlicesTestAssembly.DirectCircle.Slice1.Slice1Class Message: "Slices matching "SlicesTestAssembly.DirectCircle.(*)" should be free of cycles" failed: Cycle found: -Slice1 -> Slice2 +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.DirectCircle.Slice1.Slice1Class -> SlicesTestAssembly.DirectCircle.Slice2.Slice2Class -Slice2 -> Slice1 +Slice Slice2 -> Slice Slice1 SlicesTestAssembly.DirectCircle.Slice2.Slice2Class -> SlicesTestAssembly.DirectCircle.Slice1.Slice1Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_MultipleSubnamespaces_ReportsEveryDependency.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_MultipleSubnamespaces_ReportsEveryDependency.verified.txt index 0a801d01b..d17bbc960 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_MultipleSubnamespaces_ReportsEveryDependency.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_MultipleSubnamespaces_ReportsEveryDependency.verified.txt @@ -1,64 +1,64 @@ Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should not depend on each other Result: False -Description: Slice1 does depend on other slices: -Slice1 -> Slice2 +Description: Slice Slice1 does depend on other slices: +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class Result: False -Description: Slice1.Service does depend on other slices: -Slice1.Service -> Slice2.Service +Description: Slice Slice1.Service does depend on other slices: +Slice Slice1.Service -> Slice Slice2.Service SlicesTestAssembly.MultipleSubnamespaces.Slice1.Service.Service1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class Result: False -Description: Slice2 does depend on other slices: -Slice2 -> Slice3 +Description: Slice Slice2 does depend on other slices: +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class Result: False -Description: Slice2.Service does depend on other slices: -Slice2.Service -> Slice3 +Description: Slice Slice2.Service does depend on other slices: +Slice Slice2.Service -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class Result: False -Description: Slice3 does depend on other slices: -Slice3 -> Slice1 +Description: Slice Slice3 does depend on other slices: +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class Result: False -Description: Slice3.Group1 does depend on other slices: -Slice3.Group1 -> Slice3 +Description: Slice Slice3.Group1 does depend on other slices: +Slice Slice3.Group1 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Group1.Group1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class Result: True -Description: Slice3.Group1.Inner does not depend on another slice. +Description: Slice Slice3.Group1.Inner does not depend on another slice. Result: True -Description: Slice3.Group2 does not depend on another slice. +Description: Slice Slice3.Group2 does not depend on another slice. Result: True -Description: Slice3.Group2.Inner does not depend on another slice. +Description: Slice Slice3.Group2.Inner does not depend on another slice. Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**)" should not depend on each other" failed: - Slice1 does depend on other slices: -Slice1 -> Slice2 + Slice Slice1 does depend on other slices: +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class - Slice1.Service does depend on other slices: -Slice1.Service -> Slice2.Service + Slice Slice1.Service does depend on other slices: +Slice Slice1.Service -> Slice Slice2.Service SlicesTestAssembly.MultipleSubnamespaces.Slice1.Service.Service1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class - Slice2 does depend on other slices: -Slice2 -> Slice3 + Slice Slice2 does depend on other slices: +Slice Slice2 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Slice2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class - Slice2.Service does depend on other slices: -Slice2.Service -> Slice3 + Slice Slice2.Service does depend on other slices: +Slice Slice2.Service -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class - Slice3 does depend on other slices: -Slice3 -> Slice1 + Slice Slice3 does depend on other slices: +Slice Slice3 -> Slice Slice1 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice1.Slice1Class - Slice3.Group1 does depend on other slices: -Slice3.Group1 -> Slice3 + Slice Slice3.Group1 does depend on other slices: +Slice Slice3.Group1 -> Slice Slice3 SlicesTestAssembly.MultipleSubnamespaces.Slice3.Group1.Group1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice3.Slice3Class diff --git a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_ReturnsDescriptiveDependencyMessage.verified.txt b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_ReturnsDescriptiveDependencyMessage.verified.txt index 448e70e4b..56687bc1e 100644 --- a/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_ReturnsDescriptiveDependencyMessage.verified.txt +++ b/ArchUnitNETTests/Fluent/Slices/Snapshots/SlicesTests.NotDependOnEachOther_ReturnsDescriptiveDependencyMessage.verified.txt @@ -1,17 +1,17 @@ Query: Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**).." should not depend on each other Result: False -Description: Slice1 does depend on other slices: -Slice1 -> Slice2 +Description: Slice Slice1 does depend on other slices: +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Service.Service1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class Result: True -Description: Slice2 does not depend on another slice. +Description: Slice Slice2 does not depend on another slice. Result: True -Description: Slice3 does not depend on another slice. +Description: Slice Slice3 does not depend on another slice. Message: "Slices matching "SlicesTestAssembly.MultipleSubnamespaces.(**).." should not depend on each other" failed: - Slice1 does depend on other slices: -Slice1 -> Slice2 + Slice Slice1 does depend on other slices: +Slice Slice1 -> Slice Slice2 SlicesTestAssembly.MultipleSubnamespaces.Slice1.Service.Service1Class -> SlicesTestAssembly.MultipleSubnamespaces.Slice2.Service.Service2Class diff --git a/documentation/docs/guide.md b/documentation/docs/guide.md index 2c522a8c1..ccf6d5a52 100644 --- a/documentation/docs/guide.md +++ b/documentation/docs/guide.md @@ -174,13 +174,46 @@ IArchRule rule = Classes().That().DoNotHaveAnyAttributes(typeof(Display)).Should .NotDependOnAny(Classes().That().AreAssignableTo(typeof(ICanvas))); ``` -### 3.6. Cycle Rule +### 3.6. Slice Rules +Slices group types by namespace. A *slice* is the set of types whose namespaces produced the same +captured values from a pattern -- with `"App.(*)"`, the types in `App.Orders` form one slice, those in +`App.Shipping` another. + +To use the `Slices()` entry point directly, add: +```cs +using static ArchUnitNET.Fluent.Slices.SliceRuleDefinition; +``` + +#### How slices are named +A slice is identified by **what its capture groups captured**, in group order. Two types end up in +the same slice exactly when their groups captured the same values. + +A slice is named after its captures: `Slice ` followed by the captured values joined with ` - `. The +name never reads as a namespace, and it is what failure messages and diagrams show. + +| Pattern | Namespace | Slice name | +|---|---|---| +| `App.(*)` | `App.Orders` | `Slice Orders` | +| `App.(**)` | `App.Orders.Web` | `Slice Orders.Web` | + +Frozen violations of a slice rule (see `FreezingArchRule`) are stored by the slice name, e.g. +`Slice Orders`. + +#### Cycle-free rule ![Cycle](img/cycle.svg) ```cs IArchRule rule = Slices().Matching("Module.(*)").Should() .BeFreeOfCycles(); ``` +#### No-dependency rule +```cs +IArchRule rule = Slices().Matching("Module.(*)").Should() + .NotDependOnEachOther(); +``` +`NotDependOnEachOther` forbids *any* dependency between slices, where `BeFreeOfCycles` only forbids +circular ones. + ## 4. How to check To get a meaningful error message we recommend using