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

Extend ThatArePublicOrInternal to also look at the setter of properties #2082

Merged
merged 12 commits into from Jan 10, 2023
6 changes: 3 additions & 3 deletions Src/FluentAssertions/Types/PropertyInfoSelector.cs
Expand Up @@ -40,16 +40,16 @@ public PropertyInfoSelector(IEnumerable<Type> types)
}

/// <summary>
/// Only select the properties that have a public or internal getter.
/// Only select the properties that have at least one public or internal accessor
/// </summary>
public PropertyInfoSelector ThatArePublicOrInternal
{
get
{
selectedProperties = selectedProperties.Where(property =>
{
MethodInfo getter = property.GetGetMethod(nonPublic: true);
return (getter is not null) && (getter.IsPublic || getter.IsAssembly);
return property.GetGetMethod(nonPublic: true) is { IsPublic: true } or { IsAssembly: true }
|| property.GetSetMethod(nonPublic: true) is { IsPublic: true } or { IsAssembly: true };
});

return this;
Expand Down
87 changes: 68 additions & 19 deletions Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentAssertions.Types;
using Internal.Main.Test;
Expand Down Expand Up @@ -216,23 +215,6 @@ public void When_selecting_methods_that_do_not_return_a_specific_type_it_should_
properties.Should().HaveCount(4);
}

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

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

// Assert
properties.Should().ContainSingle();
}

[Fact]
public void When_selecting_properties_decorated_with_an_inheritable_attribute_it_should_only_return_the_applicable_properties()
{
Expand Down Expand Up @@ -355,6 +337,74 @@ public void When_selecting_properties_return_types_it_should_return_the_correct_
, typeof(string), typeof(int), typeof(int), typeof(int), typeof(int)
});
}

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

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

// Assert
properties.Should().ContainSingle();
}

[Fact]
public void When_a_property_only_has_a_public_setter_it_should_be_included_in_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPublicSetter);

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

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

private class TestClassForPublicSetter
{
private static string myPrivateStaticStringField;

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

public static string InternalStaticStringProperty { get; set; }

public int PublicIntProperty { get; init; }
}

[Fact]
public void When_selecting_properties_with_at_least_one_accessor_being_private_should_return_the_applicable_properties()
{
// Arrange
Type type = typeof(TestClassForPrivateAccessors);

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

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

private class TestClassForPrivateAccessors
{
public bool PublicBoolPrivateGet { private get; set; }

public bool PublicBoolPrivateSet { get; private set; }

internal bool InternalBoolPrivateGet { private get; set; }

internal bool InternalBoolPrivateSet { get; private set; }
}
}
}

#region Internal classes used in unit tests
Expand Down Expand Up @@ -455,5 +505,4 @@ public DummyPropertyAttribute(string value)

public string Value { get; private set; }
}

#endregion
1 change: 1 addition & 0 deletions docs/_pages/releases.md
Expand Up @@ -20,6 +20,7 @@ sidebar:
* Added new extension methods to be able to write `Exactly.Times(n)`, `AtLeast.Times(n)` and `AtMost.Times(n)` in a more fluent way - [#2047](https://github.com/fluentassertions/fluentassertions/pull/2047)

### Fixes
* `PropertyInfoSelector.ThatArePublicOrInternal` now takes the setter into account when determining if a property is `public` or `internal` - [#2082] (https://github.com/fluentassertions/fluentassertions/pull/2082)
* Quering properties on classes, e.g. `typeof(MyClass).Properties()`, now also includes static properties - [#2054](https://github.com/fluentassertions/fluentassertions/pull/2054)
* Nested AssertionScopes now print the inner scope reportables - [#2044](https://github.com/fluentassertions/fluentassertions/pull/2044)
* Throw `ArgumentException` instead of `ArgumentNullException` when a required `string` argument is empty - [#2023](https://github.com/fluentassertions/fluentassertions/pull/2023)
Expand Down