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.Collections.Generic;
6 using System.Drawing;
7 using System.Globalization;
8 using System.Linq;
9 using Xunit;
10 
11 namespace System.ComponentModel.TypeConverterTests
12 {
13     public class RectangleConverterTests : StringTypeConverterTestBase<Rectangle>
14     {
15         protected override TypeConverter Converter { get; } = new RectangleConverter();
16         protected override bool StandardValuesSupported { get; } = false;
17         protected override bool StandardValuesExclusive { get; } = false;
18         protected override Rectangle Default => new Rectangle(0, 0, 100, 100);
19         protected override bool CreateInstanceSupported { get; } = true;
20         protected override bool IsGetPropertiesSupported { get; } = true;
21 
22         protected override IEnumerable<Tuple<Rectangle, Dictionary<string, object>>> CreateInstancePairs {
23             get
24             {
25                 yield return Tuple.Create(new Rectangle(10, 10, 20, 30), new Dictionary<string, object>
26                 {
27                     ["X"] = 10,
28                     ["Y"] = 10,
29                     ["Width"] = 20,
30                     ["Height"] = 30,
31                 });
32                 yield return Tuple.Create(new Rectangle(-10, -10, 20, 30), new Dictionary<string, object>
33                 {
34                     ["X"] = -10,
35                     ["Y"] = -10,
36                     ["Width"] = 20,
37                     ["Height"] = 30,
38                 });
39             }
40         }
41 
42         [Theory]
43         [InlineData(typeof(string))]
CanConvertFromTrue(Type type)44         public void CanConvertFromTrue(Type type)
45         {
46             CanConvertFrom(type);
47         }
48 
49         [Theory]
50         [InlineData(typeof(Rectangle))]
51         [InlineData(typeof(RectangleF))]
52         [InlineData(typeof(Point))]
53         [InlineData(typeof(PointF))]
54         [InlineData(typeof(Color))]
55         [InlineData(typeof(Size))]
56         [InlineData(typeof(SizeF))]
57         [InlineData(typeof(object))]
58         [InlineData(typeof(int))]
CanConvertFromFalse(Type type)59         public void CanConvertFromFalse(Type type)
60         {
61             CannotConvertFrom(type);
62         }
63 
64         [Theory]
65         [InlineData(typeof(string))]
CanConvertToTrue(Type type)66         public void CanConvertToTrue(Type type)
67         {
68             CanConvertTo(type);
69         }
70 
71         [Theory]
72         [InlineData(typeof(Rectangle))]
73         [InlineData(typeof(RectangleF))]
74         [InlineData(typeof(Point))]
75         [InlineData(typeof(PointF))]
76         [InlineData(typeof(Color))]
77         [InlineData(typeof(Size))]
78         [InlineData(typeof(SizeF))]
79         [InlineData(typeof(object))]
80         [InlineData(typeof(int))]
CanConvertToFalse(Type type)81         public void CanConvertToFalse(Type type)
82         {
83             CannotConvertTo(type);
84         }
85 
86         public static IEnumerable<object[]> RectangleData =>
87             new[]
88             {
89                 new object[] {0, 0, 0, 0},
90                 new object[] {1, 1, 1, 1},
91                 new object[] {-1, 1, 1, 1},
92                 new object[] {1, -1, 1, 1},
93                 new object[] {-1, -1, 1, 1},
94                 new object[] {int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue},
95                 new object[] {int.MinValue, int.MaxValue, int.MaxValue, int.MaxValue},
96                 new object[] {int.MaxValue, int.MinValue, int.MaxValue, int.MaxValue},
97                 new object[] {int.MinValue, int.MinValue, int.MaxValue, int.MaxValue},
98             };
99 
100         [Theory]
101         [MemberData(nameof(RectangleData))]
ConvertFrom(int x, int y, int width, int height)102         public void ConvertFrom(int x, int y, int width, int height)
103         {
104             TestConvertFromString(new Rectangle(x, y, width, height), $"{x}, {y}, {width}, {height}");
105         }
106 
107         [Theory]
108         [InlineData("10, 10")]
109         [InlineData("1, 1, 1, 1, 1")]
ConvertFrom_ArgumentException(string value)110         public void ConvertFrom_ArgumentException(string value)
111         {
112             ConvertFromThrowsArgumentExceptionForString(value);
113         }
114 
115         [Fact]
ConvertFrom_Invalid()116         public void ConvertFrom_Invalid()
117         {
118             ConvertFromThrowsFormatInnerExceptionForString("*1, 1, 1, 1");
119         }
120 
121         public static IEnumerable<object[]> ConvertFrom_NotSupportedData =>
122             new[]
123             {
124                 new object[] {new Point(10, 10)},
125                 new object[] {new PointF(10, 10)},
126                 new object[] {new Size(10, 10)},
127                 new object[] {new SizeF(10, 10)},
128                 new object[] {new object()},
129                 new object[] {1001},
130             };
131 
132         [Theory]
133         [MemberData(nameof(ConvertFrom_NotSupportedData))]
ConvertFrom_NotSupported(object value)134         public void ConvertFrom_NotSupported(object value)
135         {
136             ConvertFromThrowsNotSupportedFor(value);
137         }
138 
139         [Theory]
140         [MemberData(nameof(RectangleData))]
ConvertTo(int x, int y, int width, int height)141         public void ConvertTo(int x, int y, int width, int height)
142         {
143             TestConvertToString(new Rectangle(x, y, width, height), $"{x}, {y}, {width}, {height}");
144         }
145 
146         [Theory]
147         [InlineData(typeof(Size))]
148         [InlineData(typeof(SizeF))]
149         [InlineData(typeof(Point))]
150         [InlineData(typeof(PointF))]
151         [InlineData(typeof(object))]
152         [InlineData(typeof(int))]
ConvertTo_NotSupportedException(Type type)153         public void ConvertTo_NotSupportedException(Type type)
154         {
155             ConvertToThrowsNotSupportedForType(type);
156         }
157 
158         [Fact]
CreateInstance_CaseSensitive()159         public void CreateInstance_CaseSensitive()
160         {
161             AssertExtensions.Throws<ArgumentException>(null, () =>
162             {
163                 Converter.CreateInstance(null, new Dictionary<string, object>
164                 {
165                     ["x"] = -10,
166                     ["Y"] = -10,
167                     ["Width"] = 20,
168                     ["Height"] = 30,
169                 });
170             });
171         }
172 
173         [Fact]
TestGetProperties()174         public void TestGetProperties()
175         {
176             var rect = new Rectangle(10, 10, 20, 30);
177             var propsColl = Converter.GetProperties(rect);
178             Assert.Equal(4, propsColl.Count);
179             Assert.Equal(rect.X, propsColl["X"].GetValue(rect));
180             Assert.Equal(rect.Y, propsColl["Y"].GetValue(rect));
181             Assert.Equal(rect.Width, propsColl["Width"].GetValue(rect));
182             Assert.Equal(rect.Height, propsColl["Height"].GetValue(rect));
183 
184             rect = new Rectangle(-10, -10, 20, 30);
185             propsColl = Converter.GetProperties(null, rect);
186             Assert.Equal(4, propsColl.Count);
187             Assert.Equal(rect.X, propsColl["X"].GetValue(rect));
188             Assert.Equal(rect.Y, propsColl["Y"].GetValue(rect));
189             Assert.Equal(rect.Width, propsColl["Width"].GetValue(rect));
190             Assert.Equal(rect.Height, propsColl["Height"].GetValue(rect));
191 
192             rect = new Rectangle(10, 10, 20, 30);
193             propsColl = Converter.GetProperties(null, rect, null);
194             Assert.Equal(11, propsColl.Count);
195             Assert.Equal(rect.X, propsColl["X"].GetValue(rect));
196             Assert.Equal(rect.Y, propsColl["Y"].GetValue(rect));
197             Assert.Equal(rect.Width, propsColl["Width"].GetValue(rect));
198             Assert.Equal(rect.Height, propsColl["Height"].GetValue(rect));
199             Assert.Equal(rect.IsEmpty, propsColl["IsEmpty"].GetValue(rect));
200 
201             Assert.Equal(rect.Top, propsColl["Top"].GetValue(rect));
202             Assert.Equal(rect.Bottom, propsColl["Bottom"].GetValue(rect));
203             Assert.Equal(rect.Left, propsColl["Left"].GetValue(rect));
204             Assert.Equal(rect.Right, propsColl["Right"].GetValue(rect));
205             Assert.Equal(rect.Location, propsColl["Location"].GetValue(rect));
206             Assert.Equal(rect.Size, propsColl["Size"].GetValue(rect));
207             Assert.Equal(rect.IsEmpty, propsColl["IsEmpty"].GetValue(rect));
208 
209             // Pick an attibute that cannot be applied to properties to make sure everything gets filtered
210             propsColl = Converter.GetProperties(null, new Rectangle(10, 10, 20, 30), new Attribute[] { new System.Reflection.AssemblyCopyrightAttribute("")});
211             Assert.Equal(0, propsColl.Count);
212         }
213 
214         [Theory]
215         [MemberData(nameof(RectangleData))]
ConvertFromInvariantString(int x, int y, int width, int height)216         public void ConvertFromInvariantString(int x, int y, int width, int height)
217         {
218             var rect = (Rectangle)Converter.ConvertFromInvariantString($"{x}, {y}, {width}, {height}");
219             Assert.Equal(x, rect.X);
220             Assert.Equal(y, rect.Y);
221             Assert.Equal(width, rect.Width);
222             Assert.Equal(height, rect.Height);
223         }
224 
225         [Fact]
ConvertFromInvariantString_ArgumentException()226         public void ConvertFromInvariantString_ArgumentException()
227         {
228             ConvertFromInvariantStringThrowsArgumentException("1, 2, 3");
229         }
230 
231         [Fact]
ConvertFromInvariantString_FormatException()232         public void ConvertFromInvariantString_FormatException()
233         {
234             ConvertFromInvariantStringThrowsFormatInnerException("hello");
235         }
236 
237         [Theory]
238         [MemberData(nameof(RectangleData))]
ConvertFromString(int x, int y, int width, int height)239         public void ConvertFromString(int x, int y, int width, int height)
240         {
241             var rect =
242                 (Rectangle)Converter.ConvertFromString(string.Format("{0}{4} {1}{4} {2}{4} {3}", x, y, width, height,
243                     CultureInfo.CurrentCulture.TextInfo.ListSeparator));
244             Assert.Equal(x, rect.X);
245             Assert.Equal(y, rect.Y);
246             Assert.Equal(width, rect.Width);
247             Assert.Equal(height, rect.Height);
248         }
249 
250         [Fact]
ConvertFromString_ArgumentException()251         public void ConvertFromString_ArgumentException()
252         {
253             ConvertFromStringThrowsArgumentException(string.Format("1{0} 1{0} 1{0} 1{0} 1",
254                 CultureInfo.CurrentCulture.TextInfo.ListSeparator));
255         }
256 
257         [Fact]
ConvertFromString_FormatException()258         public void ConvertFromString_FormatException()
259         {
260             ConvertFromStringThrowsFormatInnerException("hello");
261         }
262 
263         [Theory]
264         [MemberData(nameof(RectangleData))]
ConvertToInvariantString(int x, int y, int width, int height)265         public void ConvertToInvariantString(int x, int y, int width, int height)
266         {
267             var str = Converter.ConvertToInvariantString(new Rectangle(x, y, width, height));
268             Assert.Equal($"{x}, {y}, {width}, {height}", str);
269         }
270 
271         [Theory]
272         [MemberData(nameof(RectangleData))]
ConvertToString(int x, int y, int width, int height)273         public void ConvertToString(int x, int y, int width, int height)
274         {
275             var str = Converter.ConvertToString(new Rectangle(x, y, width, height));
276             Assert.Equal(
277                 string.Format("{0}{4} {1}{4} {2}{4} {3}", x, y, width, height,
278                     CultureInfo.CurrentCulture.TextInfo.ListSeparator), str);
279         }
280     }
281 }
282