Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HaveAnyAttributes seams to check that all exist is that how it should work? #257

Closed
jnormen opened this issue Apr 22, 2024 · 2 comments
Closed

Comments

@jnormen
Copy link

jnormen commented Apr 22, 2024

When I do:

HaveAnyAttributes(....)
It always require me to have the first attribute set. but when I also add a list of other attributes it force me to have them as well.

.HaveAnyAttributes(typeof(GetAttribute), typeof(PostAttribute), typeof(PutAttribute), typeof(DeleteAttribute))

 For me any sounds like if you find any of those act on them, but not it seams like it force me to have all those 4. 
 This seams odd. Why it's called Any if it not just check if any of them exist and then to the check? 
@mak638
Copy link
Collaborator

mak638 commented May 25, 2024

Hi @jnormen, thank you for your question. To me the method HaveAnyAttributes(...) works exactly as one would expect - the condition is fulfilled if any of the attributes is present for your class, interface, etc. You can find the implementation at the following line:

.Where(type => type.Attributes.Intersect(archAttributeList).Any())

You can also check the following simple Xunit example. The first test passes since the classes all have at least one of the attributes Test1 and Test2. The attribute Test3 is not used anywhere and therefore simply ignored. The second test fails since the classes in question have neither of the three attributes:

[Fact]
public void HaveAnyAttributesPassingTest()
{
    var classesWithAtLeastOneAttribute = Classes()
        .That()
        .Are(typeof(ClassWithAttribute1), typeof(ClassWithAttribute2), typeof(ClassWithBothAttributes))
        .Should()
        .HaveAnyAttributes(typeof(Test1), typeof(Test2), typeof(Test3));

    classesWithAtLeastOneAttribute.Check(Architecture);
}

[Fact]
public void HaveAnyAttributesFailingTest()
{
    var classesWithoutOneOfTheAttributes = Classes()
        .That()
        .Are(typeof(ClassWithoutAttributes), typeof(ClassWithDifferentAttribute))
        .Should()
        .HaveAnyAttributes(typeof(Test1), typeof(Test2), typeof(Test3));

    classesWithoutOneOfTheAttributes.Check(Architecture);
}

[Test1]
internal class ClassWithAttribute1 { }

[Test2]
[Test4]
internal class ClassWithAttribute2 { }

[Test1]
[Test2]
internal class ClassWithBothAttributes { }

internal class ClassWithoutAttributes { }

[Test4]
internal class ClassWithDifferentAttribute{ }

internal class Test1 : Attribute { }

internal class Test2 : Attribute { }

internal class Test3 : Attribute { }

internal class Test4 : Attribute { }

If you still observe unexpected behavior with the method feel free to add a minimal example to your question.

@mak638 mak638 closed this as not planned Won't fix, can't repro, duplicate, stale May 25, 2024
@jnormen
Copy link
Author

jnormen commented May 26, 2024

 [Fact]
    public void Interfaces_Using_Refit_Should_End_With_Api()
    {
        Interfaces()
            .That()
            .HaveAnyAttributes(typeof(GetAttribute))
            .Should()
            .HaveNameEndingWith("Client")
            .Because("All interfaces with Refit attributes should end with 'Api'")
            .Check(Architecture);
    }

GetAttribute is a Refit Atribute. When I do like this the test expect there shall be an Interface using this attribute.
If I add that I want any of the get, post, put attributes then it force me to have all 3 in my code.

So if I do:
.HaveAnyAttributes(typeof(GetAttribute),typeof(PostAttribute))

And I have a GetAttribut no Post it complains there is no Post. And if I have a Post but no Get it says the opposite.
So for me I'm forced to have all the attributes not just one of them.

for example:

 public interface ISvsClient
{
    [Post("/v1/balance-inquiry")]
    public Task<BalanceEnquiryResponse> GetBalanceEnquiryAsync(SvsBalanceEnquiryRequest svsBalanceEnquiryRequest);
}
[Fact]
    public void Interfaces_Using_Refit_Should_End_With_Api()
    {
        Interfaces()
            .That()
            .HaveAnyAttributes(typeof(GetAttribute),typeof(PostAttribute))
            .Should()
            .HaveNameEndingWith("Client")
            .Because("All interfaces with Refit attributes should end with 'Api'")
            .Check(Architecture);
    }

ArchUnitNET.Domain.Exceptions.TypeDoesNotExistInArchitecture: Type Refit.GetAttribute does not exist in provided architecture or is no attribute.

When I wrote the issue I did not check the source code, and now when I answer I haven't checked the source code either, but I see that I use Interface() not classes and are not sure if the implementation is different. I'm on the move now so just wanted to add a fast example as is.

I did not use the .Are(typeof(ClassWithAttribute1), typeof(ClassWithAttribute2), typeof(ClassWithBothAttributes))
things. maybe that something I need to add?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants