Skip to content

Commit

Permalink
Merge pull request #122 from zeiss-digital-innovation/121_FixDuplicat…
Browse files Browse the repository at this point in the history
…ionsInPumlErrormessages

Fix: Duplication in Puml errormessages;
  • Loading branch information
fgather authored Oct 7, 2021
2 parents 7f706a7 + 895269c commit 2db16b7
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,19 @@ ConditionResult Condition(TRuleType ruleType)
.Concat(classDiagramAssociation.GetTargetNamespaceIdentifiers(ruleType))
.ToList());


var pass = true;
var dynamicFailDescription = "does depend on";
foreach (var dependency in ruleType.GetTypeDependencies())

//Prevent failDescriptions like "does depend on X and does depend on X and does depend on Y and does depend on Y
var ruleTypeDependencies = ruleType.GetTypeDependencies().GroupBy(p => p.FullName).Select(g => g.First());
foreach (var dependency in ruleTypeDependencies)
{
if (classDiagramAssociation.Contains(dependency) && !allAllowedTargets.Any(pattern => dependency.FullNameMatches(pattern, true)))
if (classDiagramAssociation.Contains(dependency)
&& !allAllowedTargets.Any(pattern => dependency.FullNameMatches(pattern, true)))
{
dynamicFailDescription += pass ? " " + dependency.FullName : " and " + dependency.FullName;

pass = false;
}
}
Expand Down
16 changes: 11 additions & 5 deletions ArchUnitNETTests/ArchUnitNETTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ArchUnitNET.xUnit\ArchUnitNET.xUnit.csproj" />
<ProjectReference Include="..\TestAssembly\TestAssembly.csproj" />
<ProjectReference Include="..\ArchUnitNET.xUnit\ArchUnitNET.xUnit.csproj"/>
<ProjectReference Include="..\TestAssembly\TestAssembly.csproj"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4"/>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"/>
</ItemGroup>

<ItemGroup>
<None Update="Domain\PlantUml\zzz_test_version_with_errors.puml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
94 changes: 94 additions & 0 deletions ArchUnitNETTests/Domain/PlantUml/PlantUmlErrorMessagesCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ArchUnitNET.Domain;
using ArchUnitNET.Fluent;
using ArchUnitNET.xUnit;
using Xunit;
using static ArchUnitNET.Fluent.ArchRuleDefinition;

namespace ArchUnitNETTests.Domain.PlantUml
{
public class PlantUmlErrorMessagesCheck
{
private static readonly Architecture Architecture = StaticTestArchitectures.ArchUnitNETTestAssemblyArchitecture;
private readonly string _umlFile;

public PlantUmlErrorMessagesCheck()
{
_umlFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Domain", "PlantUml",
"zzz_test_version_with_errors.puml");
}

[Fact]
public void NoDuplicatesInErrorMessageTest()
{
var testPassed = CheckByPuml(out var rawErrormessage);
Assert.False(testPassed);

//CheckForDuplicates returns false when errormessage contains duplicates or is empty
var containsNoDuplicates = ContainsNoDuplicates(rawErrormessage, out var explainErrormessage);

var errormessage = "\nOriginal (ArchUnitNet) Exception:\n" + rawErrormessage +
"\n\nAssert Error:\n" + explainErrormessage + "\n";

Assert.True(containsNoDuplicates, errormessage);
}

private bool CheckByPuml(out string errormessage)
{
errormessage = null;

try
{
IArchRule adhereToPlantUmlDiagram = Types().Should().AdhereToPlantUmlDiagram(_umlFile);
adhereToPlantUmlDiagram.Check(Architecture);
}
//xUnit
catch (FailedArchRuleException exception)
{
errormessage = exception.Message;

return false;
}

return true;
}

private static bool ContainsNoDuplicates(string uncutMessage, out string errormessage)
{
if (string.IsNullOrWhiteSpace(uncutMessage))
{
errormessage = "Error message is empty.";
return false;
}

var sources = new List<string>();

var errors = uncutMessage.Split('\n').Skip(1);

foreach (var error in errors.Where(e => !string.IsNullOrWhiteSpace(e)))
{
var splitError = error.Split(" does depend on ");
var source = splitError[0].Trim();
var targets = splitError[1].Trim().Split(" and ");
if (sources.Contains(source))
{
errormessage = $"Two errors with {source} as source found.";
return false;
}

sources.Add(source);
if (targets.Distinct().Count() < targets.Length)
{
errormessage = $"The error \"{error}\" contains duplicate targets.";
return false;
}
}

errormessage = "No duplicates found.";
return true;
}
}
}
50 changes: 50 additions & 0 deletions ArchUnitNETTests/Domain/PlantUml/zzz_test_version_with_errors.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@startuml


' !!! Test Version !!!
' This PlantUML Diagram will cause errors when you run the ArchUnitNet PLantUML Test
' It is made to check the errormessages that you will get when the codebase architecture does not match the architecture of the PUML
' Unlogical or wrong dependencies are made on purpose

skinparam componentStyle uml2
skinparam component {
BorderColor #grey
BackgroundColor #white
}

[Addresses] <<TestAssembly.PlantUml.Addresses.*>>
[Customers] <<TestAssembly.PlantUml.Customers.*>>
[Orders] <<TestAssembly.PlantUml.Orders.*>>
[Products] <<TestAssembly.PlantUml.Product.*>>
[Product Catalog] <<TestAssembly.PlantUml.Catalog.*>> as catalog
[Product Import] <<TestAssembly.PlantUml.Importer.*>> as import

' Could be some random comment
[XML] <<TestAssembly.PlantUml.XML.Processor.*>> <<TestAssembly.PlantUml.XML.Types.*>> as xml

'Causes Error
[Addresses] <-[#blue]- catalog

'Causes Error
[Orders] <-[#blue]- [Customers] : is placed by
[Orders] --> [Products]
[Orders] --> [Addresses]

'Causes Error
[Customers] <-[#blue]- [Addresses]
[Customers] --> [Products]


[Products] <--[#green]- catalog

'Causes Error
catalog <-[#blue]- [Orders]

import -left-> catalog : parse products
import --> xml
'Causes Error
import <-[#blue]- [Customers]

note top on link #lightgreen: is responsible for translating XML to csharp classes

@enduml
11 changes: 11 additions & 0 deletions TestAssembly/PlantUml/Addresses/Address.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using TestAssembly.PlantUml.Catalog;

namespace TestAssembly.PlantUml.Addresses
{
public class Address
{
#pragma warning disable CS0169
private ProductCatalog productCatalog;
#pragma warning restore CS0169
}
}
22 changes: 22 additions & 0 deletions TestAssembly/PlantUml/Catalog/ProductCatalog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using TestAssembly.PlantUml.Orders;
using TestAssembly.PlantUml.Products;

namespace TestAssembly.PlantUml.Catalog
{
public class ProductCatalog
{
private readonly List<Product> _allProducts = new List<Product>();

internal void GonnaDoSomethingIllegalWithOrder()
{
var order = new Order();
foreach (var product in _allProducts)
{
product.Register();
}

order.AddProducts(_allProducts);
}
}
}
15 changes: 15 additions & 0 deletions TestAssembly/PlantUml/Customers/Customer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using TestAssembly.PlantUml.Addresses;
using TestAssembly.PlantUml.Orders;

namespace TestAssembly.PlantUml.Customers
{
public class Customer
{
public Address Address { get; set; }

internal void AddOrder(Order order)
{
// simply having such a parameter violates the specified UML diagram
}
}
}
21 changes: 21 additions & 0 deletions TestAssembly/PlantUml/Importer/ProductImport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using TestAssembly.PlantUml.Catalog;
using TestAssembly.PlantUml.Customers;
using TestAssembly.PlantUml.Xml.Processor;
using TestAssembly.PlantUml.Xml.Types;

namespace TestAssembly.PlantUml.Importer
{
public class ProductImport
{
public ProductCatalog productCatalog;
public XmlTypes xmlType;
public XmlProcessor xmlProcessor;

public Customer Customer => new Customer(); // violates diagram -> product import may not directly know Customer

private ProductCatalog Parse(byte[] xml)
{
return new ProductCatalog();
}
}
}
31 changes: 31 additions & 0 deletions TestAssembly/PlantUml/Orders/Order.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using TestAssembly.PlantUml.Addresses;
using TestAssembly.PlantUml.Customers;
using TestAssembly.PlantUml.Products;

namespace TestAssembly.PlantUml.Orders
{
public class Order
{
public Customer _customer;
private readonly List<Product> _products = new List<Product>();

public void AddProducts(IList<Product> products)
{
_products.AddRange(products);
}

internal void Report()
{
Report(_customer.Address);
foreach (var product in _products)
{
product.Report();
}
}

private void Report(Address address)
{
}
}
}
21 changes: 21 additions & 0 deletions TestAssembly/PlantUml/Products/Product.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using TestAssembly.PlantUml.Customers;
using TestAssembly.PlantUml.Orders;

namespace TestAssembly.PlantUml.Products
{
public class Product
{
public Customer _customer;

internal Order Order => null; // the return type violates the specified UML diagram


public void Register()
{
}

public void Report()
{
}
}
}
6 changes: 6 additions & 0 deletions TestAssembly/PlantUml/Xml/Processor/XmlProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TestAssembly.PlantUml.Xml.Processor
{
public class XmlProcessor
{
}
}
6 changes: 6 additions & 0 deletions TestAssembly/PlantUml/Xml/Types/XmlTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TestAssembly.PlantUml.Xml.Types
{
public class XmlTypes
{
}
}
6 changes: 6 additions & 0 deletions TestAssembly/PlantUml/Xml/Utils/XmlUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TestAssembly.PlantUml.Xml.Utils
{
public class XmlUtils
{
}
}

0 comments on commit 2db16b7

Please sign in to comment.