diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0907a1aa16..74a49d36c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,4 +5,4 @@ No open-source project is going to be successful without contributions. After we * The [Pull Request](https://help.github.com/articles/using-pull-requests) is targeted at the `develop` branch. * The code complies with the [Coding Guidelines for C# 3.0, 4.0 and 5.0](https://csharpcodingguidelines.com/)/. * The changes are covered by a new or existing set of unit tests which follow the Arrange-Act-Assert syntax such as is used [in this example](https://github.com/fluentassertions/fluentassertions/blob/daaf35b9b59b622c96d0c034e8972a020b2bee55/Tests/FluentAssertions.Shared.Specs/BasicEquivalencySpecs.cs#L33). -* If the contribution affects the documentation, please update [**the documentation**](https://github.com/fluentassertions/fluentassertions/tree/master/docs), which is published on the [website](https://fluentassertions.com/documentation/). +* If the contribution affects the documentation, please update [**the documentation**](https://github.com/fluentassertions/fluentassertions/tree/master/docs), which is published on the [website](https://fluentassertions.com/introduction). diff --git a/Src/FluentAssertions/TypeEnumerableExtensions.cs b/Src/FluentAssertions/TypeEnumerableExtensions.cs index bd6042de90..8f085896a2 100644 --- a/Src/FluentAssertions/TypeEnumerableExtensions.cs +++ b/Src/FluentAssertions/TypeEnumerableExtensions.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using System.Threading.Tasks; using FluentAssertions.Types; namespace FluentAssertions @@ -77,5 +77,61 @@ public static IEnumerable ThatImplement(this IEnumerable types) { return new TypeSelector(types).ThatImplement(); } + + /// + /// Filters to only include types that are classes. + /// + public static IEnumerable ThatAreClasses(this IEnumerable types) + { + return new TypeSelector(types).ThatAreClasses(); + } + + /// + /// Filters to only include types that are not classes. + /// + public static IEnumerable ThatAreNotClasses(this IEnumerable types) + { + return new TypeSelector(types).ThatAreNotClasses(); + } + + /// + /// Filters to only include types that are static. + /// + public static IEnumerable ThatAreStatic(this IEnumerable types) + { + return new TypeSelector(types).ThatAreStatic(); + } + + /// + /// Filters to only include types that are not static. + /// + public static IEnumerable ThatAreNotStatic(this IEnumerable types) + { + return new TypeSelector(types).ThatAreNotStatic(); + } + + /// + /// Filters to only include types that satisfies the passed. + /// + public static IEnumerable ThatSatisfy(this IEnumerable types, Func predicate) + { + return new TypeSelector(types).ThatSatisfy(predicate); + } + + /// + /// Returns T for the types which are or ; the type itself otherwise + /// + public static IEnumerable UnwrapTaskTypes(this IEnumerable types) + { + return new TypeSelector(types).UnwrapTaskTypes(); + } + + /// + /// Returns T for the types which are or implement the ; the type itself otherwise + /// + public static IEnumerable UnwrapEnumerableTypes(this IEnumerable types) + { + return new TypeSelector(types).UnwrapEnumerableTypes(); + } } } diff --git a/Src/FluentAssertions/Types/MethodInfoSelector.cs b/Src/FluentAssertions/Types/MethodInfoSelector.cs index 56edd80fd6..5140121599 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelector.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelector.cs @@ -128,6 +128,17 @@ public MethodInfoSelector ThatAreNotDecoratedWithOrInherit() return this; } + /// + /// Select return types of the methods + /// + /// + public TypeSelector ReturnTypes() + { + var returnTypes = selectedMethods.Select(mi => mi.ReturnType); + + return new TypeSelector(returnTypes); + } + /// /// The resulting objects. /// diff --git a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs index 04da39fa8d..aa60766afe 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs @@ -205,6 +205,52 @@ public AndConstraint NotBeDecoratedWith(this); } + /// + /// Asserts that the selected methods have specified . + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint Be(CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) + { + var methods = SubjectMethods.Where(pi => pi.GetCSharpAccessModifier() != accessModifier).ToArray(); + var message = $"Expected all selected methods to be {accessModifier}{{reason}}, but the following methods are not:" + Environment.NewLine + GetDescriptionsFor(methods); + + Execute.Assertion + .ForCondition(!methods.Any()) + .BecauseOf(because, becauseArgs) + .FailWith(message); + + return new AndConstraint(this); + } + + /// + /// Asserts that the selected methods don't have specified + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint NotBe(CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) + { + var methods = SubjectMethods.Where(pi => pi.GetCSharpAccessModifier() == accessModifier).ToArray(); + var message = $"Expected all selected methods to not be {accessModifier}{{reason}}, but the following methods are:" + Environment.NewLine + GetDescriptionsFor(methods); + + Execute.Assertion + .ForCondition(!methods.Any()) + .BecauseOf(because, becauseArgs) + .FailWith(message); + + return new AndConstraint(this); + } + private MethodInfo[] GetMethodsWithout(Expression> isMatchingPredicate) where TAttribute : Attribute { diff --git a/Src/FluentAssertions/Types/PropertyInfoSelector.cs b/Src/FluentAssertions/Types/PropertyInfoSelector.cs index f46e342f9c..db0def8229 100644 --- a/Src/FluentAssertions/Types/PropertyInfoSelector.cs +++ b/Src/FluentAssertions/Types/PropertyInfoSelector.cs @@ -108,6 +108,17 @@ public PropertyInfoSelector NotOfType() return this; } + /// + /// Select return types of the properties + /// + /// + public TypeSelector ReturnTypes() + { + var returnTypes = selectedProperties.Select(mi => mi.PropertyType); + + return new TypeSelector(returnTypes); + } + /// /// The resulting objects. /// diff --git a/Src/FluentAssertions/Types/TypeSelector.cs b/Src/FluentAssertions/Types/TypeSelector.cs index 28b6cf1d82..39581c599c 100644 --- a/Src/FluentAssertions/Types/TypeSelector.cs +++ b/Src/FluentAssertions/Types/TypeSelector.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using FluentAssertions.Common; namespace FluentAssertions.Types @@ -165,6 +166,107 @@ public TypeSelector ThatAreNotUnderNamespace(string @namespace) return this; } + /// + /// Determines whether the type is a class + /// + public TypeSelector ThatAreClasses() + { + types = types.Where(t => t.IsClass).ToList(); + return this; + } + + /// + /// Determines whether the type is not a class + /// + public TypeSelector ThatAreNotClasses() + { + types = types.Where(t => !t.IsClass).ToList(); + return this; + } + + /// + /// Determines whether the type is static + /// + public TypeSelector ThatAreStatic() + { + types = types.Where(t => t.IsCSharpStatic()).ToList(); + return this; + } + + /// + /// Determines whether the type is not static + /// + public TypeSelector ThatAreNotStatic() + { + types = types.Where(t => !t.IsCSharpStatic()).ToList(); + return this; + } + + /// + /// Allows to filter the types with the passed + /// + public TypeSelector ThatSatisfy(Func predicate) + { + types = types.Where(predicate).ToList(); + return this; + } + + /// + /// Returns T for the types which are or ; the type itself otherwise + /// + public TypeSelector UnwrapTaskTypes() + { + types = types.Select(type => + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>)) + { + return type.GetGenericArguments().Single(); + } + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ValueTask<>)) + { + return type.GetGenericArguments().Single(); + } + return type == typeof(Task) || type == typeof(ValueTask) ? typeof(void) : type; + }).ToList(); + + return this; + } + + /// + /// Returns T for the types which are or implement the ; the type itself otherwise + /// + public TypeSelector UnwrapEnumerableTypes() + { + var unwrappedTypes = new List(); + foreach (Type type in types) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + { + unwrappedTypes.Add(type.GetGenericArguments().Single()); + } + else + { + var iEnumerableImplementations = type + .GetInterfaces() + .Where(iType => iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + .Select(ied => ied.GetGenericArguments().Single()) + .ToList(); + + if (iEnumerableImplementations.Any()) + { + unwrappedTypes.AddRange(iEnumerableImplementations); + } + else + { + unwrappedTypes.Add(type); + } + } + } + + types = unwrappedTypes; + return this; + } + /// /// Returns an enumerator that iterates through the collection. /// diff --git a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs index 55c7561a8d..85a756359a 100644 --- a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs @@ -292,6 +292,48 @@ public AndConstraint NotBeDecoratedWithOrInherit(this); } + /// + /// Asserts that the selected types are sealed + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint BeSealed(string because = "", params object[] becauseArgs) + { + var notSealedTypes = Subject.Where(type => !type.IsCSharpSealed()).ToArray(); + + Execute.Assertion.ForCondition(!notSealedTypes.Any()) + .BecauseOf(because, becauseArgs) + .FailWith("Expected all types to be sealed{reason}, but the following types are not:{0}{1}.", Environment.NewLine, GetDescriptionsFor(notSealedTypes)); + + return new AndConstraint(this); + } + + /// + /// Asserts that the all are not sealed classes + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) + { + var sealedTypes = Subject.Where(type => type.IsCSharpSealed()).ToArray(); + + Execute.Assertion.ForCondition(!sealedTypes.Any()) + .BecauseOf(because, becauseArgs) + .FailWith("Expected all types not to be sealed{reason}, but the following types are:{0}{1}.", Environment.NewLine, GetDescriptionsFor(sealedTypes)); + + return new AndConstraint(this); + } + private static string GetDescriptionsFor(IEnumerable types) { string[] descriptions = types.Select(GetDescriptionFor).ToArray(); diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.approved.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.approved.txt index a3c7f45b5b..ee2d22fe62 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.approved.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.approved.txt @@ -229,18 +229,25 @@ namespace FluentAssertions } public static class TypeEnumerableExtensions { + public static System.Collections.Generic.IEnumerable ThatAreClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreInNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } + public static System.Collections.Generic.IEnumerable ThatAreNotClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } + public static System.Collections.Generic.IEnumerable ThatAreNotStatic(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatAreStatic(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreUnderNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } public static System.Collections.Generic.IEnumerable ThatDeriveFrom(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatImplement(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatSatisfy(this System.Collections.Generic.IEnumerable types, System.Func predicate) { } + public static System.Collections.Generic.IEnumerable UnwrapEnumerableTypes(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable UnwrapTaskTypes(this System.Collections.Generic.IEnumerable types) { } } public static class TypeExtensions { @@ -1931,6 +1938,7 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturnVoid { get; } public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() @@ -1948,11 +1956,13 @@ namespace FluentAssertions.Types public MethodInfoSelectorAssertions(params System.Reflection.MethodInfo[] methods) { } protected string Context { get; } public System.Collections.Generic.IEnumerable SubjectMethods { get; } + public FluentAssertions.AndConstraint Be(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -1984,6 +1994,7 @@ namespace FluentAssertions.Types public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.PropertyInfoSelector NotOfType() { } public FluentAssertions.Types.PropertyInfoSelector OfType() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWithOrInherit() @@ -2093,23 +2104,30 @@ namespace FluentAssertions.Types public TypeSelector(System.Collections.Generic.IEnumerable types) { } public TypeSelector(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ThatAreClasses() { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotClasses() { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotStatic() { } public FluentAssertions.Types.TypeSelector ThatAreNotUnderNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreStatic() { } public FluentAssertions.Types.TypeSelector ThatAreUnderNamespace(string @namespace) { } public FluentAssertions.Types.TypeSelector ThatDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotImplement() { } public FluentAssertions.Types.TypeSelector ThatImplement() { } + public FluentAssertions.Types.TypeSelector ThatSatisfy(System.Func predicate) { } public System.Type[] ToArray() { } + public FluentAssertions.Types.TypeSelector UnwrapEnumerableTypes() { } + public FluentAssertions.Types.TypeSelector UnwrapTaskTypes() { } } public class TypeSelectorAssertions { @@ -2123,6 +2141,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -2131,6 +2150,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) { } } } namespace FluentAssertions.Xml diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.approved.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.approved.txt index 78e62ced44..d0ec54f309 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.approved.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.approved.txt @@ -229,18 +229,25 @@ namespace FluentAssertions } public static class TypeEnumerableExtensions { + public static System.Collections.Generic.IEnumerable ThatAreClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreInNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } + public static System.Collections.Generic.IEnumerable ThatAreNotClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } + public static System.Collections.Generic.IEnumerable ThatAreNotStatic(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatAreStatic(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreUnderNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } public static System.Collections.Generic.IEnumerable ThatDeriveFrom(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatImplement(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatSatisfy(this System.Collections.Generic.IEnumerable types, System.Func predicate) { } + public static System.Collections.Generic.IEnumerable UnwrapEnumerableTypes(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable UnwrapTaskTypes(this System.Collections.Generic.IEnumerable types) { } } public static class TypeExtensions { @@ -1931,6 +1938,7 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturnVoid { get; } public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() @@ -1948,11 +1956,13 @@ namespace FluentAssertions.Types public MethodInfoSelectorAssertions(params System.Reflection.MethodInfo[] methods) { } protected string Context { get; } public System.Collections.Generic.IEnumerable SubjectMethods { get; } + public FluentAssertions.AndConstraint Be(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -1984,6 +1994,7 @@ namespace FluentAssertions.Types public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.PropertyInfoSelector NotOfType() { } public FluentAssertions.Types.PropertyInfoSelector OfType() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWithOrInherit() @@ -2093,23 +2104,30 @@ namespace FluentAssertions.Types public TypeSelector(System.Collections.Generic.IEnumerable types) { } public TypeSelector(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ThatAreClasses() { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotClasses() { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotStatic() { } public FluentAssertions.Types.TypeSelector ThatAreNotUnderNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreStatic() { } public FluentAssertions.Types.TypeSelector ThatAreUnderNamespace(string @namespace) { } public FluentAssertions.Types.TypeSelector ThatDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotImplement() { } public FluentAssertions.Types.TypeSelector ThatImplement() { } + public FluentAssertions.Types.TypeSelector ThatSatisfy(System.Func predicate) { } public System.Type[] ToArray() { } + public FluentAssertions.Types.TypeSelector UnwrapEnumerableTypes() { } + public FluentAssertions.Types.TypeSelector UnwrapTaskTypes() { } } public class TypeSelectorAssertions { @@ -2123,6 +2141,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -2131,6 +2150,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) { } } } namespace FluentAssertions.Xml diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.approved.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.approved.txt index 1b6df278aa..98dc19f1b7 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.approved.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.approved.txt @@ -229,18 +229,25 @@ namespace FluentAssertions } public static class TypeEnumerableExtensions { + public static System.Collections.Generic.IEnumerable ThatAreClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreInNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } + public static System.Collections.Generic.IEnumerable ThatAreNotClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } + public static System.Collections.Generic.IEnumerable ThatAreNotStatic(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatAreStatic(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreUnderNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } public static System.Collections.Generic.IEnumerable ThatDeriveFrom(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatImplement(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatSatisfy(this System.Collections.Generic.IEnumerable types, System.Func predicate) { } + public static System.Collections.Generic.IEnumerable UnwrapEnumerableTypes(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable UnwrapTaskTypes(this System.Collections.Generic.IEnumerable types) { } } public static class TypeExtensions { @@ -1931,6 +1938,7 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturnVoid { get; } public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() @@ -1948,11 +1956,13 @@ namespace FluentAssertions.Types public MethodInfoSelectorAssertions(params System.Reflection.MethodInfo[] methods) { } protected string Context { get; } public System.Collections.Generic.IEnumerable SubjectMethods { get; } + public FluentAssertions.AndConstraint Be(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -1984,6 +1994,7 @@ namespace FluentAssertions.Types public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.PropertyInfoSelector NotOfType() { } public FluentAssertions.Types.PropertyInfoSelector OfType() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWithOrInherit() @@ -2093,23 +2104,30 @@ namespace FluentAssertions.Types public TypeSelector(System.Collections.Generic.IEnumerable types) { } public TypeSelector(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ThatAreClasses() { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotClasses() { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotStatic() { } public FluentAssertions.Types.TypeSelector ThatAreNotUnderNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreStatic() { } public FluentAssertions.Types.TypeSelector ThatAreUnderNamespace(string @namespace) { } public FluentAssertions.Types.TypeSelector ThatDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotImplement() { } public FluentAssertions.Types.TypeSelector ThatImplement() { } + public FluentAssertions.Types.TypeSelector ThatSatisfy(System.Func predicate) { } public System.Type[] ToArray() { } + public FluentAssertions.Types.TypeSelector UnwrapEnumerableTypes() { } + public FluentAssertions.Types.TypeSelector UnwrapTaskTypes() { } } public class TypeSelectorAssertions { @@ -2123,6 +2141,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -2131,6 +2150,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) { } } } namespace FluentAssertions.Xml diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.approved.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.approved.txt index 0333b07efe..b7d3433640 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.approved.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.approved.txt @@ -228,18 +228,25 @@ namespace FluentAssertions } public static class TypeEnumerableExtensions { + public static System.Collections.Generic.IEnumerable ThatAreClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreInNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } + public static System.Collections.Generic.IEnumerable ThatAreNotClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } + public static System.Collections.Generic.IEnumerable ThatAreNotStatic(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatAreStatic(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreUnderNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } public static System.Collections.Generic.IEnumerable ThatDeriveFrom(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatImplement(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatSatisfy(this System.Collections.Generic.IEnumerable types, System.Func predicate) { } + public static System.Collections.Generic.IEnumerable UnwrapEnumerableTypes(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable UnwrapTaskTypes(this System.Collections.Generic.IEnumerable types) { } } public static class TypeExtensions { @@ -1887,6 +1894,7 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturnVoid { get; } public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() @@ -1904,11 +1912,13 @@ namespace FluentAssertions.Types public MethodInfoSelectorAssertions(params System.Reflection.MethodInfo[] methods) { } protected string Context { get; } public System.Collections.Generic.IEnumerable SubjectMethods { get; } + public FluentAssertions.AndConstraint Be(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -1940,6 +1950,7 @@ namespace FluentAssertions.Types public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.PropertyInfoSelector NotOfType() { } public FluentAssertions.Types.PropertyInfoSelector OfType() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWithOrInherit() @@ -2049,23 +2060,30 @@ namespace FluentAssertions.Types public TypeSelector(System.Collections.Generic.IEnumerable types) { } public TypeSelector(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ThatAreClasses() { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotClasses() { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotStatic() { } public FluentAssertions.Types.TypeSelector ThatAreNotUnderNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreStatic() { } public FluentAssertions.Types.TypeSelector ThatAreUnderNamespace(string @namespace) { } public FluentAssertions.Types.TypeSelector ThatDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotImplement() { } public FluentAssertions.Types.TypeSelector ThatImplement() { } + public FluentAssertions.Types.TypeSelector ThatSatisfy(System.Func predicate) { } public System.Type[] ToArray() { } + public FluentAssertions.Types.TypeSelector UnwrapEnumerableTypes() { } + public FluentAssertions.Types.TypeSelector UnwrapTaskTypes() { } } public class TypeSelectorAssertions { @@ -2079,6 +2097,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -2087,6 +2106,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) { } } } namespace FluentAssertions.Xml diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.approved.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.approved.txt index 9ef5d7e864..668325ea1d 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.approved.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.approved.txt @@ -229,18 +229,25 @@ namespace FluentAssertions } public static class TypeEnumerableExtensions { + public static System.Collections.Generic.IEnumerable ThatAreClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreInNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } + public static System.Collections.Generic.IEnumerable ThatAreNotClasses(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWith(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } public static System.Collections.Generic.IEnumerable ThatAreNotDecoratedWithOrInherit(this System.Collections.Generic.IEnumerable types) where TAttribute : System.Attribute { } + public static System.Collections.Generic.IEnumerable ThatAreNotStatic(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatAreStatic(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatAreUnderNamespace(this System.Collections.Generic.IEnumerable types, string @namespace) { } public static System.Collections.Generic.IEnumerable ThatDeriveFrom(this System.Collections.Generic.IEnumerable types) { } public static System.Collections.Generic.IEnumerable ThatImplement(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable ThatSatisfy(this System.Collections.Generic.IEnumerable types, System.Func predicate) { } + public static System.Collections.Generic.IEnumerable UnwrapEnumerableTypes(this System.Collections.Generic.IEnumerable types) { } + public static System.Collections.Generic.IEnumerable UnwrapTaskTypes(this System.Collections.Generic.IEnumerable types) { } } public static class TypeExtensions { @@ -1931,6 +1938,7 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturnVoid { get; } public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() @@ -1948,11 +1956,13 @@ namespace FluentAssertions.Types public MethodInfoSelectorAssertions(params System.Reflection.MethodInfo[] methods) { } protected string Context { get; } public System.Collections.Generic.IEnumerable SubjectMethods { get; } + public FluentAssertions.AndConstraint Be(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -1984,6 +1994,7 @@ namespace FluentAssertions.Types public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.PropertyInfoSelector NotOfType() { } public FluentAssertions.Types.PropertyInfoSelector OfType() { } + public FluentAssertions.Types.TypeSelector ReturnTypes() { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.PropertyInfoSelector ThatAreDecoratedWithOrInherit() @@ -2093,23 +2104,30 @@ namespace FluentAssertions.Types public TypeSelector(System.Collections.Generic.IEnumerable types) { } public TypeSelector(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public FluentAssertions.Types.TypeSelector ThatAreClasses() { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotClasses() { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } public FluentAssertions.Types.TypeSelector ThatAreNotInNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreNotStatic() { } public FluentAssertions.Types.TypeSelector ThatAreNotUnderNamespace(string @namespace) { } + public FluentAssertions.Types.TypeSelector ThatAreStatic() { } public FluentAssertions.Types.TypeSelector ThatAreUnderNamespace(string @namespace) { } public FluentAssertions.Types.TypeSelector ThatDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotDeriveFrom() { } public FluentAssertions.Types.TypeSelector ThatDoNotImplement() { } public FluentAssertions.Types.TypeSelector ThatImplement() { } + public FluentAssertions.Types.TypeSelector ThatSatisfy(System.Func predicate) { } public System.Type[] ToArray() { } + public FluentAssertions.Types.TypeSelector UnwrapEnumerableTypes() { } + public FluentAssertions.Types.TypeSelector UnwrapTaskTypes() { } } public class TypeSelectorAssertions { @@ -2123,6 +2141,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) @@ -2131,6 +2150,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWithOrInherit(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } + public FluentAssertions.AndConstraint NotBeSealed(string because = "", params object[] becauseArgs) { } } } namespace FluentAssertions.Xml diff --git a/Tests/FluentAssertions.Specs/TypeEnumerableExtensionsSpecs.cs b/Tests/FluentAssertions.Specs/TypeEnumerableExtensionsSpecs.cs new file mode 100644 index 0000000000..0751a81e95 --- /dev/null +++ b/Tests/FluentAssertions.Specs/TypeEnumerableExtensionsSpecs.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FluentAssertions.Common; +using TypeEnumerableExtensionsSpecs.BaseNamespace; +using TypeEnumerableExtensionsSpecs.BaseNamespace.Nested; +using TypeEnumerableExtensionsSpecs.Internal; +using Xunit; + +namespace FluentAssertions.Specs +{ + public class TypeEnumerableExtensionsSpecs + { + [Fact] + public void When_selecting_types_that_decorated_with_attribute_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(ClassWithSomeAttribute), typeof(ClassDerivedFromClassWithSomeAttribute) }; + + types.ThatAreDecoratedWith() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(ClassWithSomeAttribute)); + } + + [Fact] + public void When_selecting_types_that_decorated_with_attribute_or_inherit_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(ClassWithSomeAttribute), typeof(ClassDerivedFromClassWithSomeAttribute) }; + + types.ThatAreDecoratedWithOrInherit() + .Should() + .HaveCount(2) + .And.Contain(typeof(ClassWithSomeAttribute)) + .And.Contain(typeof(ClassDerivedFromClassWithSomeAttribute)); + } + + [Fact] + public void When_selecting_types_that_not_decorated_with_attribute_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(ClassWithSomeAttribute), typeof(ClassDerivedFromClassWithSomeAttribute) }; + + types.ThatAreNotDecoratedWith() + .Should() + .HaveCount(2) + .And.Contain(typeof(JustAClass)) + .And.Contain(typeof(ClassDerivedFromClassWithSomeAttribute)); + } + + [Fact] + public void When_selecting_types_that_not_decorated_with_attribute_or_inherit_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(ClassWithSomeAttribute), typeof(ClassDerivedFromClassWithSomeAttribute) }; + + types.ThatAreNotDecoratedWithOrInherit() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(JustAClass)); + } + + [Fact] + public void When_selecting_types_in_namespace_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(BaseNamespaceClass), typeof(NestedNamespaceClass) }; + + types.ThatAreInNamespace(typeof(BaseNamespaceClass).Namespace) + .Should() + .ContainSingle() + .Which.Should().Be(typeof(BaseNamespaceClass)); + } + + [Fact] + public void When_selecting_types_under_namespace_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(BaseNamespaceClass), typeof(NestedNamespaceClass) }; + + types.ThatAreUnderNamespace(typeof(BaseNamespaceClass).Namespace) + .Should() + .HaveCount(2) + .And.Contain(typeof(BaseNamespaceClass)) + .And.Contain(typeof(NestedNamespaceClass)); + } + + [Fact] + public void When_selecting_derived_classes_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(SomeBaseClass), typeof(SomeClassDerivedFromSomeBaseClass) }; + + types.ThatDeriveFrom() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(SomeClassDerivedFromSomeBaseClass)); + } + + [Fact] + public void When_selecting_types_that_implement_interface_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(ClassImplementingJustAnInterface), typeof(IJustAnInterface) }; + + types.ThatImplement() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(ClassImplementingJustAnInterface)); + } + + [Fact] + public void When_selecting_only_the_classes_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(IJustAnInterface) }; + + types.ThatAreClasses() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(JustAClass)); + } + + [Fact] + public void When_selecting_not_a_classes_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(IJustAnInterface) }; + + types.ThatAreNotClasses() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(IJustAnInterface)); + } + + [Fact] + public void When_selecting_static_classes_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(AStaticClass) }; + + types.ThatAreStatic() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(AStaticClass)); + } + + [Fact] + public void When_selecting_not_a_static_classes_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(AStaticClass) }; + + types.ThatAreNotStatic() + .Should() + .ContainSingle() + .Which.Should().Be(typeof(JustAClass)); + } + + [Fact] + public void When_selecting_types_with_predicate_it_should_return_the_correct_type() + { + var types = new[] { typeof(JustAClass), typeof(AStaticClass) }; + + types.ThatSatisfy(t => t.IsCSharpStatic()) + .Should() + .ContainSingle() + .Which.Should().Be(typeof(AStaticClass)); + } + + [Fact] + public void When_unwrap_task_types_it_should_return_the_correct_type() + { + var types = new[] { typeof(Task), typeof(List) }; + + types.UnwrapTaskTypes() + .Should() + .HaveCount(2) + .And.Contain(typeof(JustAClass)) + .And.Contain(typeof(List)); + } + + [Fact] + public void When_unwrap_enumerable_types_it_should_return_the_correct_type() + { + var types = new[] { typeof(Task), typeof(List) }; + + types.UnwrapEnumerableTypes() + .Should() + .HaveCount(2) + .And.Contain(typeof(Task)) + .And.Contain(typeof(IJustAnInterface)); + } + } +} + +#region Internal classes used in unit tests + +namespace TypeEnumerableExtensionsSpecs.BaseNamespace +{ + internal class BaseNamespaceClass + { + + } +} + +namespace TypeEnumerableExtensionsSpecs.BaseNamespace.Nested +{ + internal class NestedNamespaceClass + { + + } +} + +namespace TypeEnumerableExtensionsSpecs.Internal +{ + internal interface IJustAnInterface + { + + } + internal class JustAClass + { + + } + internal static class AStaticClass + { + + } + + internal class SomeBaseClass + { + + } + internal class SomeClassDerivedFromSomeBaseClass : SomeBaseClass + { + + } + + internal class ClassImplementingJustAnInterface : IJustAnInterface + { + } + + [Some] + internal class ClassWithSomeAttribute + { + + } + internal class ClassDerivedFromClassWithSomeAttribute : ClassWithSomeAttribute + { + + } + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + internal class SomeAttribute : Attribute + { + } +} +#endregion diff --git a/Tests/FluentAssertions.Specs/Types/MethodInfoAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Types/MethodInfoAssertionSpecs.cs index 3e9d23960f..51668538dc 100644 --- a/Tests/FluentAssertions.Specs/Types/MethodInfoAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/MethodInfoAssertionSpecs.cs @@ -647,5 +647,31 @@ internal class ClassWithMethodWithImplementationAttribute public void ZeroOptions() { } } + internal class ClassWithPublicMethods + { + public void PublicDoNothing() + { + } + + public void DoNothingWithParameter(int i) + { + } + } + + internal class ClassWithNonPublicMethods + { + protected void PublicDoNothing() + { + } + + internal void DoNothingWithParameter(int i) + { + } + + private void DoNothingWithAnotherParameter(string i) + { + } + } + #endregion } diff --git a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorAssertionSpecs.cs index 6bb81120c3..1c877a9809 100644 --- a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorAssertionSpecs.cs @@ -1,4 +1,5 @@ using System; +using FluentAssertions.Common; using FluentAssertions.Types; using Xunit; using Xunit.Sdk; @@ -231,5 +232,107 @@ public void When_asserting_methods_are_not_decorated_with_attribute_but_they_are "*ClassWithAllMethodsDecoratedWithDummyAttribute.ProtectedDoNothing*" + "*ClassWithAllMethodsDecoratedWithDummyAttribute.PrivateDoNothing"); } + + [Fact] + public void When_all_methods_have_specified_accessor_it_should_succeed() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().Be(CSharpAccessModifier.Public); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_not_all_methods_have_specified_accessor_it_should_throw() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithNonPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().Be(CSharpAccessModifier.Public); + + // Assert + act.Should().Throw() + .WithMessage("Expected all selected methods to be Public" + + ", but the following methods are not:*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.PublicDoNothing*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.DoNothingWithParameter*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.DoNothingWithAnotherParameter"); + } + + [Fact] + public void When_not_all_methods_have_specified_accessor_it_should_throw_with_descriptive_message() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithNonPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().Be(CSharpAccessModifier.Public, "we want to test the error {0}", "message"); + + // Assert + act.Should().Throw() + .WithMessage("Expected all selected methods to be Public" + + " because we want to test the error message" + + ", but the following methods are not:*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.PublicDoNothing*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.DoNothingWithParameter*" + + "Void FluentAssertions.Specs.ClassWithNonPublicMethods.DoNothingWithAnotherParameter"); + } + + [Fact] + public void When_all_methods_does_not_have_specified_accessor_it_should_succeed() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithNonPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().NotBe(CSharpAccessModifier.Public); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_any_method_have_specified_accessor_it_should_throw() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().NotBe(CSharpAccessModifier.Public); + + // Assert + act.Should().Throw() + .WithMessage("Expected all selected methods to not be Public" + + ", but the following methods are:*" + + "Void FluentAssertions.Specs.ClassWithPublicMethods.PublicDoNothing*"); + } + + [Fact] + public void When_any_method_have_specified_accessor_it_should_throw_with_descriptive_message() + { + // Arrange + var methodSelector = new MethodInfoSelector(typeof(ClassWithPublicMethods)); + + // Act + Action act = () => + methodSelector.Should().NotBe(CSharpAccessModifier.Public, "we want to test the error {0}", "message"); + + // Assert + act.Should().Throw() + .WithMessage("Expected all selected methods to not be Public" + + " because we want to test the error message" + + ", but the following methods are:*" + + "Void FluentAssertions.Specs.ClassWithPublicMethods.PublicDoNothing*"); + } } } diff --git a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs index 57133ca29d..add9215066 100644 --- a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs @@ -242,6 +242,23 @@ public void When_selecting_methods_not_decorated_with_or_inheriting_a_noninherit // Assert methods.Should().ContainSingle(); } + + [Fact] + public void When_selecting_methods_return_types_it_should_return_the_correct_types() + { + // Arrange + Type type = typeof(TestClassForMethodReturnTypesSelector); + + // Act + IEnumerable returnTypes = type.Methods().ReturnTypes().ToArray(); + + // Assert + returnTypes.Should() + .HaveCount(3) + .And.Contain(typeof(void)) + .And.Contain(typeof(int)) + .And.Contain(typeof(string)); + } } #region Internal classes used in unit tests @@ -308,6 +325,13 @@ internal class TestClassForMethodSelectorWithNonInheritableAttributeDerived : Te public override void PublicVirtualVoidMethodWithAttribute() { } } + internal class TestClassForMethodReturnTypesSelector + { + public void SomeMethod() { } + public int AnotherMethod() { return default; } + public string OneMoreMethod() { return default; } + } + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public class DummyMethodNonInheritableAttributeAttribute : Attribute { diff --git a/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs b/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs index cdf62e7d55..8d5b290460 100644 --- a/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorSpecs.cs @@ -217,6 +217,20 @@ public void When_selecting_properties_not_decorated_with_or_inheriting_a_noninhe // Assert properties.Should().ContainSingle(); } + + [Fact] + public void When_selecting_properties_return_types_it_should_return_the_correct_types() + { + // Arrange + Type type = typeof(TestClassForPropertySelector); + + // Act + IEnumerable returnTypes = type.Properties().ReturnTypes().ToArray(); + + // Assert + returnTypes.Should() + .BeEquivalentTo(typeof(string), typeof(string), typeof(int), typeof(int), typeof(int), typeof(int)); + } } #region Internal classes used in unit tests diff --git a/Tests/FluentAssertions.Specs/Types/TypeAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Types/TypeAssertionSpecs.cs index 0a1254e7cc..91dee598e0 100644 --- a/Tests/FluentAssertions.Specs/Types/TypeAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/TypeAssertionSpecs.cs @@ -1592,6 +1592,39 @@ public void When_type_is_not_valid_for_BeSealed_it_throws_exception(Type type, s .WithMessage(exceptionMessage); } + [Fact] + public void When_all_types_are_sealed_it_succeeds() + { + // Arrange + var types = new TypeSelector(new[] + { + typeof(Sealed) + }); + + // Act / Assert + types.Should().BeSealed(); + } + + [Fact] + public void When_any_type_is_not_sealed_it_fails_with_a_meaningful_message() + { + // Arrange + var types = new TypeSelector(new[] + { + typeof(Sealed), + typeof(Abstract) + }); + + // Act + Action act = () => types.Should().BeSealed("it's {0} important", "very"); + + // Assert + act.Should().Throw() + .WithMessage("Expected all types to be sealed because it's very important, but the following types are not:" + + "*Abstract*" + + "."); + } + #endregion #region NotBeSealed @@ -1648,6 +1681,39 @@ public void When_type_is_not_valid_for_NotBeSealed_it_throws_exception(Type type .WithMessage(exceptionMessage); } + [Fact] + public void When_all_types_are_not_sealed_it_succeeds() + { + // Arrange + var types = new TypeSelector(new[] + { + typeof(Abstract) + }); + + // Act / Assert + types.Should().NotBeSealed(); + } + + [Fact] + public void When_any_type_is_sealed_it_fails_with_a_meaningful_message() + { + // Arrange + var types = new TypeSelector(new[] + { + typeof(Abstract), + typeof(Sealed) + }); + + // Act + Action act = () => types.Should().NotBeSealed("it's {0} important", "very"); + + // Assert + act.Should().Throw() + .WithMessage("Expected all types not to be sealed because it's very important, but the following types are:" + + "*Sealed*" + + "."); + } + #endregion #region BeAbstract diff --git a/Tests/FluentAssertions.Specs/Types/TypeSelectorSpecs.cs b/Tests/FluentAssertions.Specs/Types/TypeSelectorSpecs.cs index 5a08853c77..a25ffc2bbc 100644 --- a/Tests/FluentAssertions.Specs/Types/TypeSelectorSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/TypeSelectorSpecs.cs @@ -1,13 +1,18 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; - +using System.Threading.Tasks; using FluentAssertions.Types; using Internal.Main.Test; +using Internal.NotOnlyClasses.Test; using Internal.Other.Test; using Internal.Other.Test.Common; +using Internal.StaticAndNonStaticClasses.Test; +using Internal.UnwrapSelectorTestTypes.Test; using Xunit; +using ISomeInterface = Internal.Main.Test.ISomeInterface; namespace FluentAssertions.Specs { @@ -415,6 +420,119 @@ public void When_deselecting_a_prefix_of_a_namespace_it_should_not_match() // Assert filteredTypes.As>().Should().ContainSingle(); } + + [Fact] + public void When_selecting_types_that_are_classes_it_should_return_the_correct_types() + { + // Arrange + TypeSelector types = new[] { typeof(NotOnlyClassesClass), typeof(NotOnlyClassesEnumeration), typeof(INotOnlyClassesInterface) }.Types(); + + // Act + IEnumerable filteredTypes = types.ThatAreClasses(); + + // Assert + filteredTypes.Should() + .ContainSingle() + .Which.Should().Be(typeof(NotOnlyClassesClass)); + } + + [Fact] + public void When_selecting_types_that_are_not_classes_it_should_return_the_correct_types() + { + // Arrange + Assembly assembly = typeof(NotOnlyClassesClass).GetTypeInfo().Assembly; + + // Act + IEnumerable types = AllTypes.From(assembly) + .ThatAreInNamespace("Internal.NotOnlyClasses.Test") + .ThatAreNotClasses(); + + // Assert + types.Should() + .HaveCount(2) + .And.Contain(typeof(INotOnlyClassesInterface)) + .And.Contain(typeof(NotOnlyClassesEnumeration)); + } + + [Fact] + public void When_selecting_types_that_are_static_classes_it_should_return_the_correct_types() + { + // Arrange + Assembly assembly = typeof(StaticClass).GetTypeInfo().Assembly; + + // Act + IEnumerable types = AllTypes.From(assembly) + .ThatAreInNamespace("Internal.StaticAndNonStaticClasses.Test") + .ThatAreStatic(); + + // Assert + types.Should() + .ContainSingle() + .Which.Should().Be(typeof(StaticClass)); + } + + [Fact] + public void When_selecting_types_that_are_not_static_classes_it_should_return_the_correct_types() + { + // Arrange + Assembly assembly = typeof(StaticClass).GetTypeInfo().Assembly; + + // Act + IEnumerable types = AllTypes.From(assembly) + .ThatAreInNamespace("Internal.StaticAndNonStaticClasses.Test") + .ThatAreNotStatic(); + + // Assert + types.Should() + .ContainSingle() + .Which.Should().Be(typeof(NotAStaticClass)); + } + + [Fact] + public void When_selecting_types_with_predicate_it_should_return_the_correct_types() + { + // Arrange + Assembly assembly = typeof(SomeBaseClass).GetTypeInfo().Assembly; + + // Act + IEnumerable types = AllTypes.From(assembly) + .ThatSatisfy(t => t.GetCustomAttribute() != null); + + // Assert + types.Should() + .HaveCount(3) + .And.Contain(typeof(ClassWithSomeAttribute)) + .And.Contain(typeof(ClassWithSomeAttributeDerived)) + .And.Contain(typeof(ClassWithSomeAttributeThatImplementsSomeInterface)); + } + + [Fact] + public void When_unwrap_task_types_it_should_return_the_correct_types() + { + IEnumerable types = typeof(ClassToExploreUnwrappedTaskTypes) + .Methods() + .ReturnTypes() + .UnwrapTaskTypes(); + + types.Should() + .BeEquivalentTo(typeof(int), typeof(void), typeof(void), typeof(string), typeof(bool)); + } + + [Fact] + public void When_unwrap_enumerable_types_it_should_return_the_correct_types() + { + IEnumerable types = typeof(ClassToExploreUnwrappedEnumerableTypes) + .Methods() + .ReturnTypes() + .UnwrapEnumerableTypes(); + + types.Should() + .HaveCount(4) + .And.Contain(typeof(IEnumerable)) + .And.Contain(typeof(bool)) + .And.Contain(typeof(int)) + .And.Contain(typeof(string)); + } } } @@ -510,6 +628,63 @@ internal class SomeCommonClass } } +namespace Internal.NotOnlyClasses.Test +{ + internal class NotOnlyClassesClass + { + } + + internal enum NotOnlyClassesEnumeration + { + } + + internal interface INotOnlyClassesInterface + { + } +} + +namespace Internal.StaticAndNonStaticClasses.Test +{ + internal static class StaticClass + { + } + + internal class NotAStaticClass + { + } +} + +namespace Internal.UnwrapSelectorTestTypes.Test +{ + internal class ClassToExploreUnwrappedTaskTypes + { + internal int DoWithInt() { return default; } + internal Task DoWithTask() { return Task.CompletedTask; } + internal ValueTask DoWithValueTask() { return new ValueTask(); } + internal Task DoWithIntTask() { return Task.FromResult(string.Empty); } + internal ValueTask DoWithBoolValueTask() { return new ValueTask(false); } + } + + internal class ClassToExploreUnwrappedEnumerableTypes + { + internal IEnumerable DoWithTask() { return default; } + internal List DoWithIntTask() { return default; } + internal ClassImplementingMultipleEnumerable DoWithBoolValueTask() { return default; } + } + + internal class ClassImplementingMultipleEnumerable : IEnumerable, IEnumerable + { + private readonly IEnumerable integers = new int[0]; + private readonly IEnumerable strings = new string[0]; + + public IEnumerator GetEnumerator() => integers.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)integers).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => strings.GetEnumerator(); + } +} + #pragma warning disable RCS1110 // Declare type inside namespace. internal class ClassInGlobalNamespace { } #pragma warning restore RCS1110 diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index 119e1b3138..bcbe4fc478 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -21,6 +21,13 @@ sidebar: * Make `DefaultValueFormatter` and `EnumerableValueFormatter` suitable for inheritance - [#1295](https://github.com/fluentassertions/fluentassertions/pull/1295). * Added support for dictionary assertions on `IReadOnlyDictionary` - [#1298](https://github.com/fluentassertions/fluentassertions/pull/1298). * `GenericAsyncFunctionAssertions` now has `AndWhichConstraint` overloads for `NotThrow[Async]` and `NotThrowAfter[Async]` - [#1289](https://github.com/fluentassertions/fluentassertions/pull/1289). +* Added `ReturnTypes` to `MethodInfoSelector` to get all return types from all the methods selected +* Added `[Not]Be` to `MethodInfoSelector` to check that methods [don't] have specified access modifier +* Added `ThatAre[Not]Classes`, `ThatAre[Not]Static` selectors to `TypeSelector` +* Added `ThatSatisfy` to `TypeSelector` to filter types with specified predicate +* Added `UnwrapEnumerableTypes` to `TypeSelector` to get the `T` type from types implementing `IEnumerable` +* Added `UnwrapTaskTypes` to `TypeSelector` to get the `T` type for any type that are `Task` or `ValueTask` +* Added `[Not]BeSealed` to `TypeSelectorAssertions` * Added `collection.Should().NotContainEquivalentTo` to use object graph comparison rules to assert absence of an element in the collection - [#1318](https://github.com/fluentassertions/fluentassertions/pull/1318). **Fixes** diff --git a/docs/_pages/typesandmethods.md b/docs/_pages/typesandmethods.md index 79dd2a469b..b6651baa38 100644 --- a/docs/_pages/typesandmethods.md +++ b/docs/_pages/typesandmethods.md @@ -63,6 +63,30 @@ typeof(MyController).Methods() "because all Actions with HttpPost require ValidateAntiForgeryToken"); ``` +You can also perform assertions on all of methods return types to check class contract. +Like this: + +```csharp +typeof(MyDataReader).Methods() + .ReturnTypes() + .Properties() + .Should() + .NotBeWritable("all the return types should be immutable"); +``` + +If the methods return types are `IEnumerable` or `Task` you can unwrap underlying types to with `UnwrapTaskTypes` and `UnwrapEnumerableTypes` methods. +Like this: + +```csharp +typeof(MyDataReader).Methods() + .ReturnTypes() + .UnwrapTaskTypes() + .UnwrapEnumerableTypes() + .Properties() + .Should() + .NotBeWritable("all the return types should be immutable"); +``` + If you also want to assert that an attribute has a specific property value, use this syntax. ```csharp