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

More Assertions on types #645

Closed
20 of 88 tasks
jnyrup opened this issue Sep 29, 2017 · 21 comments
Closed
20 of 88 tasks

More Assertions on types #645

jnyrup opened this issue Sep 29, 2017 · 21 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation enhancement up-for-grabs

Comments

@jnyrup
Copy link
Member

jnyrup commented Sep 29, 2017

We do have an impressive amount of type assertions.
I've tried to lookup the .net type hierarchy and keywords to see what we might be missing.
See the bottom for types and keywords.

Here's a rough sketch of what such APIs could look like, but please notice that I haven't checked if they are:

  • even possible
  • desirable.

References:

Type hierachy:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/members

  • Members
    • Fields
    • Constants
    • Properties
    • Methods
    • Events
    • Operators
    • Indexers
    • Constructors
    • Finalizers
  • Classes
  • Structs
  • Interfaces
  • StaticConstructors

Keywords and which type they apply to:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/

  • member, type
    • access modifiers:
      • private
      • protected
      • public
      • internal
      • protected Internal
  • classes, fields, methods, properties, operators, events, and constructors
    • static
  • method, property, indexer, or event
    • virtual
    • override
  • member
    • new
  • type
    • abstract
    • unsafe
  • method
    • extern
    • async
  • class
    • sealed
  • class, struct, interface, method
    • partial
  • field
    • volatile
    • readonly
    • const
@dennisdoomen
Copy link
Member

Is this something you need yourself? If not, I really need some help to finish https://github.com/fluentassertions/fluentassertions/milestone/10

@jnyrup
Copy link
Member Author

jnyrup commented Sep 30, 2017

I have a case that could be more readable with ThatAreAbstract.
Aside from that one, I currently don't any of these methods myself.
Let's discuss on Slack how I be of better help.

@melchiork
Copy link
Contributor

Checking partial keyword seems all but impossible. After the compilation all the code is merged into single type and there is no information whatsoever that the class was assembled from multiple parts. One less to worry about.

@obiwanjacobi
Copy link

obiwanjacobi commented Jun 29, 2019

In that same light, you could also think of something like:

noClasses()
        .that()
        .resideIn("..model..")
        .should()
        .dependOnClassesThat()
        .resideIn("..application..");

Not sure how you would phrase that, but the idea here is to make assertions on the design of the code.
Could be a real help to validate architectural rules (Test-Driven-Architecture? ;-)

@Evangelink
Copy link
Contributor

@jnyrup Hey sorry to bother! I am genuinely interested in knowing in which situation you are using tests which ensure a modifier or a keyword. As for now, I have always written tests targeting the "feature" provided by the method but not the "how".

@jnyrup
Copy link
Member Author

jnyrup commented Sep 3, 2019

@Evangelink No need to apologize.
There are some examples in the docs.

At work I've used the type assertion API, as a poor man's code analyzer, to avoid some coding pitfalls.
E.g. using the wrong overload of RangeValidatorAttribute.

For example a double member in our API was annotated with

[RangeValidator(0, RangeBoundaryType.Inclusive, 100, RangeBoundaryType.Inclusive)]

but should have been

[RangeValidator(0.0, RangeBoundaryType.Inclusive, 100.0, RangeBoundaryType.Inclusive)]

IIRC the int overload downcasts the double to an int, so a value of 100.7 was accepted, but should have been rejected.

Then I wrote a unit test, that scans our API using the type assertion API to detect such cases.

@Evangelink
Copy link
Contributor

Oh, I see! I had a few cases like that in the past but I went for the analyzer option :)
Anyway good to know about this.

Thank you @jnyrup

@rubenrorije
Copy link
Contributor

I think this is extremely useful. I am doing similar things to the RangeValidator test above in my projects to enforce certain project specific implementation policies without having to create code analyzers (which I did not study yet).
My specific usecase in this case was to make sure that certain interfaces were implemented explicitly and it would be useful to have this out-of-the-box.
Some additions I did create in my own project:

  • ClassSelector
    • ThatAreValueTypes
    • ThatArePublicOrInternal
  • ClassAssertions
    • ImplementsExplicit

inyutin-maxim added a commit to inyutin-maxim/fluentassertions that referenced this issue Jun 22, 2021
+ public TypeSelector ThatImplement(Type interfaceType)
+ public TypeSelector ThatDoNotImplement(Type interfaceType)
+ public TypeSelector ThatAreDecoratedWith(Type attribute)
+ public TypeSelector ThatAreDecoratedWithOrInherit(Type attribute)
+ public TypeSelector ThatAreNotDecoratedWith(Type attribute)
+ public TypeSelector ThatAreNotDecoratedWithOrInherit(Type attribute)
@chvollm
Copy link
Contributor

chvollm commented Oct 28, 2021

I think this issues needs some updates. A lot of things seem to have been implemented over the past years.

@jnyrup
Copy link
Member Author

jnyrup commented Oct 28, 2021

@chvollm I had a look at it and saw that I hadn't updated this with the contributions from #1306.
Did you spot more?

@chvollm
Copy link
Contributor

chvollm commented Oct 28, 2021

@jnyrup Just a gut feel when I looked at it. I'll try to have a thorough look next week.

@chvollm
Copy link
Contributor

chvollm commented Oct 28, 2021

@jnyrup Just quickly. Maybe I misunderstand this issue, but in #1700 I completed the BeAsync stuff on the methods. Is that different from the things discussed in this issue? Above it says on MethodInfoSelector "ThatAre[Not]Async". Do I misunderstand something here?

@jnyrup
Copy link
Member Author

jnyrup commented Oct 28, 2021

The ones in #1700 are for MethodInfoSelectorAssertions.
MethodInfoSelector is another class used to filter methods.
E.g.

typeof(MyType)
    .Methods() // <-- returns a MethodInfoSelector
    .ThatAreAsync() // <-- MethodInfoSelector
    .Should() // <-- returns a MethodInfoSelectorAssertions
    .BeDecoratedWith<MyAttribute>(); // <-- MethodInfoSelectorAssertions

@chvollm
Copy link
Contributor

chvollm commented Oct 28, 2021

OK, thanks for the clarification. Now I get it. Sorry.

@chvollm
Copy link
Contributor

chvollm commented Nov 11, 2021

@jnyrup Is there an ordered list of top 10 requests?

@jnyrup
Copy link
Member Author

jnyrup commented Nov 11, 2021

@jnyrup Is there an ordered list of top 10 requests?

For the APIs from this issue?
No.
I would probably go with what brings most consistency across all type assertions classes.

@94sedighi
Copy link
Contributor

hi @jnyrup
I am working on PropertyInfo and PropertyInfoSelector (ThatAreOverridable and ThatAreNotOverridable) and i have finished the implementation and tests. But some ApproveApi Tests fails, because of difference in ...verified.txt and ...recieved.txt. Are we supposed to enter the changes manually to the ...verified.txt files?

@jnyrup
Copy link
Member Author

jnyrup commented Nov 30, 2022

You can run one of the AcceptApiChanges scripts from the root folder.

@94sedighi
Copy link
Contributor

94sedighi commented Nov 30, 2022

@jnyrup
In PropertyInfoSelector you wanted also to have ThatAre[Not]Sealed, but it is difficult to find out if a property is marked as sealed, MethodInfo class don't offer a property or a method to check it.
but the purpose of checking a property for sealed is to make sure that it is not overridable, and i have already implemented this feature, so you can remove it from checklist.

And as i understand PropertyInfoSelector.cs is only a filter, so we can implement the functionalities there and test them in PropertyInfoSelectorSpecs.cs am i right?

If yes, then i will make a pull request for PropertyInfoSelector, MethodInfoSelector and MemberInfoAssertions funtionalities, which contains the following functionalities:

PropertyInfoSelector:

  • ThatAre[Not]Overridable as property
  • ThatAre[Not]Static as property
  • ThatAre[Not]Abstract as property
  • ThatAre[Not]Virtual as property

MethodInfoSelector:

  • ThatAre[Not]Abstract() as Method
  • ThatAre[Not]Overridable() as Method

evtl. MemberInfoAssertions:

  • [Not]HaveAccessModifier
  • [Not]BeOverridable
  • [Not]BeStatic
  • [Not]BeAbstract

To extend PropertyInfoSelector with these new functionalities, i have written some extensions in PropertyInfoExtensions.cs and so we can also extend the PropertyInfoAssertions.cs and PropertyInfoSelectorAssertions.cs with these new functionalities like:

PropertyInfoAssertions and PropertyInfoSelectorAssertions:

  • [Not]BeOverridable
  • [Not]BeStatic
  • [Not]BeAbstract

MethodInfoAssertions:

  • [Not]BeAbstract()
  • [Not]BeOverridable()

@jnyrup jnyrup added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Dec 1, 2022
@jnyrup
Copy link
Member Author

jnyrup commented Dec 1, 2022

In PropertyInfoSelector you wanted also to have ThatAre[Not]Sealed, but it is difficult to find out if a property is marked as sealed, MethodInfo Class don't offer a property or a method to check it.

When I created this ticket 5 years ago I spend little to no time thinking about what APIs would actually be useful - I even see that I wrote

Here's a rough sketch of what such APIs could look like, but please notice that I haven't checked if they are:

  • even possible
  • desirable.

Over the years that have passed we have become much more aware about what the value of an API is before adding it.
It so to speak "needs to pull its own weight".

As I re-read this issue I suspect that the Overridable APIs would be the least used of those you mention and also have some caveats (e.g. a virtual method is not overridable if the class is sealed and probably more corners of the C# language specifications that I don't know about).
If you still find it useful, I suggest you open a new issue specifically for that.
All the other you mention (Static, Abstract, HaveAccessModifier) looks complementary to what we already offer in the other areas of our type assertions 👍

And as i understand PropertyInfoSelector.cs is only a filter, so we can implement the functionalities there and test them in PropertyInfoSelectorSpecs.cs am i right?

I'm not sure I understand your question, but in general we want to test functionalities through their public APIs, so PropertyInfoSelector should be tested in PropertyInfoSelectorSpecs.cs and PropertyInfoSelectorAssertions in PropertyInfoSelectorAssertionSpecs.cs.

@jnyrup
Copy link
Member Author

jnyrup commented Dec 19, 2022

Thanks for all the implementations contributed over the years ❤️
I'm closing this issue for now since the vast majority of the APIs I brainstormed back then have now been implemented and remaining ones are getting more and more esoteric to see in a unit test.

For the remainder of the APIs, if you would find it useful in your usage of Fluent Assertions, please open a new issue describing the use-case, then we can discuss the it there.

@jnyrup jnyrup closed this as completed Dec 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation enhancement up-for-grabs
Projects
None yet
Development

No branches or pull requests

8 participants