Skip to content

Commit

Permalink
Add ThatAre[Not]Abstract, ThatAre[Not]Static and `ThatAre[Not]Vir…
Browse files Browse the repository at this point in the history
…tual` to `PropertyInfoSelector` (#2054)
  • Loading branch information
94sedighi committed Dec 8, 2022
1 parent 0a04100 commit d1f2ade
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 10 deletions.
12 changes: 12 additions & 0 deletions Src/FluentAssertions/Common/PropertyInfoExtensions.cs
Expand Up @@ -9,4 +9,16 @@ internal static bool IsVirtual(this PropertyInfo property)
MethodInfo methodInfo = property.GetGetMethod(nonPublic: true) ?? property.GetSetMethod(nonPublic: true);
return !methodInfo.IsNonVirtual();
}

internal static bool IsStatic(this PropertyInfo property)
{
MethodInfo methodInfo = property.GetGetMethod(nonPublic: true) ?? property.GetSetMethod(nonPublic: true);
return methodInfo.IsStatic;
}

internal static bool IsAbstract(this PropertyInfo property)
{
MethodInfo methodInfo = property.GetGetMethod(nonPublic: true) ?? property.GetSetMethod(nonPublic: true);
return methodInfo.IsAbstract;
}
}
75 changes: 74 additions & 1 deletion Src/FluentAssertions/Types/PropertyInfoSelector.cs
Expand Up @@ -35,7 +35,8 @@ public PropertyInfoSelector(IEnumerable<Type> types)
Guard.ThrowIfArgumentContainsNull(types, nameof(types));

selectedProperties = types.SelectMany(t => t
.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance
| BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
}

/// <summary>
Expand All @@ -55,6 +56,78 @@ public PropertyInfoSelector ThatArePublicOrInternal
}
}

/// <summary>
/// Only select the properties that are abstract
/// </summary>
public PropertyInfoSelector ThatAreAbstract
{
get
{
selectedProperties = selectedProperties.Where(property => property.IsAbstract());
return this;
}
}

/// <summary>
/// Only select the properties that are not abstract
/// </summary>
public PropertyInfoSelector ThatAreNotAbstract
{
get
{
selectedProperties = selectedProperties.Where(property => !property.IsAbstract());
return this;
}
}

/// <summary>
/// Only select the properties that are static
/// </summary>
public PropertyInfoSelector ThatAreStatic
{
get
{
selectedProperties = selectedProperties.Where(property => property.IsStatic());
return this;
}
}

/// <summary>
/// Only select the properties that are not static
/// </summary>
public PropertyInfoSelector ThatAreNotStatic
{
get
{
selectedProperties = selectedProperties.Where(property => !property.IsStatic());
return this;
}
}

/// <summary>
/// Only select the properties that are virtual
/// </summary>
public PropertyInfoSelector ThatAreVirtual
{
get
{
selectedProperties = selectedProperties.Where(property => property.IsVirtual());
return this;
}
}

/// <summary>
/// Only select the properties that are not virtual
/// </summary>
public PropertyInfoSelector ThatAreNotVirtual
{
get
{
selectedProperties = selectedProperties.Where(property => !property.IsVirtual());
return this;
}
}

/// <summary>
/// Only select the properties that are decorated with an attribute of the specified type.
/// </summary>
Expand Down
Expand Up @@ -2526,7 +2526,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down Expand Up @@ -2765,4 +2771,4 @@ namespace FluentAssertions.Xml
public bool CanHandle(object value) { }
public void Format(object value, FluentAssertions.Formatting.FormattedObjectGraph formattedGraph, FluentAssertions.Formatting.FormattingContext context, FluentAssertions.Formatting.FormatChild formatChild) { }
}
}
}
Expand Up @@ -2656,7 +2656,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down
Expand Up @@ -2528,7 +2528,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down
Expand Up @@ -2528,7 +2528,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down
Expand Up @@ -2477,7 +2477,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down
Expand Up @@ -2528,7 +2528,13 @@ namespace FluentAssertions.Types
{
public PropertyInfoSelector(System.Collections.Generic.IEnumerable<System.Type> types) { }
public PropertyInfoSelector(System.Type type) { }
public FluentAssertions.Types.PropertyInfoSelector ThatAreAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotAbstract { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreNotVirtual { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatArePublicOrInternal { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreStatic { get; }
public FluentAssertions.Types.PropertyInfoSelector ThatAreVirtual { get; }
public System.Collections.Generic.IEnumerator<System.Reflection.PropertyInfo> GetEnumerator() { }
public FluentAssertions.Types.PropertyInfoSelector NotOfType<TReturn>() { }
public FluentAssertions.Types.PropertyInfoSelector OfType<TReturn>() { }
Expand Down
126 changes: 118 additions & 8 deletions Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentAssertions.Types;
using Internal.Main.Test;
Expand Down Expand Up @@ -73,15 +74,91 @@ public void When_selecting_properties_from_types_in_an_assembly_it_should_return
public void When_selecting_properties_that_are_public_or_internal_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);
Type type = typeof(TestClassForPropertySelectorWithInternalAndPublicProperties);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatArePublicOrInternal.ToArray();

// Assert
const int PublicPropertyCount = 3;
const int InternalPropertyCount = 1;
properties.Should().HaveCount(PublicPropertyCount + InternalPropertyCount);
properties.Should().HaveCount(2);
}

[Fact]
public void When_selecting_properties_that_are_abstract_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreAbstract.ToArray();

// Assert
properties.Should().HaveCount(2);
}

[Fact]
public void When_selecting_properties_that_are_not_abstract_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreNotAbstract.ToArray();

// Assert
properties.Should().HaveCount(10);
}

[Fact]
public void When_selecting_properties_that_are_static_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreStatic.ToArray();

// Assert
properties.Should().HaveCount(4);
}

[Fact]
public void When_selecting_properties_that_are_not_static_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreNotStatic.ToArray();

// Assert
properties.Should().HaveCount(8);
}

[Fact]
public void When_selecting_properties_that_are_virtual_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreVirtual.ToArray();

// Assert
properties.Should().HaveCount(7);
}

[Fact]
public void When_selecting_properties_that_are_not_virtual_it_should_return_only_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

// Act
IEnumerable<PropertyInfo> properties = type.Properties().ThatAreNotVirtual.ToArray();

// Assert
properties.Should().HaveCount(5);
}

[Fact]
Expand Down Expand Up @@ -123,7 +200,7 @@ public void When_selecting_methods_that_return_a_specific_type_it_should_return_
IEnumerable<PropertyInfo> properties = type.Properties().OfType<string>().ToArray();

// Assert
properties.Should().HaveCount(2);
properties.Should().HaveCount(8);
}

[Fact]
Expand Down Expand Up @@ -271,15 +348,48 @@ public void When_selecting_properties_return_types_it_should_return_the_correct_

// Assert
returnTypes.Should()
.BeEquivalentTo(new[] { typeof(string), typeof(string), typeof(int), typeof(int), typeof(int), typeof(int) });
.BeEquivalentTo(new[]
{
typeof(string), typeof(string), typeof(string), typeof(string)
, typeof(string), typeof(string), typeof(string)
, typeof(string), typeof(int), typeof(int), typeof(int), typeof(int)
});
}
}

#region Internal classes used in unit tests

internal class TestClassForPropertySelector
internal class TestClassForPropertySelectorWithInternalAndPublicProperties
{
public virtual string PublicVirtualStringProperty { get; set; }
public static string PublicStaticStringProperty { get; }

internal static string InternalStaticStringProperty { get; set; }

protected static string ProtectedStaticStringProperty { get; set; }

private static string PrivateStaticStringProperty { get; set; }
}

internal abstract class TestClassForPropertySelector
{
private static string myPrivateStaticStringField;

public static string PublicStaticStringProperty { set => myPrivateStaticStringField = value; }

internal static string InternalStaticStringProperty { get; set; }

protected static string ProtectedStaticStringProperty { get; set; }

private static string PrivateStaticStringProperty { get; set; }

// An abstract method/property is implicitly a virtual method/property.
public abstract string PublicAbstractStringProperty { get; set; }

public abstract string PublicAbstractStringPropertyWithSetterOnly { set; }

private string myPrivateStringField;

public virtual string PublicVirtualStringProperty { set => myPrivateStringField = value; }

[DummyProperty]
public virtual string PublicVirtualStringPropertyWithAttribute { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions docs/_pages/releases.md
Expand Up @@ -10,9 +10,13 @@ sidebar:
## Unreleased

### What's new
* Added `ThatAre[Not]Abstract`, `ThatAre[Not]Static` and `ThatAre[Not]Virtual` properties for filtering in `PropertyInfoSelector.cs` - [#2054](https://github.com/fluentassertions/fluentassertions/pull/2054)
* Added `BeOneOf` methods for object comparisons and `IComparable`s - [#2028](https://github.com/fluentassertions/fluentassertions/pull/2028)
* Added `BeCloseTo` and `NotBeCloseTo` to `TimeOnly` - [#2030](https://github.com/fluentassertions/fluentassertions/pull/2030)

### Fixes
* Quering properties on classes, e.g. `typeof(MyClass).Properties()`, now also includes static properties - [#2054](https://github.com/fluentassertions/fluentassertions/pull/2054)

## 6.8.0

### What's new
Expand Down

0 comments on commit d1f2ade

Please sign in to comment.