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

Add ThatAre[Not]Abstract, ThatAre[Not]Static and ThatAre[Not]Virtual to PropertyInfoSelector #2054

Merged
merged 11 commits into from Dec 8, 2022
27 changes: 27 additions & 0 deletions Src/FluentAssertions/Common/PropertyInfoExtensions.cs
Expand Up @@ -4,9 +4,36 @@ namespace FluentAssertions.Common;

internal static class PropertyInfoExtensions
{
/// <summary>
/// Checks if the property is virtual
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
internal static bool IsVirtual(this PropertyInfo property)
{
MethodInfo methodInfo = property.GetGetMethod(nonPublic: true) ?? property.GetSetMethod(nonPublic: true);
return !methodInfo.IsNonVirtual();
}

/// <summary>
/// Checks if the property is static
94sedighi marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
internal static bool IsStatic(this PropertyInfo property)
{
MethodInfo methodInfo = property.GetGetMethod(nonPublic: true) ?? property.GetSetMethod(nonPublic: true);
return methodInfo.IsStatic;
}

/// <summary>
/// Checks if the property is Abstract
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
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
94sedighi marked this conversation as resolved.
Show resolved Hide resolved
| 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
108 changes: 103 additions & 5 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 @@ -79,11 +80,92 @@ public void When_selecting_properties_that_are_public_or_internal_it_should_retu
IEnumerable<PropertyInfo> properties = type.Properties().ThatArePublicOrInternal.ToArray();

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

[Fact]
public void When_selecting_properteis_that_are_abstract_it_should_return_only_the_applicable_properties()
jnyrup marked this conversation as resolved.
Show resolved Hide resolved
{
// Arrange
Type type = typeof(TestClassForPropertySelector);

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

// Assert
int abstractPropertiesCount = 1;
jnyrup marked this conversation as resolved.
Show resolved Hide resolved
properties.Should().HaveCount(abstractPropertiesCount);
}

[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
int notArbastractPropertiesCount = 10;
properties.Should().HaveCount(notArbastractPropertiesCount);
}

[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(7);
}

[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(6);
}

[Fact]
public void When_seletcing_properties_that_are_not_virtual_it_should_return_only_the_applicable_properties()
{
94sedighi marked this conversation as resolved.
Show resolved Hide resolved
// Arrange
Type type = typeof(TestClassForPropertySelector);

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

// Assert
int notVirtualPropertiesCount = 5;
properties.Should().HaveCount(notVirtualPropertiesCount);
}

[Fact]
public void When_selecting_properties_decorated_with_specific_attribute_it_should_return_only_the_applicable_properties()
{
Expand Down Expand Up @@ -123,7 +205,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(7);
}

[Fact]
Expand Down Expand Up @@ -271,14 +353,30 @@ 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(int), typeof(int), typeof(int), typeof(int)
});
}
}

#region Internal classes used in unit tests

internal class TestClassForPropertySelector
internal abstract class TestClassForPropertySelector
{
public static string PublicStaticStringProperty { get; set; }

internal static string InternalStaticStringProperty { get; set; }

protected static string ProtectedStaticStringProperty { get; set; }

private static string ProtectedStaticStringPropertyWithAttribute { get; set; }
jnyrup marked this conversation as resolved.
Show resolved Hide resolved

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

public virtual string PublicVirtualStringProperty { get; set; }

[DummyProperty]
Expand Down