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