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 System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Linq;
9 using System.Runtime.CompilerServices;
10 using System.Runtime.Serialization;
11 using Xunit;
12 
13 namespace Microsoft.CSharp.RuntimeBinder.Tests
14 {
15     public class ImplicitConversionTests
16     {
AssertImplicitConvert(TSource argument, TTarget expected)17         private static void AssertImplicitConvert<TSource, TTarget>(TSource argument, TTarget expected)
18         {
19             CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, typeof(TTarget), typeof(ImplicitConversionTests));
20             CallSite<Func<CallSite, TSource, TTarget>> callSite =
21                 CallSite<Func<CallSite, TSource, TTarget>>.Create(binder);
22             Func<CallSite, TSource, TTarget> func = callSite.Target;
23             TTarget result = func(callSite, argument);
24             Assert.Equal(expected, result);
25 
26             if (typeof(TSource) != typeof(object))
27             {
28                 AssertImplicitConvert<object, TTarget>(argument, expected);
29             }
30         }
31 
AssertBadImplicitConvert(TSource argument)32         private static void AssertBadImplicitConvert<TSource, TTarget>(TSource argument)
33         {
34             CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, typeof(TTarget), typeof(ImplicitConversionTests));
35             CallSite<Func<CallSite, TSource, TTarget>> callSite =
36                 CallSite<Func<CallSite, TSource, TTarget>>.Create(binder);
37             Func<CallSite, TSource, TTarget> func = callSite.Target;
38             Assert.Throws<RuntimeBinderException>(() => func(callSite, argument));
39 
40             if (typeof(TSource) != typeof(object))
41             {
42                 AssertBadImplicitConvert<object, TTarget>(argument);
43             }
44         }
45 
TestTypeAsArgument(TTarget argument)46         private static void TestTypeAsArgument<TTarget>(TTarget argument)
47         {
48             // Do nothing. Just test whether something can be accepted as an argument.
49         }
50 
TestBadTypeAsArgument(dynamic argument)51         private static void TestBadTypeAsArgument<TTarget>(dynamic argument)
52         {
53             Assert.Throws<RuntimeBinderException>(() => TestTypeAsArgument<TTarget>(argument));
54         }
55 
56         [Fact]
NullablesToValueTypeUp()57         public void NullablesToValueTypeUp()
58         {
59             AssertImplicitConvert<int?, ValueType>(2, 2);
60             AssertImplicitConvert<int?, ValueType>(null, null);
61             AssertImplicitConvert<int?, object>(2, 2);
62         }
63 
64 
65         [Fact]
NullablesToBaseTypesInterfaces()66         public void NullablesToBaseTypesInterfaces()
67         {
68             AssertImplicitConvert<int?, IEquatable<int>>(2, 2);
69             AssertImplicitConvert<int?, IEquatable<int>>(null, null);
70             AssertImplicitConvert<int?, IComparable<int>>(2, 2);
71             AssertImplicitConvert<int?, IComparable>(2, 2);
72             AssertImplicitConvert<int?, IConvertible>(2, 2);
73             AssertImplicitConvert<int?, IFormattable>(2, 2);
74         }
75 
76         [Fact]
NumericConversions()77         public void NumericConversions()
78         {
79             AssertImplicitConvert<sbyte, short>(1, 1);
80             AssertImplicitConvert<sbyte, int>(1, 1);
81             AssertImplicitConvert<sbyte, long>(1, 1);
82             AssertImplicitConvert<sbyte, float>(1, 1);
83             AssertImplicitConvert<sbyte, double>(1, 1);
84             AssertImplicitConvert<sbyte, decimal>(1, 1);
85 
86             AssertImplicitConvert<byte, short>(1, 1);
87             AssertImplicitConvert<byte, ushort>(1, 1);
88             AssertImplicitConvert<byte, int>(1, 1);
89             AssertImplicitConvert<byte, uint>(1, 1);
90             AssertImplicitConvert<byte, long>(1, 1);
91             AssertImplicitConvert<byte, ulong>(1, 1);
92             AssertImplicitConvert<byte, float>(1, 1);
93             AssertImplicitConvert<byte, double>(1, 1);
94             AssertImplicitConvert<byte, decimal>(1, 1);
95 
96             AssertImplicitConvert<short, int>(1, 1);
97             AssertImplicitConvert<short, long>(1, 1);
98             AssertImplicitConvert<short, float>(1, 1);
99             AssertImplicitConvert<short, double>(1, 1);
100             AssertImplicitConvert<short, decimal>(1, 1);
101 
102             AssertImplicitConvert<ushort, int>(1, 1);
103             AssertImplicitConvert<ushort, uint>(1, 1);
104             AssertImplicitConvert<ushort, long>(1, 1);
105             AssertImplicitConvert<ushort, ulong>(1, 1);
106             AssertImplicitConvert<ushort, float>(1, 1);
107             AssertImplicitConvert<ushort, double>(1, 1);
108             AssertImplicitConvert<ushort, decimal>(1, 1);
109 
110             AssertImplicitConvert<int, long>(1, 1);
111             AssertImplicitConvert<int, float>(1, 1);
112             AssertImplicitConvert<int, double>(1, 1);
113             AssertImplicitConvert<int, decimal>(1, 1);
114 
115             AssertImplicitConvert<uint, long>(1, 1);
116             AssertImplicitConvert<uint, ulong>(1, 1);
117             AssertImplicitConvert<uint, float>(1, 1);
118             AssertImplicitConvert<uint, double>(1, 1);
119             AssertImplicitConvert<uint, decimal>(1, 1);
120 
121             AssertImplicitConvert<long, float>(1, 1);
122             AssertImplicitConvert<long, double>(1, 1);
123             AssertImplicitConvert<long, decimal>(1, 1);
124 
125             AssertImplicitConvert<ulong, float>(1, 1);
126             AssertImplicitConvert<ulong, double>(1, 1);
127             AssertImplicitConvert<ulong, decimal>(1, 1);
128 
129             AssertImplicitConvert<float, double>(1, 1);
130 
131             AssertImplicitConvert<char, ushort>('a', 'a');
132             AssertImplicitConvert<char, int>('a', 'a');
133             AssertImplicitConvert<char, uint>('a', 'a');
134             AssertImplicitConvert<char, long>('a', 'a');
135             AssertImplicitConvert<char, ulong>('a', 'a');
136             AssertImplicitConvert<char, float>('a', 'a');
137             AssertImplicitConvert<char, double>('a', 'a');
138             AssertImplicitConvert<char, decimal>('a', 'a');
139         }
140 
141         [Fact]
NumericNullableConversions()142         public void NumericNullableConversions()
143         {
144             AssertImplicitConvert<sbyte, short?>(1, 1);
145             AssertImplicitConvert<sbyte, int?>(1, 1);
146             AssertImplicitConvert<sbyte, long?>(1, 1);
147             AssertImplicitConvert<sbyte, float?>(1, 1);
148             AssertImplicitConvert<sbyte, double?>(1, 1);
149             AssertImplicitConvert<sbyte, decimal?>(1, 1);
150 
151             AssertImplicitConvert<byte, short?>(1, 1);
152             AssertImplicitConvert<byte, ushort?>(1, 1);
153             AssertImplicitConvert<byte, int?>(1, 1);
154             AssertImplicitConvert<byte, uint?>(1, 1);
155             AssertImplicitConvert<byte, long?>(1, 1);
156             AssertImplicitConvert<byte, ulong?>(1, 1);
157             AssertImplicitConvert<byte, float?>(1, 1);
158             AssertImplicitConvert<byte, double?>(1, 1);
159             AssertImplicitConvert<byte, decimal?>(1, 1);
160 
161             AssertImplicitConvert<short, int?>(1, 1);
162             AssertImplicitConvert<short, long?>(1, 1);
163             AssertImplicitConvert<short, float?>(1, 1);
164             AssertImplicitConvert<short, double?>(1, 1);
165             AssertImplicitConvert<short, decimal?>(1, 1);
166 
167             AssertImplicitConvert<ushort, int?>(1, 1);
168             AssertImplicitConvert<ushort, uint?>(1, 1);
169             AssertImplicitConvert<ushort, long?>(1, 1);
170             AssertImplicitConvert<ushort, ulong?>(1, 1);
171             AssertImplicitConvert<ushort, float?>(1, 1);
172             AssertImplicitConvert<ushort, double?>(1, 1);
173             AssertImplicitConvert<ushort, decimal?>(1, 1);
174 
175             AssertImplicitConvert<int, long?>(1, 1);
176             AssertImplicitConvert<int, float?>(1, 1);
177             AssertImplicitConvert<int, double?>(1, 1);
178             AssertImplicitConvert<int, decimal?>(1, 1);
179 
180             AssertImplicitConvert<uint, long?>(1, 1);
181             AssertImplicitConvert<uint, ulong?>(1, 1);
182             AssertImplicitConvert<uint, float?>(1, 1);
183             AssertImplicitConvert<uint, double?>(1, 1);
184             AssertImplicitConvert<uint, decimal?>(1, 1);
185 
186             AssertImplicitConvert<long, float?>(1, 1);
187             AssertImplicitConvert<long, double?>(1, 1);
188             AssertImplicitConvert<long, decimal?>(1, 1);
189 
190             AssertImplicitConvert<ulong, float?>(1, 1);
191             AssertImplicitConvert<ulong, double?>(1, 1);
192             AssertImplicitConvert<ulong, decimal?>(1, 1);
193 
194             AssertImplicitConvert<float, double?>(1, 1);
195 
196             AssertImplicitConvert<char, ushort?>('a', 'a');
197             AssertImplicitConvert<char, int?>('a', 'a');
198             AssertImplicitConvert<char, uint?>('a', 'a');
199             AssertImplicitConvert<char, long?>('a', 'a');
200             AssertImplicitConvert<char, ulong?>('a', 'a');
201             AssertImplicitConvert<char, float?>('a', 'a');
202             AssertImplicitConvert<char, double?>('a', 'a');
203             AssertImplicitConvert<char, decimal?>('a', 'a');
204         }
205 
206         [Fact]
NumericNullableToNullableConversions()207         public void NumericNullableToNullableConversions()
208         {
209             AssertImplicitConvert<sbyte?, short?>(1, 1);
210             AssertImplicitConvert<sbyte?, int?>(1, 1);
211             AssertImplicitConvert<sbyte?, long?>(1, 1);
212             AssertImplicitConvert<sbyte?, float?>(1, 1);
213             AssertImplicitConvert<sbyte?, double?>(1, 1);
214             AssertImplicitConvert<sbyte?, decimal?>(1, 1);
215 
216             AssertImplicitConvert<byte?, short?>(1, 1);
217             AssertImplicitConvert<byte?, ushort?>(1, 1);
218             AssertImplicitConvert<byte?, int?>(1, 1);
219             AssertImplicitConvert<byte?, uint?>(1, 1);
220             AssertImplicitConvert<byte?, long?>(1, 1);
221             AssertImplicitConvert<byte?, ulong?>(1, 1);
222             AssertImplicitConvert<byte?, float?>(1, 1);
223             AssertImplicitConvert<byte?, double?>(1, 1);
224             AssertImplicitConvert<byte?, decimal?>(1, 1);
225 
226             AssertImplicitConvert<short?, int?>(1, 1);
227             AssertImplicitConvert<short?, long?>(1, 1);
228             AssertImplicitConvert<short?, float?>(1, 1);
229             AssertImplicitConvert<short?, double?>(1, 1);
230             AssertImplicitConvert<short?, decimal?>(1, 1);
231 
232             AssertImplicitConvert<ushort?, int?>(1, 1);
233             AssertImplicitConvert<ushort?, uint?>(1, 1);
234             AssertImplicitConvert<ushort?, long?>(1, 1);
235             AssertImplicitConvert<ushort?, ulong?>(1, 1);
236             AssertImplicitConvert<ushort?, float?>(1, 1);
237             AssertImplicitConvert<ushort?, double?>(1, 1);
238             AssertImplicitConvert<ushort?, decimal?>(1, 1);
239 
240             AssertImplicitConvert<int?, long?>(1, 1);
241             AssertImplicitConvert<int?, float?>(1, 1);
242             AssertImplicitConvert<int?, double?>(1, 1);
243             AssertImplicitConvert<int?, decimal?>(1, 1);
244 
245             AssertImplicitConvert<uint?, long?>(1, 1);
246             AssertImplicitConvert<uint?, ulong?>(1, 1);
247             AssertImplicitConvert<uint?, float?>(1, 1);
248             AssertImplicitConvert<uint?, double?>(1, 1);
249             AssertImplicitConvert<uint?, decimal?>(1, 1);
250 
251             AssertImplicitConvert<long?, float?>(1, 1);
252             AssertImplicitConvert<long?, double?>(1, 1);
253             AssertImplicitConvert<long?, decimal?>(1, 1);
254 
255             AssertImplicitConvert<ulong?, float?>(1, 1);
256             AssertImplicitConvert<ulong?, double?>(1, 1);
257             AssertImplicitConvert<ulong?, decimal?>(1, 1);
258 
259             AssertImplicitConvert<float?, double?>(1, 1);
260 
261             AssertImplicitConvert<char?, ushort?>('a', 'a');
262             AssertImplicitConvert<char?, int?>('a', 'a');
263             AssertImplicitConvert<char?, uint?>('a', 'a');
264             AssertImplicitConvert<char?, long?>('a', 'a');
265             AssertImplicitConvert<char?, ulong?>('a', 'a');
266             AssertImplicitConvert<char?, float?>('a', 'a');
267             AssertImplicitConvert<char?, double?>('a', 'a');
268             AssertImplicitConvert<char?, decimal?>('a', 'a');
269 
270             AssertImplicitConvert<sbyte?, short?>(null, null);
271             AssertImplicitConvert<sbyte?, int?>(null, null);
272             AssertImplicitConvert<sbyte?, long?>(null, null);
273             AssertImplicitConvert<sbyte?, float?>(null, null);
274             AssertImplicitConvert<sbyte?, double?>(null, null);
275             AssertImplicitConvert<sbyte?, decimal?>(null, null);
276 
277             AssertImplicitConvert<byte?, short?>(null, null);
278             AssertImplicitConvert<byte?, ushort?>(null, null);
279             AssertImplicitConvert<byte?, int?>(null, null);
280             AssertImplicitConvert<byte?, uint?>(null, null);
281             AssertImplicitConvert<byte?, long?>(null, null);
282             AssertImplicitConvert<byte?, ulong?>(null, null);
283             AssertImplicitConvert<byte?, float?>(null, null);
284             AssertImplicitConvert<byte?, double?>(null, null);
285             AssertImplicitConvert<byte?, decimal?>(null, null);
286 
287             AssertImplicitConvert<short?, int?>(null, null);
288             AssertImplicitConvert<short?, long?>(null, null);
289             AssertImplicitConvert<short?, float?>(null, null);
290             AssertImplicitConvert<short?, double?>(null, null);
291             AssertImplicitConvert<short?, decimal?>(null, null);
292 
293             AssertImplicitConvert<ushort?, int?>(null, null);
294             AssertImplicitConvert<ushort?, uint?>(null, null);
295             AssertImplicitConvert<ushort?, long?>(null, null);
296             AssertImplicitConvert<ushort?, ulong?>(null, null);
297             AssertImplicitConvert<ushort?, float?>(null, null);
298             AssertImplicitConvert<ushort?, double?>(null, null);
299             AssertImplicitConvert<ushort?, decimal?>(null, null);
300 
301             AssertImplicitConvert<int?, long?>(null, null);
302             AssertImplicitConvert<int?, float?>(null, null);
303             AssertImplicitConvert<int?, double?>(null, null);
304             AssertImplicitConvert<int?, decimal?>(null, null);
305 
306             AssertImplicitConvert<uint?, long?>(null, null);
307             AssertImplicitConvert<uint?, ulong?>(null, null);
308             AssertImplicitConvert<uint?, float?>(null, null);
309             AssertImplicitConvert<uint?, double?>(null, null);
310             AssertImplicitConvert<uint?, decimal?>(null, null);
311 
312             AssertImplicitConvert<long?, float?>(null, null);
313             AssertImplicitConvert<long?, double?>(null, null);
314             AssertImplicitConvert<long?, decimal?>(null, null);
315 
316             AssertImplicitConvert<ulong?, float?>(null, null);
317             AssertImplicitConvert<ulong?, double?>(null, null);
318             AssertImplicitConvert<ulong?, decimal?>(null, null);
319 
320             AssertImplicitConvert<float?, double?>(null, null);
321 
322             AssertImplicitConvert<char?, ushort?>(null, null);
323             AssertImplicitConvert<char?, int?>(null, null);
324             AssertImplicitConvert<char?, uint?>(null, null);
325             AssertImplicitConvert<char?, long?>(null, null);
326             AssertImplicitConvert<char?, ulong?>(null, null);
327             AssertImplicitConvert<char?, float?>(null, null);
328             AssertImplicitConvert<char?, double?>(null, null);
329             AssertImplicitConvert<char?, decimal?>(null, null);
330         }
331 
332         [Fact]
StructToInterfacesAndBase()333         public void StructToInterfacesAndBase()
334         {
335             DateTime now = DateTime.Now;
336             AssertImplicitConvert<DateTime, IEquatable<DateTime>>(now, now);
337             AssertImplicitConvert<DateTime, IComparable<DateTime>>(now, now);
338             AssertImplicitConvert<DateTime, ISerializable>(now, now);
339             AssertImplicitConvert<DateTime, IFormattable>(now, now);
340         }
341 
342         [Fact]
ArraysToInterfaces()343         public void ArraysToInterfaces()
344         {
345             int[] intArray = {1, 2, 3};
346             AssertImplicitConvert<int[], IEnumerable>(intArray, intArray);
347             AssertImplicitConvert<int[], IEnumerable<int>>(intArray, intArray);
348             AssertImplicitConvert<int[], IList<int>>(intArray, intArray);
349             AssertImplicitConvert<int[], ICollection<int>>(intArray, intArray);
350             AssertImplicitConvert<int[], IReadOnlyList<int>>(intArray, intArray);
351             AssertImplicitConvert<int[], IReadOnlyCollection<int>>(intArray, intArray);
352         }
353 
354         [Fact]
ArraysToInterfacesAsArguments()355         public void ArraysToInterfacesAsArguments()
356         {
357             dynamic intArray = new[] {1, 2, 3};
358             TestTypeAsArgument<IEnumerable>(intArray);
359             TestTypeAsArgument<IEnumerable<int>>(intArray);
360             TestTypeAsArgument<IList<int>>(intArray);
361             TestTypeAsArgument<ICollection<int>>(intArray);
362             TestTypeAsArgument<IReadOnlyList<int>>(intArray);
363             TestTypeAsArgument<IReadOnlyCollection<int>>(intArray);
364         }
365 
366         [Fact]
ArraysToIncompatibleInterfaces()367         public void ArraysToIncompatibleInterfaces()
368         {
369             int[] intArray = { 1, 2, 3 };
370             AssertBadImplicitConvert<int[], IEnumerable<string>>(intArray);
371             AssertBadImplicitConvert<int[], IList<int?>>(intArray);
372             AssertBadImplicitConvert<int[], ICollection<Uri>>(intArray);
373             AssertBadImplicitConvert<int[], IReadOnlyList<DateTime>>(intArray);
374             AssertBadImplicitConvert<int[], IReadOnlyCollection<long>>(intArray);
375             AssertBadImplicitConvert<int[], IOrderedEnumerable<int>>(intArray);
376         }
377 
378         [Fact]
ArraysToIncompatibleInterfacesAsArgument()379         public void ArraysToIncompatibleInterfacesAsArgument()
380         {
381             int[] intArray = { 1, 2, 3 };
382             TestBadTypeAsArgument<IEnumerable<string>>(intArray);
383             TestBadTypeAsArgument<IList<int?>>(intArray);
384             TestBadTypeAsArgument<ICollection<Uri>>(intArray);
385             TestBadTypeAsArgument<IReadOnlyList<DateTime>>(intArray);
386             TestBadTypeAsArgument<IReadOnlyCollection<long>>(intArray);
387             TestBadTypeAsArgument<IOrderedEnumerable<int>>(intArray);
388         }
389     }
390 }
391