diff --git a/PowerAssert/Hints/TypeTestHint.cs b/PowerAssert/Hints/TypeTestHint.cs new file mode 100644 index 0000000..b7a5cfd --- /dev/null +++ b/PowerAssert/Hints/TypeTestHint.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using PowerAssert.Infrastructure; + +namespace PowerAssert.Hints +{ + class TypeTestHint : IHint + { + public bool TryGetHint(ExpressionParser parser, Expression expression, out string hint) + { + if (expression is TypeBinaryExpression typeBinaryExp && typeBinaryExp.NodeType == ExpressionType.TypeIs) + { + var expressionOperand = parser.DynamicInvoke(typeBinaryExp.Expression); + var typeOperand = typeBinaryExp.TypeOperand; + + if (!typeOperand.IsInstanceOfType(expressionOperand)) + { + hint = $", {expressionOperand} is not assignable to {typeOperand}"; + return true; + } + } + + hint = null; + return false; + } + } +} diff --git a/PowerAssert/Infrastructure/ExpressionParser.cs b/PowerAssert/Infrastructure/ExpressionParser.cs index fb5b065..79e6818 100644 --- a/PowerAssert/Infrastructure/ExpressionParser.cs +++ b/PowerAssert/Infrastructure/ExpressionParser.cs @@ -151,6 +151,14 @@ Node ParseExpression(UnaryExpression e) return new UnaryNode {Prefix = "-", Operand = Parse(e.Operand), PrefixValue = GetValue(e)}; case ExpressionType.ArrayLength: return new MemberAccessNode {Container = Parse(e.Operand), MemberName = "Length", MemberValue = GetValue(e)}; + case ExpressionType.TypeAs: + return new BinaryNode + { + Left = Parse(e.Operand), + Operator = "as", + Right = new ConstantNode() { Text = NameOfType(e.Type) }, + Value = GetValue(e) + }; } throw new ArgumentOutOfRangeException("e", string.Format("Can't handle UnaryExpression expression of class {0} and type {1}", e.GetType().Name, e.NodeType)); } @@ -410,7 +418,8 @@ string GetDisplayText(MemberInfo member) new FloatEqualityHint(), new BrokenEqualityHint(), new TimeSpanTotalMistakesHint(), - new EnumComparisonShowValuesHint() + new EnumComparisonShowValuesHint(), + new TypeTestHint() ); string GetHints(Expression e, object value) diff --git a/PowerAssertTests/Approvals/EndToEndTest.PrintingIsTest.approved.txt b/PowerAssertTests/Approvals/EndToEndTest.PrintingIsTest.approved.txt index d921aad..772f627 100644 --- a/PowerAssertTests/Approvals/EndToEndTest.PrintingIsTest.approved.txt +++ b/PowerAssertTests/Approvals/EndToEndTest.PrintingIsTest.approved.txt @@ -3,7 +3,7 @@ b is string . __ . | -| False +| False, System.Object is not assignable to System.String System.Object at PowerAssert.PAssert.IsTrue(Expression`1 expression) in ...\PAssert.cs diff --git a/PowerAssertTests/Approvals/EndToEndTest.SafeCasting.approved.txt b/PowerAssertTests/Approvals/EndToEndTest.SafeCasting.approved.txt new file mode 100644 index 0000000..d5ed0e8 --- /dev/null +++ b/PowerAssertTests/Approvals/EndToEndTest.SafeCasting.approved.txt @@ -0,0 +1,12 @@ +System.Exception: IsTrue failed, expression was: + +a as string != null +. .. __ +. __ | +. | | +| | False +| null +System.Object + + at PowerAssert.PAssert.IsTrue(Expression`1 expression) in ...\PAssert.cs + at PowerAssertTests.Approvals.EndToEndTest.ApproveException(Expression`1 func) in ...\EndToEndTest.cs \ No newline at end of file diff --git a/PowerAssertTests/Approvals/EndToEndTest.cs b/PowerAssertTests/Approvals/EndToEndTest.cs index b63ca26..60fa07b 100644 --- a/PowerAssertTests/Approvals/EndToEndTest.cs +++ b/PowerAssertTests/Approvals/EndToEndTest.cs @@ -328,6 +328,14 @@ public void Casting() ApproveException(() => (long) x == 10L); } + [Test] + public void SafeCasting() + { + object a = new object(); + + ApproveException(() => a as string != null); + } + [Test] public void ArrayLength() { diff --git a/PowerAssertTests/Hints/TypeTestHintTests.cs b/PowerAssertTests/Hints/TypeTestHintTests.cs new file mode 100644 index 0000000..837be20 --- /dev/null +++ b/PowerAssertTests/Hints/TypeTestHintTests.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using PowerAssert.Hints; +using PowerAssert.Infrastructure; + +namespace PowerAssertTests.Hints +{ + [TestFixture] + public class TypeTestHintTests + { + [Test] + public void ShouldPickUpTypeComparisonOperator() + { + var hint = new TypeTestHint(); + + var a = new TypeA(); + + Expression> x = () => a is TypeB; + var p = new ExpressionParser(x.Body); + + string description; + Assert.IsTrue(hint.TryGetHint(p, x.Body, out description)); + Assert.IsNotNull(description); + } + + class TypeA { } + class TypeB { } + } +} diff --git a/PowerAssertTests/PowerAssertTests.csproj b/PowerAssertTests/PowerAssertTests.csproj index 39f33a5..c5f04e3 100644 --- a/PowerAssertTests/PowerAssertTests.csproj +++ b/PowerAssertTests/PowerAssertTests.csproj @@ -86,6 +86,7 @@ +