|
| 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 | + |
| 4 | +using System.ComponentModel.Design.Serialization; |
| 5 | +using System.Globalization; |
| 6 | + |
| 7 | +namespace System.Windows.Media.Animation; |
| 8 | + |
| 9 | +public sealed class KeySplineConverterTests |
| 10 | +{ |
| 11 | + [Theory] |
| 12 | + // Valid type |
| 13 | + [InlineData(true, typeof(string))] |
| 14 | + // Invalid types |
| 15 | + [InlineData(false, typeof(Duration))] |
| 16 | + [InlineData(false, typeof(TimeSpan))] |
| 17 | + [InlineData(false, typeof(InstanceDescriptor))] |
| 18 | + [InlineData(false, typeof(KeySpline))] |
| 19 | + [InlineData(false, typeof(int))] |
| 20 | + public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType) |
| 21 | + { |
| 22 | + KeySplineConverter converter = new(); |
| 23 | + |
| 24 | + Assert.Equal(expected, converter.CanConvertFrom(sourceType)); |
| 25 | + } |
| 26 | + |
| 27 | + [Theory] |
| 28 | + // Valid types |
| 29 | + [InlineData(true, typeof(string))] |
| 30 | + [InlineData(true, typeof(InstanceDescriptor))] |
| 31 | + // Invalid types |
| 32 | + [InlineData(false, typeof(Duration))] |
| 33 | + [InlineData(false, typeof(TimeSpan))] |
| 34 | + [InlineData(false, typeof(KeySpline))] |
| 35 | + [InlineData(false, typeof(int))] |
| 36 | + [InlineData(false, typeof(long))] |
| 37 | + public void CanConvertTo_ReturnsExpected(bool expected, Type destinationType) |
| 38 | + { |
| 39 | + KeySplineConverter converter = new(); |
| 40 | + |
| 41 | + Assert.Equal(expected, converter.CanConvertTo(destinationType)); |
| 42 | + } |
| 43 | + |
| 44 | + [Theory] |
| 45 | + [MemberData(nameof(ConvertFrom_ValidValues_ReturnsExpected_Data))] |
| 46 | + public void ConvertFrom_ValidValues_ReturnsExpected(string input, double x1, double y1, double x2, double y2, CultureInfo culture) |
| 47 | + { |
| 48 | + KeySplineConverter converter = new(); |
| 49 | + |
| 50 | + KeySpline? result = (KeySpline?)converter.ConvertFrom(null, culture, input); |
| 51 | + Assert.NotNull(result); |
| 52 | + |
| 53 | + Assert.Equal(x1, result.ControlPoint1.X); |
| 54 | + Assert.Equal(y1, result.ControlPoint1.Y); |
| 55 | + Assert.Equal(x2, result.ControlPoint2.X); |
| 56 | + Assert.Equal(y2, result.ControlPoint2.Y); |
| 57 | + } |
| 58 | + |
| 59 | + public static IEnumerable<object[]> ConvertFrom_ValidValues_ReturnsExpected_Data |
| 60 | + { |
| 61 | + get |
| 62 | + { |
| 63 | + yield return new object[] { "0.25,0.1,0.25,1", 0.25, 0.1, 0.25, 1.0, CultureInfo.InvariantCulture }; |
| 64 | + yield return new object[] { "0,25 ;0,1;0,25;1", 0.25, 0.1, 0.25, 1.0, new CultureInfo("fr-FR") }; |
| 65 | + yield return new object[] { " 0,25;0,1 ;0,25;1", 0.25, 0.1, 0.25, 1.0, new CultureInfo("de-DE") }; |
| 66 | + yield return new object[] { "0.25,0.1,0.25,1", 0.25, 0.1, 0.25, 1.0, new CultureInfo("en-US") }; |
| 67 | + yield return new object[] { "0,25; 0,1;0,25;1 ", 0.25, 0.1, 0.25, 1.0, new CultureInfo("es-ES") }; |
| 68 | + yield return new object[] { "0.5,0.75,0.25,0.9", 0.5, 0.75, 0.25, 0.9, CultureInfo.InvariantCulture }; |
| 69 | + yield return new object[] { "0,5;0,75;0,25; 0,9", 0.5, 0.75, 0.25, 0.9, new CultureInfo("fr-FR") }; |
| 70 | + yield return new object[] { "1,0,0,1", 1.0, 0.0, 0.0, 1.0, CultureInfo.InvariantCulture }; |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + [Theory] |
| 75 | + [MemberData(nameof(ConvertFrom_KeySpline_ThrowsArgumentException_Data))] |
| 76 | + public void ConvertFrom_KeySpline_ThrowsArgumentException(string input, CultureInfo cultureInfo) |
| 77 | + { |
| 78 | + KeySplineConverter converter = new(); |
| 79 | + |
| 80 | + // This throws in KeySpline actually as X values cannot be over 1.0 |
| 81 | + Assert.Throws<ArgumentException>(() => converter.ConvertFrom(null, cultureInfo, input)); |
| 82 | + } |
| 83 | + |
| 84 | + public static IEnumerable<object[]> ConvertFrom_KeySpline_ThrowsArgumentException_Data |
| 85 | + { |
| 86 | + get |
| 87 | + { |
| 88 | + yield return new object[] { "0.3, 0.4, 77771.6, 0.7", CultureInfo.InvariantCulture }; |
| 89 | + yield return new object[] { " 1.1, 0.4, 0.6, 0.7", CultureInfo.InvariantCulture }; |
| 90 | + yield return new object[] { "040.3, 881.2, 0.6, 0.7", CultureInfo.InvariantCulture }; |
| 91 | + yield return new object[] { "8,3; 0,4; 0,6; 1,8", new CultureInfo("fr-FR") }; |
| 92 | + yield return new object[] { "1.1, 1.2, 0.6, 0.7 ", CultureInfo.InvariantCulture }; |
| 93 | + yield return new object[] { "1110.3, 1.4, 1.6, 0.7", CultureInfo.InvariantCulture }; |
| 94 | + yield return new object[] { "8888.9, 0.4, 0.6, 1.2", CultureInfo.InvariantCulture }; |
| 95 | + yield return new object[] { "0.3, 0.4, 1.7776, 1.2", CultureInfo.InvariantCulture }; |
| 96 | + yield return new object[] { "1.3, 0.4, 0.66666, 1.2", CultureInfo.InvariantCulture }; |
| 97 | + yield return new object[] { "0.3, 1.8, 40.6, 1.2", CultureInfo.InvariantCulture }; |
| 98 | + yield return new object[] { "1.3, 1.8, 0.6, 0.7", CultureInfo.InvariantCulture }; |
| 99 | + yield return new object[] { "90.3, 1.8, 0.6, 72.2", CultureInfo.InvariantCulture }; |
| 100 | + yield return new object[] { "1.3, 0.4, 1.6, 25", CultureInfo.InvariantCulture }; |
| 101 | + yield return new object[] { "2221.3, 1.4, 1.6, 2.2", CultureInfo.InvariantCulture }; |
| 102 | + yield return new object[] { "0.3, 1.4, 110.6, 2.2", CultureInfo.InvariantCulture }; |
| 103 | + yield return new object[] { "1.1, 0.4, 1.6, 2.2", CultureInfo.InvariantCulture }; |
| 104 | + yield return new object[] { " 0.3, 1.8, 1.6, 0.7", new CultureInfo("de-DE") }; |
| 105 | + yield return new object[] { "1.3, 1.4, 0.6, 0.7", CultureInfo.InvariantCulture }; |
| 106 | + yield return new object[] { "0.3, 0.4, 1.6, 2.7", CultureInfo.InvariantCulture }; |
| 107 | + yield return new object[] { "1.3, 0.4, 1.6, 2.7", CultureInfo.InvariantCulture }; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + [Theory] |
| 112 | + [InlineData("invalid")] |
| 113 | + [InlineData("0.1, invalid")] |
| 114 | + [InlineData("0.1,invalid,0.3")] |
| 115 | + [InlineData("0.1, 0.2, 0.3, invalid")] |
| 116 | + [InlineData("0.1, 0.2, invalid, 0.3, 0.7 ")] |
| 117 | + public void ConvertFrom_DoubleParse_ThrowsFormatException(string input) |
| 118 | + { |
| 119 | + KeySplineConverter converter = new(); |
| 120 | + |
| 121 | + Assert.Throws<FormatException>(() => converter.ConvertFrom(null, CultureInfo.InvariantCulture, input)); |
| 122 | + } |
| 123 | + |
| 124 | + [Theory] |
| 125 | + [InlineData("")] |
| 126 | + [InlineData("0.1")] |
| 127 | + [InlineData("0.1,0.2")] |
| 128 | + [InlineData("0.1,0.2,0.3")] |
| 129 | + [InlineData("0.7, 0.5, 0.3")] |
| 130 | + [InlineData(" 0.1, 0.2")] |
| 131 | + [InlineData("0.1, 0.2, 0.3")] |
| 132 | + public void ConvertFrom_Tokenizer_ThrowsInvalidOperationException(string input) |
| 133 | + { |
| 134 | + KeySplineConverter converter = new(); |
| 135 | + |
| 136 | + Assert.Throws<InvalidOperationException>(() => converter.ConvertFrom(null, CultureInfo.InvariantCulture, input)); |
| 137 | + } |
| 138 | + |
| 139 | + [Fact] |
| 140 | + public void ConvertFrom_NULL_ThrowsNotSupportedException() |
| 141 | + { |
| 142 | + KeySplineConverter converter = new(); |
| 143 | + |
| 144 | + // TODO: Remove suppression once nullable annotations are done |
| 145 | + Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, CultureInfo.InvariantCulture, null!)); |
| 146 | + } |
| 147 | + |
| 148 | + [MemberData(nameof(ConvertTo_String_ReturnsExpected_Data))] |
| 149 | + [Theory] |
| 150 | + public void ConvertTo_String_ReturnsExpected(KeySpline keySpline, CultureInfo culture, string expected) |
| 151 | + { |
| 152 | + KeySplineConverter converter = new(); |
| 153 | + |
| 154 | + Assert.Equal(expected, converter.ConvertTo(null, culture, keySpline, typeof(string))); |
| 155 | + } |
| 156 | + |
| 157 | + public static IEnumerable<object[]> ConvertTo_String_ReturnsExpected_Data |
| 158 | + { |
| 159 | + get |
| 160 | + { |
| 161 | + yield return new object[] |
| 162 | + { |
| 163 | + new KeySpline { ControlPoint1 = new Point(0.25, 0.1), ControlPoint2 = new Point(0.25, 1.0) }, |
| 164 | + CultureInfo.InvariantCulture, "0.25,0.1,0.25,1" |
| 165 | + }; |
| 166 | + yield return new object[] |
| 167 | + { |
| 168 | + new KeySpline { ControlPoint1 = new Point(0.5, 0.75), ControlPoint2 = new Point(0.25, 0.9) }, |
| 169 | + CultureInfo.InvariantCulture, "0.5,0.75,0.25,0.9" |
| 170 | + }; |
| 171 | + yield return new object[] |
| 172 | + { |
| 173 | + new KeySpline { ControlPoint1 = new Point(1.0, 0.0), ControlPoint2 = new Point(0.0, 1.0) }, |
| 174 | + new CultureInfo("en-US"), "1,0,0,1" |
| 175 | + }; |
| 176 | + yield return new object[] |
| 177 | + { |
| 178 | + new KeySpline { ControlPoint1 = new Point(1.0, 0.0), ControlPoint2 = new Point(0.0, 1.0) }, |
| 179 | + new CultureInfo("fr-FR"), "1;0;0;1" |
| 180 | + }; |
| 181 | + yield return new object[] |
| 182 | + { |
| 183 | + new KeySpline { ControlPoint1 = new Point(0.3, 0.2), ControlPoint2 = new Point(0.4, 0.8) }, |
| 184 | + new CultureInfo("de-DE"), "0,3;0,2;0,4;0,8" |
| 185 | + }; |
| 186 | + yield return new object[] |
| 187 | + { |
| 188 | + new KeySpline { ControlPoint1 = new Point(0.12, 0.34), ControlPoint2 = new Point(0.56, 0.78) }, |
| 189 | + CultureInfo.InvariantCulture, "0.12,0.34,0.56,0.78" |
| 190 | + }; |
| 191 | + yield return new object[] |
| 192 | + { |
| 193 | + new KeySpline { ControlPoint1 = new Point(0.9, 0.1), ControlPoint2 = new Point(0.3, 0.7) }, |
| 194 | + CultureInfo.InvariantCulture, "0.9,0.1,0.3,0.7" |
| 195 | + }; |
| 196 | + yield return new object[] |
| 197 | + { |
| 198 | + new KeySpline { ControlPoint1 = new Point(0.0, 0.5), ControlPoint2 = new Point(1.0, 0.5) }, |
| 199 | + CultureInfo.InvariantCulture, "0,0.5,1,0.5" |
| 200 | + }; |
| 201 | + yield return new object[] |
| 202 | + { |
| 203 | + new KeySpline { ControlPoint1 = new Point(0.15, 0.35), ControlPoint2 = new Point(0.85, 0.95) }, |
| 204 | + CultureInfo.InvariantCulture, "0.15,0.35,0.85,0.95" |
| 205 | + }; |
| 206 | + yield return new object[] |
| 207 | + { |
| 208 | + new KeySpline { ControlPoint1 = new Point(0.6, 0.4), ControlPoint2 = new Point(0.2, 0.8) }, |
| 209 | + new CultureInfo("en-US"), "0.6,0.4,0.2,0.8" |
| 210 | + }; |
| 211 | + yield return new object[] |
| 212 | + { |
| 213 | + new KeySpline { ControlPoint1 = new Point(0.33, 0.67), ControlPoint2 = new Point(0.25, 0.75) }, |
| 214 | + CultureInfo.InvariantCulture, "0.33,0.67,0.25,0.75" |
| 215 | + }; |
| 216 | + yield return new object[] |
| 217 | + { |
| 218 | + new KeySpline { ControlPoint1 = new Point(0.2, 0.8), ControlPoint2 = new Point(0.4, 0.6) }, |
| 219 | + new CultureInfo("fr-FR"), "0,2;0,8;0,4;0,6" |
| 220 | + }; |
| 221 | + yield return new object[] |
| 222 | + { |
| 223 | + new KeySpline { ControlPoint1 = new Point(0.75, 0.25), ControlPoint2 = new Point(0.5, 0.5) }, |
| 224 | + new CultureInfo("de-DE"), "0,75;0,25;0,5;0,5" |
| 225 | + }; |
| 226 | + yield return new object[] |
| 227 | + { |
| 228 | + new KeySpline { ControlPoint1 = new Point(0.1, 0.9), ControlPoint2 = new Point(0.9, 0.1) }, |
| 229 | + CultureInfo.InvariantCulture, "0.1,0.9,0.9,0.1" |
| 230 | + }; |
| 231 | + yield return new object[] |
| 232 | + { |
| 233 | + new KeySpline { ControlPoint1 = new Point(0.05, 0.95), ControlPoint2 = new Point(0.95, 100.05) }, |
| 234 | + CultureInfo.InvariantCulture, "0.05,0.95,0.95,100.05" |
| 235 | + }; |
| 236 | + yield return new object[] |
| 237 | + { |
| 238 | + new KeySpline { ControlPoint1 = new Point(0.4, 0.4), ControlPoint2 = new Point(0.6, 0.6) }, |
| 239 | + new CultureInfo("en-US"), "0.4,0.4,0.6,0.6" |
| 240 | + }; |
| 241 | + yield return new object[] |
| 242 | + { |
| 243 | + new KeySpline { ControlPoint1 = new Point(0.8, 0.2), ControlPoint2 = new Point(0.3, 0.7) }, |
| 244 | + new CultureInfo("fr-FR"), "0,8;0,2;0,3;0,7" |
| 245 | + }; |
| 246 | + yield return new object[] |
| 247 | + { |
| 248 | + new KeySpline { ControlPoint1 = new Point(0.55, 0.45), ControlPoint2 = new Point(0.35, 0.65) }, |
| 249 | + new CultureInfo("de-DE"), "0,55;0,45;0,35;0,65" |
| 250 | + }; |
| 251 | + yield return new object[] |
| 252 | + { |
| 253 | + new KeySpline { ControlPoint1 = new Point(0.99, 0.01), ControlPoint2 = new Point(0.5, 0.5) }, |
| 254 | + CultureInfo.InvariantCulture, "0.99,0.01,0.5,0.5" |
| 255 | + }; |
| 256 | + } |
| 257 | + } |
| 258 | + |
| 259 | + [Theory] |
| 260 | + [MemberData(nameof(ConvertTo_StringInput_ReturnsString_Data))] |
| 261 | + public void ConvertTo_ObjectInput_ReturnsStringRepresentation(object input, Type destinationType, CultureInfo culture) |
| 262 | + { |
| 263 | + KeySplineConverter converter = new(); |
| 264 | + |
| 265 | + Assert.Equal(input.ToString(), converter.ConvertTo(null, culture, input, destinationType)); |
| 266 | + } |
| 267 | + |
| 268 | + public static IEnumerable<object[]> ConvertTo_StringInput_ReturnsString_Data |
| 269 | + { |
| 270 | + get |
| 271 | + { |
| 272 | + yield return new object[] { string.Empty, typeof(string), CultureInfo.InvariantCulture }; |
| 273 | + |
| 274 | + // This is how base calls work, fun |
| 275 | + yield return new object[] { Colors.Red, typeof(string), CultureInfo.InvariantCulture }; |
| 276 | + yield return new object[] { Brushes.Purple, typeof(string), CultureInfo.CurrentCulture }; |
| 277 | + yield return new object[] { "This is given back", typeof(string), CultureInfo.InvariantCulture }; |
| 278 | + yield return new object[] { " This too ", typeof(string), CultureInfo.InvariantCulture }; |
| 279 | + } |
| 280 | + } |
| 281 | + |
| 282 | + [Theory] |
| 283 | + [MemberData(nameof(ConvertTo_InvalidData_ThrowsNotSupportedException_Data))] |
| 284 | + public void ConvertTo_InvalidData_ThrowsNotSupportedException(object? input, Type? destinationType, CultureInfo? culture) |
| 285 | + { |
| 286 | + KeySplineConverter converter = new(); |
| 287 | + |
| 288 | + Assert.Throws<NotSupportedException>(() => converter.ConvertTo(null, culture, input, destinationType)); |
| 289 | + } |
| 290 | + |
| 291 | + public static IEnumerable<object?[]> ConvertTo_InvalidData_ThrowsNotSupportedException_Data |
| 292 | + { |
| 293 | + get |
| 294 | + { |
| 295 | + yield return new object[] { new KeySpline(0.1, 0.2, 0.3, 0.4), typeof(int), CultureInfo.CurrentCulture }; |
| 296 | + yield return new object[] { new KeySpline(0.5, 0.6, 0.7, 0.8), typeof(double), CultureInfo.InvariantCulture }; |
| 297 | + yield return new object[] { new KeySpline(0.25, 0.25, 0.75, 0.75), typeof(object), CultureInfo.InvariantCulture }; |
| 298 | + yield return new object[] { new KeySpline(1.0, 0.0, 0.0, 1.0), typeof(bool), CultureInfo.InvariantCulture }; |
| 299 | + yield return new object[] { new KeySpline(0.33, 0.66, 0.66, 0.33), typeof(DateTime), CultureInfo.InvariantCulture }; |
| 300 | + yield return new object[] { new KeySpline(0.5, 0.5, 0.5, 0.5), typeof(Guid), CultureInfo.CurrentCulture }; |
| 301 | + yield return new object[] { new KeySpline(0.1, 0.2, 0.3, 0.4), typeof(Uri), CultureInfo.InvariantCulture }; |
| 302 | + yield return new object[] { new KeySpline(0.6, 0.7, 0.8, 0.9), typeof(Array), CultureInfo.InvariantCulture }; |
| 303 | + yield return new object[] { new KeySpline(0.2, 0.3, 0.4, 0.5), typeof(TimeSpan), CultureInfo.InvariantCulture }; |
| 304 | + yield return new object[] { new KeySpline(0.7, 0.8, 0.9, 1.0), typeof(Enum), CultureInfo.InvariantCulture }; |
| 305 | + yield return new object[] { new KeySpline(0.1, 0.2, 0.3, 0.4), typeof(Point), CultureInfo.InvariantCulture }; |
| 306 | + yield return new object[] { new KeySpline(0.1, 0.1, 0.9, 0.9), typeof(Color), CultureInfo.CurrentCulture }; |
| 307 | + yield return new object[] { new KeySpline(0.2, 0.4, 0.6, 0.8), typeof(KeySpline), CultureInfo.InvariantCulture }; |
| 308 | + yield return new object[] { new KeySpline(0.2, 0.3, 0.4, 0.5), typeof(byte[]), CultureInfo.InvariantCulture }; |
| 309 | + yield return new object[] { new KeySpline(0.0, 0.1, 0.2, 0.3), typeof(Dictionary<int, string>), CultureInfo.InvariantCulture }; |
| 310 | + yield return new object[] { new KeySpline(0.1, 0.2, 0.3, 0.4), typeof(List<int>), CultureInfo.InvariantCulture }; |
| 311 | + yield return new object[] { new KeySpline(0.4, 0.3, 0.2, 0.1), typeof(Stack<int>), CultureInfo.InvariantCulture }; |
| 312 | + } |
| 313 | + } |
| 314 | + |
| 315 | + [Theory] |
| 316 | + [MemberData(nameof(ConvertTo_InvalidDestinationType_ThrowsArgumentNullException_Data))] |
| 317 | + public void ConvertTo_InvalidDestinationType_ThrowsArgumentNullException(KeySpline? input, Type? destinationType, CultureInfo? culture) |
| 318 | + { |
| 319 | + KeySplineConverter converter = new(); |
| 320 | + |
| 321 | + Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(null, culture, input, destinationType)); |
| 322 | + } |
| 323 | + |
| 324 | + public static IEnumerable<object?[]> ConvertTo_InvalidDestinationType_ThrowsArgumentNullException_Data |
| 325 | + { |
| 326 | + get |
| 327 | + { |
| 328 | + yield return new object?[] { null, null, CultureInfo.InvariantCulture }; |
| 329 | + yield return new object?[] { new KeySpline(0.0, 0.0, 1.0, 1.0), null, CultureInfo.InvariantCulture }; |
| 330 | + } |
| 331 | + } |
| 332 | +} |
0 commit comments