1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using Xunit;
6 
7 namespace System.Linq.Expressions.Tests
8 {
9     public class TypeIs : TypeBinaryTests
10     {
11         [Fact]
NullExpression()12         public void NullExpression()
13         {
14             AssertExtensions.Throws<ArgumentNullException>("expression", () => Expression.TypeIs(null, typeof(int)));
15         }
16 
17         [Fact]
NullType()18         public void NullType()
19         {
20             Expression exp = Expression.Constant(0);
21             AssertExtensions.Throws<ArgumentNullException>("type", () => Expression.TypeIs(exp, null));
22         }
23 
24         [Fact]
TypeByRef()25         public void TypeByRef()
26         {
27             Expression exp = Expression.Constant(0);
28             Type byRef = typeof(int).MakeByRefType();
29             AssertExtensions.Throws<ArgumentException>("type", () => Expression.TypeIs(exp, byRef));
30         }
31 
32         [Theory, ClassData(typeof(CompilationTypes))]
TypePointer(bool useInterpreter)33         public void TypePointer(bool useInterpreter)
34         {
35             Expression exp = Expression.Constant(0);
36             Type pointer = typeof(int*);
37             var test = Expression.TypeIs(exp, pointer);
38             var lambda = Expression.Lambda<Func<bool>>(test);
39             var func = lambda.Compile(useInterpreter);
40             Assert.False(func());
41         }
42 
43         [Fact]
UnreadableExpression()44         public void UnreadableExpression()
45         {
46             Expression exp = Expression.Property(null, typeof(Unreadable<int>), "WriteOnly");
47             AssertExtensions.Throws<ArgumentException>("expression", () => Expression.TypeIs(exp, typeof(int)));
48         }
49 
50         [Fact]
CannotReduce()51         public void CannotReduce()
52         {
53             Expression exp = Expression.TypeIs(Expression.Constant(0), typeof(int));
54             Assert.False(exp.CanReduce);
55             Assert.Same(exp, exp.Reduce());
56             AssertExtensions.Throws<ArgumentException>(null, () => exp.ReduceAndCheck());
57         }
58 
59         [Theory]
60         [MemberData(nameof(ExpressionAndTypeCombinations))]
TypePropertyMatches(Expression expression, Type type)61         public void TypePropertyMatches(Expression expression, Type type)
62         {
63             Assert.Equal(type, Expression.TypeIs(expression, type).TypeOperand);
64         }
65 
66         [Theory]
67         [MemberData(nameof(ExpressionAndTypeCombinations))]
TypeIsBoolean(Expression expression, Type type)68         public void TypeIsBoolean(Expression expression, Type type)
69         {
70             Assert.Equal(typeof(bool), Expression.TypeIs(expression, type).Type);
71         }
72 
73         [Theory]
74         [MemberData(nameof(ExpressionAndTypeCombinations))]
NodeType(Expression expression, Type type)75         public void NodeType(Expression expression, Type type)
76         {
77             Assert.Equal(ExpressionType.TypeIs, Expression.TypeIs(expression, type).NodeType);
78         }
79 
80         [Theory]
81         [MemberData(nameof(ExpressionAndTypeCombinations))]
ExpressionIsThatPassed(Expression expression, Type type)82         public void ExpressionIsThatPassed(Expression expression, Type type)
83         {
84             Assert.Same(expression, Expression.TypeIs(expression, type).Expression);
85         }
86 
87         [Theory]
88         [PerCompilationType(nameof(ExpressionAndTypeCombinations))]
ExpressionEvaluationCompiled(Expression expression, Type type, bool useInterpreter)89         public void ExpressionEvaluationCompiled(Expression expression, Type type, bool useInterpreter)
90         {
91             bool expected = expression.Type == typeof(void)
92                 ? type == typeof(void)
93                 : type.IsInstanceOfType(Expression.Lambda<Func<object>>(Expression.Convert(expression, typeof(object))).Compile()());
94 
95             Assert.Equal(expected, Expression.Lambda<Func<bool>>(Expression.TypeIs(expression, type)).Compile(useInterpreter)());
96         }
97 
98         [Theory]
99         [PerCompilationType(nameof(ExpressionAndTypeCombinations))]
ExpressionEvaluationWithParameter(Expression expression, Type type, bool useInterpreter)100         public void ExpressionEvaluationWithParameter(Expression expression, Type type, bool useInterpreter)
101         {
102             if (expression.Type == typeof(void))
103                 return; // Can't have void parameter.
104 
105             bool expected = expression.Type == typeof(void)
106                 ? type == typeof(void)
107                 : type.IsInstanceOfType(Expression.Lambda<Func<object>>(Expression.Convert(expression, typeof(object))).Compile()());
108 
109             ParameterExpression param = Expression.Parameter(expression.Type);
110 
111             Func<bool> func = Expression.Lambda<Func<bool>>(
112                 Expression.Block(
113                     new[] { param },
114                     Expression.Assign(param, expression),
115                     Expression.TypeIs(param, type)
116                     )
117                 ).Compile(useInterpreter);
118 
119             Assert.Equal(expected, func());
120         }
121 
122         [Fact]
UpdateSameReturnsSame()123         public void UpdateSameReturnsSame()
124         {
125             Expression expression = Expression.Constant(0);
126             TypeBinaryExpression typeExp = Expression.TypeIs(expression, typeof(int));
127             Assert.Same(typeExp, typeExp.Update(expression));
128             Assert.Same(typeExp, NoOpVisitor.Instance.Visit(typeExp));
129         }
130 
131         [Fact]
UpdateNotSameReturnsNotSame()132         public void UpdateNotSameReturnsNotSame()
133         {
134             Expression expression = Expression.Constant(0);
135             TypeBinaryExpression typeExp = Expression.TypeIs(expression, typeof(int));
136             Assert.NotSame(typeExp, typeExp.Update(Expression.Constant(0)));
137         }
138 
139         [Fact]
VisitHitsVisitTypeBinary()140         public void VisitHitsVisitTypeBinary()
141         {
142             TypeBinaryExpression expression = Expression.TypeIs(Expression.Constant(0), typeof(int));
143             TypeBinaryVisitCheckingVisitor visitor = new TypeBinaryVisitCheckingVisitor();
144             visitor.Visit(expression);
145             Assert.Same(expression, visitor.LastTypeBinaryVisited);
146         }
147 
148         [Fact]
ToStringTest()149         public void ToStringTest()
150         {
151             TypeBinaryExpression e = Expression.TypeIs(Expression.Parameter(typeof(object), "o"), typeof(string));
152             Assert.Equal("(o Is String)", e.ToString());
153         }
154     }
155 }
156