public void TrueWhenTypesAreSame(Type type)
        {
            var compilation = TestHelpers.CreateCompilation();
            var typeSymbol  = GetTypeSymbol(compilation, type);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(typeSymbol, typeSymbol, compilation), Is.True);
        }
 private static void AssertThatCommutativeEqual(ITypeSymbol?leftTypeSymbol, ITypeSymbol?rightTypeSymbol, Compilation compilation, Constraint constraint)
 {
     Assert.Multiple(() =>
     {
         Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), constraint);
         Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), constraint);
     });
 }
        public void FalseWhenIncompatibleTypesProvided(Type leftType, Type rightType)
        {
            var compilation     = TestHelpers.CreateCompilation();
            var leftTypeSymbol  = GetTypeSymbol(compilation, leftType);
            var rightTypeSymbol = GetTypeSymbol(compilation, rightType);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.False);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.False);
        }
        protected override void AnalyzeAssertInvocation(SyntaxNodeAnalysisContext context,
                                                        InvocationExpressionSyntax assertExpression, IMethodSymbol methodSymbol)
        {
            var cancellationToken = context.CancellationToken;
            var semanticModel     = context.SemanticModel;

            if (!AssertHelper.TryGetActualAndConstraintExpressions(assertExpression, semanticModel,
                                                                   out var actualExpression, out var constraintExpression))
            {
                return;
            }

            foreach (var constraintPartExpression in constraintExpression.ConstraintParts)
            {
                if (HasIncompatiblePrefixes(constraintPartExpression) ||
                    HasCustomEqualityComparer(constraintPartExpression) ||
                    constraintPartExpression.HasUnknownExpressions())
                {
                    return;
                }

                var constraintMethod = constraintPartExpression.GetConstraintMethod();

                if (constraintMethod?.Name != NunitFrameworkConstants.NameOfIsEqualTo ||
                    constraintMethod.ReturnType?.GetFullMetadataName() != NunitFrameworkConstants.FullNameOfEqualToConstraint)
                {
                    continue;
                }

                var expectedArgumentExpression = constraintPartExpression.GetExpectedArgumentExpression();

                if (expectedArgumentExpression == null)
                {
                    continue;
                }

                var actualTypeInfo = semanticModel.GetTypeInfo(actualExpression, cancellationToken);
                var actualType     = actualTypeInfo.Type ?? actualTypeInfo.ConvertedType;

                if (actualType == null)
                {
                    continue;
                }

                actualType = AssertHelper.UnwrapActualType(actualType);

                var expectedType = semanticModel.GetTypeInfo(expectedArgumentExpression, cancellationToken).Type;

                if (!NUnitEqualityComparerHelper.CanBeEqual(actualType, expectedType, semanticModel.Compilation))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 descriptor,
                                                 expectedArgumentExpression.GetLocation()));
                }
            }
        }
        public void TrueForErrorType()
        {
            var compilation = TestHelpers.CreateCompilation();

            var leftTypeSymbol  = compilation.GetSpecialType(SpecialType.System_Int32);
            var rightTypeSymbol = compilation.CreateErrorTypeSymbol(null, "ErrorType", 0);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void FalseWhenDifferentEnumsProvided()
        {
            var compilation     = TestHelpers.CreateCompilation(@"
                enum EnumOne { A, B, C }
                enum EnumTwo { A, B, C }");
            var leftTypeSymbol  = compilation.GetTypeByMetadataName("EnumOne");
            var rightTypeSymbol = compilation.GetTypeByMetadataName("EnumTwo");

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.False);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.False);
        }
        public void TrueForArrayWithElementErrorType()
        {
            var compilation = TestHelpers.CreateCompilation();

            var errorType       = compilation.CreateErrorTypeSymbol(null, "ErrorType", 0);
            var leftTypeSymbol  = GetTypeSymbol(compilation, typeof(IEnumerable <int>));
            var rightTypeSymbol = compilation.CreateArrayTypeSymbol(errorType);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void TrueWhenSameNullableEnumsProvided()
        {
            var compilation        = TestHelpers.CreateCompilation(@"
                enum EnumOne { A, B, C }");
            var nullableTypeSymbol = compilation.GetSpecialType(SpecialType.System_Nullable_T);
            var leftTypeSymbol     = compilation.GetTypeByMetadataName("EnumOne");
            var rightTypeSymbol    = nullableTypeSymbol.Construct(leftTypeSymbol);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void TrueForNumericTypes(
            [ValueSource(nameof(NumericTypes))] Type leftType,
            [ValueSource(nameof(NumericTypes))] Type rightType)
        {
            var compilation     = TestHelpers.CreateCompilation();
            var leftTypeSymbol  = GetTypeSymbol(compilation, leftType);
            var rightTypeSymbol = GetTypeSymbol(compilation, rightType);

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void TrueWhenOneTypeInheritsAnother()
        {
            var compilation     = TestHelpers.CreateCompilation(@"
                class A { }
                class B : A { }");
            var leftTypeSymbol  = compilation.GetTypeByMetadataName("A");
            var rightTypeSymbol = compilation.GetTypeByMetadataName("B");

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void FalseWhenValueTuplesWithIncompatibleElementTypesProvided()
        {
            var compilation = TestHelpers.CreateCompilation();

            var intTypeSymbol    = compilation.GetSpecialType(SpecialType.System_Int32);
            var stringTypeSymbol = compilation.GetSpecialType(SpecialType.System_String);
            var leftTypeSymbol   = compilation.CreateTupleTypeSymbol(ImmutableArray.Create <ITypeSymbol>(intTypeSymbol, intTypeSymbol));
            var rightTypeSymbol  = compilation.CreateTupleTypeSymbol(ImmutableArray.Create <ITypeSymbol>(intTypeSymbol, stringTypeSymbol));

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.False);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.False);
        }
        public void TrueWhenActualHasIEquatableOfExpected()
        {
            var compilation     = TestHelpers.CreateCompilation(@"
                class A : System.IEquatable<B>
                {
                    public bool Equals(B other) => true;
                }

                class B { }");
            var leftTypeSymbol  = compilation.GetTypeByMetadataName("A");
            var rightTypeSymbol = compilation.GetTypeByMetadataName("B");

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.True);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.True);
        }
        public void FalseWhenIncompatibleTypesWithCyclicTypesProvided()
        {
            var compilation     = TestHelpers.CreateCompilation(@"
                class A : IEnumerable<A>
                {
                    public IEnumerator<A> GetEnumerator() => null;
                    IEnumerator IEnumerable.GetEnumerator() => null;
                }

                class B : IEnumerable<B>
                {
                    public IEnumerator<B> GetEnumerator() => null;
                    IEnumerator IEnumerable.GetEnumerator() => null;
                }");
            var leftTypeSymbol  = compilation.GetTypeByMetadataName("A");
            var rightTypeSymbol = compilation.GetTypeByMetadataName("B");

            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(leftTypeSymbol, rightTypeSymbol, compilation), Is.False);
            Assert.That(NUnitEqualityComparerHelper.CanBeEqual(rightTypeSymbol, leftTypeSymbol, compilation), Is.False);
        }
Beispiel #14
0
        private static void CheckActualVsExpectedOperation(OperationAnalysisContext context, IOperation?actualOperation, IOperation?expectedOperation)
        {
            if (actualOperation == null || expectedOperation == null)
            {
                return;
            }

            var actualType   = AssertHelper.GetUnwrappedActualType(actualOperation);
            var expectedType = expectedOperation.Type;

            if (actualType == null || expectedType == null)
            {
                return;
            }

            if (!NUnitEqualityComparerHelper.CanBeEqual(actualType, expectedType, context.Compilation))
            {
                context.ReportDiagnostic(Diagnostic.Create(
                                             descriptor,
                                             expectedOperation.Syntax.GetLocation()));
            }
        }
        protected override void AnalyzeAssertInvocation(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax assertExpression, IMethodSymbol methodSymbol)
        {
            var cancellationToken = context.CancellationToken;
            var semanticModel     = context.SemanticModel;

            if (!AssertHelper.TryGetActualAndConstraintExpressions(assertExpression, semanticModel,
                                                                   out var actualExpression, out var constraintExpression))
            {
                return;
            }

            foreach (var constraintPart in constraintExpression.ConstraintParts)
            {
                if ((!IsDoesContain(constraintPart) && !IsContainsItem(constraintPart)) ||
                    constraintPart.GetConstraintTypeSymbol()?.GetFullMetadataName() != NunitFrameworkConstants.FullNameOfSomeItemsConstraint)
                {
                    continue;
                }

                if (HasIncompatibleOperators(constraintPart))
                {
                    return;
                }

                var expectedExpression = constraintPart.GetExpectedArgumentExpression();

                if (expectedExpression == null)
                {
                    continue;
                }

                var expectedType = semanticModel.GetTypeInfo(expectedExpression, cancellationToken).Type;
                var actualType   = AssertHelper.GetUnwrappedActualType(actualExpression, semanticModel, cancellationToken);

                if (actualType == null || expectedType == null)
                {
                    continue;
                }

                if (actualType.IsIEnumerable(out var elementType))
                {
                    // Cannot determine element type for non-generic IEnumerable, therefore consider valid.
                    if (elementType == null)
                    {
                        continue;
                    }

                    // Valid, if collection element type matches expected type.
                    if (NUnitEqualityComparerHelper.CanBeEqual(elementType, expectedType, semanticModel.Compilation))
                    {
                        continue;
                    }
                }

                var actualTypeDisplay   = actualType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                var expectedTypeDisplay = expectedType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);

                context.ReportDiagnostic(Diagnostic.Create(
                                             descriptor,
                                             constraintPart.GetLocation(),
                                             ConstraintDiagnosticDescription(constraintPart),
                                             actualTypeDisplay,
                                             expectedTypeDisplay));
            }
        }
Beispiel #16
0
        protected override void AnalyzeAssertInvocation(OperationAnalysisContext context, IInvocationOperation assertOperation)
        {
            if (!AssertHelper.TryGetActualAndConstraintOperations(assertOperation,
                                                                  out var actualOperation, out var constraintExpression))
            {
                return;
            }

            foreach (var constraintPart in constraintExpression.ConstraintParts)
            {
                if ((!IsDoesContain(constraintPart) && !IsContainsItem(constraintPart)) ||
                    constraintPart.Root?.Type.GetFullMetadataName() != NunitFrameworkConstants.FullNameOfSomeItemsConstraint)
                {
                    continue;
                }

                if (constraintPart.HasIncompatiblePrefixes())
                {
                    return;
                }

                var expectedType = constraintPart.GetExpectedArgument()?.Type;
                var actualType   = AssertHelper.GetUnwrappedActualType(actualOperation);

                if (actualType == null || expectedType == null)
                {
                    continue;
                }

                if (actualType.IsIEnumerable(out var elementType))
                {
                    // Cannot determine element type for non-generic IEnumerable, therefore consider valid.
                    if (elementType == null)
                    {
                        continue;
                    }

                    IInvocationOperation?usingInvocation = constraintPart.GetSuffix(NunitFrameworkConstants.NameOfUsing) as IInvocationOperation;
                    if (usingInvocation != null)
                    {
                        IMethodSymbol target = usingInvocation.TargetMethod;
                        ImmutableArray <ITypeSymbol> typeArguments = target.TypeArguments;
                        switch (typeArguments.Length)
                        {
                        case 1:
                            // IEqualityComparer<T> or IComparer<T> or Comparison<T>
                            // Type must match.
                            break;

                        case 2:
                            // Func<TCollection, TMember, bool>
                            // Allows type translation to TMember.
                            if (NUnitEqualityComparerHelper.CanBeEqual(typeArguments[0], elementType, context.Compilation))
                            {
                                elementType = typeArguments[1];
                            }

                            break;

                        case 0:
                        // IEqualityComparer, IComparer
                        // Could potentially compare any type to any type
                        default:
                            // Unknown new method
                            continue;
                        }
                    }

                    // Valid, if collection element type matches expected type.
                    if (NUnitEqualityComparerHelper.CanBeEqual(elementType, expectedType, context.Compilation))
                    {
                        continue;
                    }
                }

                var actualTypeDisplay   = actualType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                var expectedTypeDisplay = expectedType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);

                context.ReportDiagnostic(Diagnostic.Create(
                                             descriptor,
                                             constraintPart.GetLocation(),
                                             ConstraintDiagnosticDescription(constraintPart),
                                             actualTypeDisplay,
                                             expectedTypeDisplay));
            }
        }