Skip to content

Slices don't differentiate between (*) and (**) making top-level cycle checks impossible #468

@enolive

Description

@enolive

if I understand the original docs of ArchUnit correctly, there should be a difference between (*) and (**).

  • (*) should target the package
  • (**) should target the package and its sub packages

See also https://www.archunit.org/userguide/html/000_Index.html#_slices

this is however not how the dotnet port of ArchUnit behaves.

If I specify sth. like CycleDemo.(*) I'd expect it to only check cycles on the top-level

so

  • Domain -> Db -> Domain should be detected
  • Domain.Beers -> Domain.Wine -> Domain.Beers should not be detected

it will detect however both cycles effectively behaving like (**)

"Slices matching "CycleDemo.(*)" should be free of cycles" failed:
	Cycle found:
Db -> Domain
	CycleDemo.Db.ViolatingRepository -> CycleDemo.Domain.Service
Domain -> Db
	CycleDemo.Domain.Service -> CycleDemo.Db.Repository

	Cycle found:
Domain.Beers -> Domain.Wines
	CycleDemo.Domain.Beers.Beer -> CycleDemo.Domain.Wines.Wine
Domain.Wines -> Domain.Beers
	CycleDemo.Domain.Wines.Wine -> CycleDemo.Domain.Beers.Beer

I compared it with the behavior of the Java implementation and it works as documented.

Architecture Violation [Priority: MEDIUM] - Rule 'slices matching 'demo.(*)' should be free of cycles' was violated (1 times):
Cycle detected: Slice db -> 
                Slice domain -> 
                Slice db
  1. Dependencies of Slice db
    - Field <demo.db.ViolatingRepository.service> has type <demo.domain.Service> in (ViolatingRepository.java:0)
    - Constructor <demo.db.ViolatingRepository.<init>()> calls constructor <demo.domain.Service.<init>()> in (ViolatingRepository.java:6)
  2. Dependencies of Slice domain
    - Field <demo.domain.Service.repository> has type <demo.db.Repository> in (Service.java:0)
    - Constructor <demo.domain.Service.<init>()> calls constructor <demo.db.Repository.<init>()> in (Service.java:6)

If I look inside the SliceRuleInitializer.cs it confirms my suspicion. A single asterisk will be replaced with a double asterisk (line 81):

var countOfSingleAsterisk =
pattern.Split(new[] { "(*)" }, StringSplitOptions.None).Length - 1;
pattern = pattern.Remove(indexOfAsteriskInPattern) + "(**).";

Am I missing something?

ping me if I should upload my reproduction projects to GitHub!

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIndicates that an issue needs to be categorized.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions