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.Runtime.InteropServices; 7 using Xunit; 8 9 namespace System.Globalization.Tests 10 { 11 public class IdnMappingGetUnicodeTests 12 { GetUnicode_TestData()13 public static IEnumerable<object[]> GetUnicode_TestData() 14 { 15 yield return new object[] { "xn--yda", 0, 7, "\u0101" }; 16 yield return new object[] { "axn--ydab", 1, 7, "\u0101" }; 17 18 yield return new object[] { "xn--aa-cla", 0, 10, "\u0101\u0061a" }; 19 yield return new object[] { "xn--ab-dla", 0, 10, "\u0061\u0101\u0062" }; 20 yield return new object[] { "xn--ab-ela", 0, 10, "\u0061\u0062\u0101" }; 21 22 yield return new object[] { "xn--097ccd", 0, 10, "\uD800\uDF00\uD800\uDF01\uD800\uDF02" }; // Surrogate pairs 23 yield return new object[] { "xn--ab-ic6nfag", 0, 14, "\uD800\uDF00\u0061\uD800\uDF01b\uD800\uDF02" }; // Surrogate pairs separated by ASCII 24 yield return new object[] { "xn--yda263v6b6kfag", 0, 18, "\uD800\uDF00\u0101\uD800\uDF01\u305D\uD800\uDF02" }; // Surrogate pairs separated by non-ASCII 25 yield return new object[] { "xn--a-nha4529qfag", 0, 17, "\uD800\uDF00\u0101\uD800\uDF01\u0061\uD800\uDF02" }; // Surrogate pairs separated by ASCII and non-ASCII 26 yield return new object[] { "\u0061\u0062\u0063", 0, 3, "\u0061\u0062\u0063" }; // ASCII only code points 27 yield return new object[] { "xn--d9juau41awczczp", 0, 19, "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067" }; // Non-ASCII only code points 28 yield return new object[] { "xn--de-jg4avhby1noc0d", 0, 21, "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; // ASCII and non-ASCII code points 29 yield return new object[] { "abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", 0, 45, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; // Fully qualified domain name 30 31 // Embedded domain name conversion (NLS + only)(Priority 1) 32 // Per the spec [7], "The index and count parameters (when provided) allow the 33 // conversion to be done on a larger string where the domain name is embedded 34 // (such as a URI or IRI). The output string is only the converted FQDN or 35 // label, not the whole input string (if the input string contains more 36 // character than the substring to convert)." 37 // Fully Qualified Domain Name (Label1.Label2.Label3) 38 yield return new object[] { "abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", 0, 45, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; 39 yield return new object[] { "abc.xn--d9juau41awczczp", 0, 23, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067" }; 40 yield return new object[] { "abc.xn--d9juau41awczczp.", 0, 24, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067." }; 41 yield return new object[] { "xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", 0, 41, "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; 42 yield return new object[] { "xn--d9juau41awczczp", 0, 19, "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067" }; 43 yield return new object[] { "xn--d9juau41awczczp.", 0, 20, "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067." }; 44 yield return new object[] { "xn--de-jg4avhby1noc0d", 0, 21, "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; 45 } 46 47 [Theory] 48 [MemberData(nameof(GetUnicode_TestData))] GetUnicode(string ascii, int index, int count, string expected)49 public void GetUnicode(string ascii, int index, int count, string expected) 50 { 51 if (index + count == ascii.Length) 52 { 53 if (index == 0) 54 { 55 Assert.Equal(expected, new IdnMapping().GetUnicode(ascii)); 56 } 57 Assert.Equal(expected, new IdnMapping().GetUnicode(ascii, index)); 58 } 59 Assert.Equal(expected, new IdnMapping().GetUnicode(ascii, index, count)); 60 } 61 GetUnicode_Invalid_TestData()62 public static IEnumerable<object[]> GetUnicode_Invalid_TestData() 63 { 64 // Ascii is null 65 yield return new object[] { null, 0, 0, typeof(ArgumentNullException) }; 66 yield return new object[] { null, -5, -10, typeof(ArgumentNullException) }; 67 68 // Index or count are invalid 69 yield return new object[] { "abc", -1, 0, typeof(ArgumentOutOfRangeException) }; 70 yield return new object[] { "abc", 0, -1, typeof(ArgumentOutOfRangeException) }; 71 yield return new object[] { "abc", -5, -10, typeof(ArgumentOutOfRangeException) }; 72 yield return new object[] { "abc", 2, 2, typeof(ArgumentOutOfRangeException) }; 73 yield return new object[] { "abc", 4, 99, typeof(ArgumentOutOfRangeException) }; 74 yield return new object[] { "abc", 3, 0, typeof(ArgumentException) }; 75 76 // Null containing strings 77 yield return new object[] { "abc\u0000", 0, 4, typeof(ArgumentException) }; 78 yield return new object[] { "ab\u0000c", 0, 4, typeof(ArgumentException) }; 79 80 // Invalid unicode strings 81 for (int i = 0; i <= 0x1F; i++) 82 { 83 yield return new object[] { "abc" + (char)i + "def", 0, 7, typeof(ArgumentException) }; 84 } 85 86 yield return new object[] { "abc" + (char)0x7F + "def", 0, 7, typeof(ArgumentException) }; 87 88 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/corefx/issues/8242 89 { 90 yield return new object[] { "xn--\u1234", 0, 5, typeof(ArgumentException) }; 91 yield return new object[] { "xn--\u1234pck", 0, 8, typeof(ArgumentException) }; 92 } 93 } 94 95 [Theory] 96 [MemberData(nameof(GetUnicode_Invalid_TestData))] GetUnicode_Invalid(string ascii, int index, int count, Type exceptionType)97 public void GetUnicode_Invalid(string ascii, int index, int count, Type exceptionType) 98 { 99 GetUnicode_Invalid(new IdnMapping() { UseStd3AsciiRules = false }, ascii, index, count, exceptionType); 100 GetUnicode_Invalid(new IdnMapping() { UseStd3AsciiRules = true }, ascii, index, count, exceptionType); 101 } 102 GetUnicode_Invalid(IdnMapping idnMapping, string ascii, int index, int count, Type exceptionType)103 public static void GetUnicode_Invalid(IdnMapping idnMapping, string ascii, int index, int count, Type exceptionType) 104 { 105 if (ascii == null || index + count == ascii.Length) 106 { 107 if (ascii == null || index == 0) 108 { 109 Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii)); 110 } 111 Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii, index)); 112 } 113 Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii, index, count)); 114 } 115 } 116 } 117