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.Reflection;
7 using Xunit;
8 
9 namespace System.Globalization.Tests
10 {
11     public class CompareInfoTests
12     {
13         [Theory]
14         [InlineData("")]
15         [InlineData("en-US")]
16         [InlineData("fr-FR")]
17         [InlineData("en")]
18         [InlineData("zh-Hans")]
19         [InlineData("zh-Hant")]
GetCompareInfo(string name)20         public void GetCompareInfo(string name)
21         {
22             CompareInfo compare = CompareInfo.GetCompareInfo(name);
23             Assert.Equal(name, compare.Name);
24         }
25 
26         [Fact]
GetCompareInfo_Null_ThrowsArgumentNullException()27         public void GetCompareInfo_Null_ThrowsArgumentNullException()
28         {
29             AssertExtensions.Throws<ArgumentNullException>("name", () => CompareInfo.GetCompareInfo(null));
30         }
31 
Equals_TestData()32         public static IEnumerable<object[]> Equals_TestData()
33         {
34             yield return new object[] { CultureInfo.InvariantCulture.CompareInfo, CultureInfo.InvariantCulture.CompareInfo, true };
35             yield return new object[] { CultureInfo.InvariantCulture.CompareInfo, CompareInfo.GetCompareInfo(""), true };
36             yield return new object[] { new CultureInfo("en-US").CompareInfo, CompareInfo.GetCompareInfo("en-US"), true };
37             yield return new object[] { new CultureInfo("en-US").CompareInfo, CompareInfo.GetCompareInfo("fr-FR"), false };
38             yield return new object[] { new CultureInfo("en-US").CompareInfo, new object(), false };
39         }
40 
41         [Theory]
42         [MemberData(nameof(Equals_TestData))]
Equals(CompareInfo compare1, object value, bool expected)43         public void Equals(CompareInfo compare1, object value, bool expected)
44         {
45             Assert.Equal(expected, compare1.Equals(value));
46             if (value is CompareInfo)
47             {
48                 Assert.Equal(expected, compare1.GetHashCode().Equals(value.GetHashCode()));
49             }
50         }
51 
52         [Theory]
53         [InlineData("abc", CompareOptions.OrdinalIgnoreCase, "ABC", CompareOptions.OrdinalIgnoreCase, true)]
54         [InlineData("abc", CompareOptions.Ordinal, "ABC", CompareOptions.Ordinal, false)]
55         [InlineData("abc", CompareOptions.Ordinal, "abc", CompareOptions.Ordinal, true)]
56         [InlineData("abc", CompareOptions.None, "abc", CompareOptions.None, true)]
GetHashCode(string source1, CompareOptions options1, string source2, CompareOptions options2, bool expected)57         public void GetHashCode(string source1, CompareOptions options1, string source2, CompareOptions options2, bool expected)
58         {
59             CompareInfo invariantCompare = CultureInfo.InvariantCulture.CompareInfo;
60             Assert.Equal(expected, invariantCompare.GetHashCode(source1, options1).Equals(invariantCompare.GetHashCode(source2, options2)));
61         }
62 
63         [Fact]
GetHashCode_EmptyString()64         public void GetHashCode_EmptyString()
65         {
66             Assert.Equal(0, CultureInfo.InvariantCulture.CompareInfo.GetHashCode("", CompareOptions.None));
67         }
68 
69         [Fact]
GetHashCode_Invalid()70         public void GetHashCode_Invalid()
71         {
72             AssertExtensions.Throws<ArgumentNullException>("source", () => CultureInfo.InvariantCulture.CompareInfo.GetHashCode(null, CompareOptions.None));
73 
74             AssertExtensions.Throws<ArgumentException>("options", () => CultureInfo.InvariantCulture.CompareInfo.GetHashCode("Test", CompareOptions.StringSort));
75             AssertExtensions.Throws<ArgumentException>("options", () => CultureInfo.InvariantCulture.CompareInfo.GetHashCode("Test", CompareOptions.Ordinal | CompareOptions.IgnoreSymbols));
76             AssertExtensions.Throws<ArgumentException>("options", () => CultureInfo.InvariantCulture.CompareInfo.GetHashCode("Test", (CompareOptions)(-1)));
77         }
78 
79         [Theory]
80         [InlineData("", "CompareInfo - ")]
81         [InlineData("en-US", "CompareInfo - en-US")]
82         [InlineData("EN-US", "CompareInfo - en-US")]
ToString(string name, string expected)83         public void ToString(string name, string expected)
84         {
85             Assert.Equal(expected, new CultureInfo(name).CompareInfo.ToString());
86         }
87 
CompareInfo_TestData()88         public static IEnumerable<object[]> CompareInfo_TestData()
89         {
90             yield return new object[] { "en-US"  , 0x0409 };
91             yield return new object[] { "ar-SA"  , 0x0401 };
92             yield return new object[] { "ja-JP"  , 0x0411 };
93             yield return new object[] { "zh-CN"  , 0x0804 };
94             yield return new object[] { "en-GB"  , 0x0809 };
95             yield return new object[] { "tr-TR"  , 0x041f };
96         }
97 
98         // On Windows, hiragana characters sort after katakana.
99         // On ICU, it is the opposite
100         private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsWindows ? 1 : -1;
101 
102         // On Windows, all halfwidth characters sort before fullwidth characters.
103         // On ICU, half and fullwidth characters that aren't in the "Halfwidth and fullwidth forms" block U+FF00-U+FFEF
104         // sort before the corresponding characters that are in the block U+FF00-U+FFEF
105         private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsWindows ? -1 : 1;
106 
107         private static CompareInfo s_invariantCompare = CultureInfo.InvariantCulture.CompareInfo;
108         private static CompareInfo s_turkishCompare = new CultureInfo("tr-TR").CompareInfo;
109 
SortKey_TestData()110         public static IEnumerable<object[]> SortKey_TestData()
111         {
112             CompareOptions ignoreKanaIgnoreWidthIgnoreCase = CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase;
113             yield return new object[] { s_invariantCompare, "\u3042", "\u30A2", ignoreKanaIgnoreWidthIgnoreCase, 0 };
114             yield return new object[] { s_invariantCompare, "\u3042", "\uFF71", ignoreKanaIgnoreWidthIgnoreCase, 0 };
115 
116             yield return new object[] { s_invariantCompare, "\u304D\u3083", "\u30AD\u30E3", ignoreKanaIgnoreWidthIgnoreCase, 0 };
117             yield return new object[] { s_invariantCompare, "\u304D\u3083", "\u30AD\u3083", ignoreKanaIgnoreWidthIgnoreCase, 0 };
118             yield return new object[] { s_invariantCompare, "\u304D \u3083", "\u30AD\u3083", ignoreKanaIgnoreWidthIgnoreCase, -1 };
119             yield return new object[] { s_invariantCompare, "\u3044", "I", ignoreKanaIgnoreWidthIgnoreCase, 1 };
120 
121             yield return new object[] { s_invariantCompare, "a", "A", ignoreKanaIgnoreWidthIgnoreCase, 0 };
122             yield return new object[] { s_invariantCompare, "a", "\uFF41", ignoreKanaIgnoreWidthIgnoreCase, 0 };
123             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF21\uFF22\uFF23\uFF24\uFF25", ignoreKanaIgnoreWidthIgnoreCase, 0 };
124             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF21\uFF22\uFF23D\uFF25", ignoreKanaIgnoreWidthIgnoreCase, 0 };
125             yield return new object[] { s_invariantCompare, "ABCDE", "a\uFF22\uFF23D\uFF25", ignoreKanaIgnoreWidthIgnoreCase, 0 };
126             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF41\uFF42\uFF23D\uFF25", ignoreKanaIgnoreWidthIgnoreCase, 0 };
127 
128             yield return new object[] { s_invariantCompare, "\u6FA4", "\u6CA2", ignoreKanaIgnoreWidthIgnoreCase, 1 };
129 
130             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u30D6\u30D9\u30DC", ignoreKanaIgnoreWidthIgnoreCase, 0 };
131             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\u30DC", ignoreKanaIgnoreWidthIgnoreCase, 0 };
132             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, 0 };
133             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, 0 };
134             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, -1 };
135             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, -1 };
136             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u3079\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, -1 };
137             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D6", ignoreKanaIgnoreWidthIgnoreCase, -1 };
138             yield return new object[] { s_invariantCompare, "\u3071\u3074\u30D7\u307A", "\uFF8B\uFF9F\uFF8C\uFF9F", ignoreKanaIgnoreWidthIgnoreCase, -1 };
139             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u3070\uFF8E\uFF9E\u30D6", ignoreKanaIgnoreWidthIgnoreCase, 1 };
140             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C\u3079\u307C", "\u3079\uFF8E\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, -1 };
141             yield return new object[] { s_invariantCompare, "\u3070\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D6", ignoreKanaIgnoreWidthIgnoreCase, -1 };
142 
143             yield return new object[] { s_invariantCompare, "ABDDE", "D", ignoreKanaIgnoreWidthIgnoreCase, -1 };
144             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF43D", ignoreKanaIgnoreWidthIgnoreCase, -1 };
145             yield return new object[] { s_invariantCompare, "ABCDE", "c", ignoreKanaIgnoreWidthIgnoreCase, -1 };
146             yield return new object[] { s_invariantCompare, "\u3060", "\u305F", ignoreKanaIgnoreWidthIgnoreCase, 1 };
147             yield return new object[] { s_invariantCompare, "\u3060", "\uFF80\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, 0 };
148             yield return new object[] { s_invariantCompare, "\u3060", "\u30C0", ignoreKanaIgnoreWidthIgnoreCase, 0 };
149 
150             yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9\u30B9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E\uFF7D", ignoreKanaIgnoreWidthIgnoreCase, 0 };
151             yield return new object[] { s_invariantCompare, "\u30C7", "\uFF83\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, 0 };
152             yield return new object[] { s_invariantCompare, "\u30C7\u30BF", "\uFF83\uFF9E\uFF80", ignoreKanaIgnoreWidthIgnoreCase, 0 };
153             yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E", ignoreKanaIgnoreWidthIgnoreCase, 0 };
154             yield return new object[] { s_invariantCompare, "\u30BF", "\uFF80", ignoreKanaIgnoreWidthIgnoreCase, 0 };
155 
156             yield return new object[] { s_invariantCompare, "\uFF83\uFF9E\uFF70\uFF80\uFF8D\uFF9E\uFF70\uFF7D", "\u3067\u30FC\u305F\u3079\u30FC\u3059", ignoreKanaIgnoreWidthIgnoreCase, 0 };
157             yield return new object[] { s_invariantCompare, "\u68EE\u9D0E\u5916", "\u68EE\u9DD7\u5916", ignoreKanaIgnoreWidthIgnoreCase, -1 };
158             yield return new object[] { s_invariantCompare, "\u68EE\u9DD7\u5916", "\u68EE\u9DD7\u5916", ignoreKanaIgnoreWidthIgnoreCase, 0 };
159             yield return new object[] { s_invariantCompare, "\u2019\u2019\u2019\u2019", "''''", ignoreKanaIgnoreWidthIgnoreCase, 1 };
160             yield return new object[] { s_invariantCompare, "\u2019", "'", ignoreKanaIgnoreWidthIgnoreCase, 1 };
161             yield return new object[] { s_invariantCompare, "", "'", ignoreKanaIgnoreWidthIgnoreCase, -1 };
162             yield return new object[] { s_invariantCompare, "\u4E00", "\uFF11", ignoreKanaIgnoreWidthIgnoreCase, 1 };
163             yield return new object[] { s_invariantCompare, "\u2160", "\uFF11", ignoreKanaIgnoreWidthIgnoreCase, 1 };
164 
165             yield return new object[] { s_invariantCompare, "0", "\uFF10", ignoreKanaIgnoreWidthIgnoreCase, 0 };
166             yield return new object[] { s_invariantCompare, "10", "1\uFF10", ignoreKanaIgnoreWidthIgnoreCase, 0 };
167             yield return new object[] { s_invariantCompare, "9999\uFF1910", "1\uFF10", ignoreKanaIgnoreWidthIgnoreCase, 1 };
168             yield return new object[] { s_invariantCompare, "9999\uFF191010", "1\uFF10", ignoreKanaIgnoreWidthIgnoreCase, 1 };
169 
170             yield return new object[] { s_invariantCompare, "'\u3000'", "' '", ignoreKanaIgnoreWidthIgnoreCase, 0 };
171             yield return new object[] { s_invariantCompare, "\uFF1B", ";", ignoreKanaIgnoreWidthIgnoreCase, 0 };
172             yield return new object[] { s_invariantCompare, "\uFF08", "(", ignoreKanaIgnoreWidthIgnoreCase, 0 };
173             yield return new object[] { s_invariantCompare, "\u30FC", "\uFF70", ignoreKanaIgnoreWidthIgnoreCase, 0 };
174             yield return new object[] { s_invariantCompare, "\u30FC", "\uFF0D", ignoreKanaIgnoreWidthIgnoreCase, 1 };
175             yield return new object[] { s_invariantCompare, "\u30FC", "\u30FC", ignoreKanaIgnoreWidthIgnoreCase, 0 };
176             yield return new object[] { s_invariantCompare, "\u30FC", "\u2015", ignoreKanaIgnoreWidthIgnoreCase, 1 };
177             yield return new object[] { s_invariantCompare, "\u30FC", "\u2010", ignoreKanaIgnoreWidthIgnoreCase, 1 };
178 
179             yield return new object[] { s_invariantCompare, "/", "\uFF0F", ignoreKanaIgnoreWidthIgnoreCase, 0 };
180             yield return new object[] { s_invariantCompare, "'", "\uFF07", ignoreKanaIgnoreWidthIgnoreCase, PlatformDetection.IsWindows7 ? -1 : 0};
181             yield return new object[] { s_invariantCompare, "\"", "\uFF02", ignoreKanaIgnoreWidthIgnoreCase, 0 };
182 
183             yield return new object[] { s_invariantCompare, "\u3042", "\u30A1", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
184             yield return new object[] { s_invariantCompare, "\u3042", "\u30A2", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
185             yield return new object[] { s_invariantCompare, "\u3042", "\uFF71", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
186             yield return new object[] { s_invariantCompare, "\u304D\u3083", "\u30AD\u30E3", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
187             yield return new object[] { s_invariantCompare, "\u304D\u3083", "\u30AD\u3083", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
188 
189             yield return new object[] { s_invariantCompare, "\u304D \u3083", "\u30AD\u3083", CompareOptions.None, -1 };
190             yield return new object[] { s_invariantCompare, "\u3044", "I", CompareOptions.None, 1 };
191             yield return new object[] { s_invariantCompare, "a", "A", CompareOptions.None, -1 };
192             yield return new object[] { s_invariantCompare, "a", "\uFF41", CompareOptions.None, -1 };
193             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF21\uFF22\uFF23\uFF24\uFF25", CompareOptions.None, -1 };
194             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF21\uFF22\uFF23D\uFF25", CompareOptions.None, -1 };
195             yield return new object[] { s_invariantCompare, new string('a', 5555), new string('a', 5554) + "b", CompareOptions.None, -1 };
196             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF41\uFF42\uFF23D\uFF25", CompareOptions.None, 1 };
197             yield return new object[] { s_invariantCompare, "\u6FA4", "\u6CA2", CompareOptions.None, 1 };
198 
199             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u30D6\u30D9\u30DC", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
200             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\u30DC", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
201             yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
202             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
203 
204             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\uFF8E\uFF9E", CompareOptions.None, -1 };
205             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u3079\uFF8E\uFF9E", CompareOptions.None, -1 };
206             yield return new object[] { s_invariantCompare, "\u3070\u3073\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D6", CompareOptions.None, -1 };
207             yield return new object[] { s_invariantCompare, "\u3071\u3074\u30D7\u307A", "\uFF8B\uFF9F\uFF8C\uFF9F", CompareOptions.None, -1 };
208             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u3070\uFF8E\uFF9E\u30D6", CompareOptions.None, 1 };
209             yield return new object[] { s_invariantCompare, "\u3070\u30DC\uFF8C\uFF9E\uFF8D\uFF9E\u307C\u3079\u307C", "\u3079\uFF8E\uFF9E", CompareOptions.None, -1 };
210             yield return new object[] { s_invariantCompare, "\u3070\uFF8C\uFF9E\uFF8D\uFF9E\u307C", "\u30D6", CompareOptions.None, -1 };
211 
212             yield return new object[] { s_invariantCompare, "ABDDE", "D", CompareOptions.None, -1 };
213             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF43D\uFF25", CompareOptions.None, -1 };
214             yield return new object[] { s_invariantCompare, "ABCDE", "\uFF43D", CompareOptions.None, -1 };
215             yield return new object[] { s_invariantCompare, "ABCDE", "c", CompareOptions.None, -1 };
216             yield return new object[] { s_invariantCompare, "\u3060", "\u305F", CompareOptions.None, 1 };
217             yield return new object[] { s_invariantCompare, "\u3060", "\uFF80\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
218             yield return new object[] { s_invariantCompare, "\u3060", "\u30C0", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
219             yield return new object[] { s_invariantCompare, "\u68EE\u9D0E\u5916", "\u68EE\u9DD7\u5916", CompareOptions.None, -1 };
220             yield return new object[] { s_invariantCompare, "\u68EE\u9DD7\u5916", "\u68EE\u9DD7\u5916", CompareOptions.None, 0 };
221 
222             yield return new object[] { s_invariantCompare, "\u2019\u2019\u2019\u2019", "''''", CompareOptions.None, 1 };
223             yield return new object[] { s_invariantCompare, "\u2019\u2019\u2019\u2019", "''''", CompareOptions.None, 1 };
224             yield return new object[] { s_invariantCompare, "\u2019\u2019\u2019\u2019", "''''", CompareOptions.None, 1 };
225             yield return new object[] { s_invariantCompare, "\u2019", "'", CompareOptions.None, 1 };
226             yield return new object[] { s_invariantCompare, "", "'", CompareOptions.None, -1 };
227 
228             yield return new object[] { s_invariantCompare, "\u4E00", "\uFF11", CompareOptions.None, 1 };
229             yield return new object[] { s_invariantCompare, "\u2160", "\uFF11", CompareOptions.None, 1 };
230             yield return new object[] { s_invariantCompare, "0", "\uFF10", CompareOptions.None, -1 };
231             yield return new object[] { s_invariantCompare, "10", "1\uFF10", CompareOptions.None, -1 };
232             yield return new object[] { s_invariantCompare, "1\uFF10", "1\uFF10", CompareOptions.None, 0 };
233             yield return new object[] { s_invariantCompare, "9999\uFF1910", "1\uFF10", CompareOptions.None, 1 };
234             yield return new object[] { s_invariantCompare, "9999\uFF191010", "1\uFF10", CompareOptions.None, 1 };
235 
236             yield return new object[] { s_invariantCompare, "'\u3000'", "' '", CompareOptions.None, 1 };
237             yield return new object[] { s_invariantCompare, "\uFF1B", ";", CompareOptions.None, 1 };
238             yield return new object[] { s_invariantCompare, "\uFF08", "(", CompareOptions.None, 1 };
239             yield return new object[] { s_invariantCompare, "\u30FC", "\uFF0D", CompareOptions.None, 1 };
240             yield return new object[] { s_invariantCompare, "\u30FC", "\u30FC", CompareOptions.None, 0 };
241             yield return new object[] { s_invariantCompare, "\u30FC", "\u2015", CompareOptions.None, 1 };
242             yield return new object[] { s_invariantCompare, "\u30FC", "\u2010", CompareOptions.None, 1 };
243 
244             yield return new object[] { s_invariantCompare, "/", "\uFF0F", CompareOptions.None, -1 };
245             yield return new object[] { s_invariantCompare, "'", "\uFF07", CompareOptions.None, -1 };
246             yield return new object[] { s_invariantCompare, "\"", "\uFF02", CompareOptions.None, -1 };
247 
248             // Turkish
249             yield return new object[] { s_turkishCompare, "i", "I", CompareOptions.None, 1 };
250             yield return new object[] { s_turkishCompare, "i", "I", CompareOptions.IgnoreCase, 1 };
251             yield return new object[] { s_invariantCompare, "i", "\u0130", CompareOptions.None, -1 };
252             yield return new object[] { s_turkishCompare, "i", "\u0130", CompareOptions.IgnoreCase, 0 };
253             yield return new object[] { s_invariantCompare, "i", "I", CompareOptions.None, -1 };
254             yield return new object[] { s_invariantCompare, "i", "I", CompareOptions.IgnoreCase, 0 };
255             yield return new object[] { s_invariantCompare, "i", "\u0130", CompareOptions.None, -1 };
256             yield return new object[] { s_invariantCompare, "i", "\u0130", CompareOptions.IgnoreCase, -1 };
257 
258             yield return new object[] { s_invariantCompare, "\u00C0", "A\u0300", CompareOptions.None, 0 };
259             yield return new object[] { s_invariantCompare, "\u00C0", "a\u0300", CompareOptions.None, 1 };
260             yield return new object[] { s_invariantCompare, "\u00C0", "a\u0300", CompareOptions.IgnoreCase, 0 };
261             yield return new object[] { s_invariantCompare, "FooBA\u0300R", "FooB\u00C0R", CompareOptions.IgnoreNonSpace, 0 };
262 
263             yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.IgnoreSymbols, 0 };
264             yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.StringSort, -1 };
265 
266             yield return new object[] { s_invariantCompare, new string('a', 5555), new string('a', 5555), CompareOptions.None, 0 };
267             yield return new object[] { s_invariantCompare, "foobar", "FooB\u00C0R", CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase, 0 };
268             yield return new object[] { s_invariantCompare, "foobar", "FooB\u00C0R", CompareOptions.IgnoreNonSpace, -1 };
269 
270             yield return new object[] { s_invariantCompare, "\uFF9E", "\u3099", CompareOptions.IgnoreNonSpace, 0 };
271             yield return new object[] { s_invariantCompare, "\uFF9E", "\u3099", CompareOptions.IgnoreCase, 0 };
272             yield return new object[] { s_invariantCompare, "\u20A9", "\uFFE6", CompareOptions.IgnoreWidth, 0 };
273             yield return new object[] { s_invariantCompare, "\u20A9", "\uFFE6", CompareOptions.IgnoreCase, -1 };
274             yield return new object[] { s_invariantCompare, "\u20A9", "\uFFE6", CompareOptions.None, -1 };
275             yield return new object[] { s_invariantCompare, "\u0021", "\uFF01", CompareOptions.IgnoreSymbols, 0 };
276             yield return new object[] { s_invariantCompare, "\u00A2", "\uFFE0", CompareOptions.IgnoreSymbols, 0 };
277             yield return new object[] { s_invariantCompare, "$", "&", CompareOptions.IgnoreSymbols, 0 };
278             yield return new object[] { s_invariantCompare, "\uFF65", "\u30FB", CompareOptions.IgnoreSymbols, 0 };
279             yield return new object[] { s_invariantCompare, "\u0021", "\uFF01", CompareOptions.IgnoreWidth, 0 };
280             yield return new object[] { s_invariantCompare, "\u0021", "\uFF01", CompareOptions.None, -1 };
281             yield return new object[] { s_invariantCompare, "\uFF66", "\u30F2", CompareOptions.IgnoreWidth, 0 };
282 
283             yield return new object[] { s_invariantCompare, "\uFF66", "\u30F2", CompareOptions.IgnoreSymbols, s_expectedHalfToFullFormsComparison };
284             yield return new object[] { s_invariantCompare, "\uFF66", "\u30F2", CompareOptions.IgnoreCase, s_expectedHalfToFullFormsComparison };
285             yield return new object[] { s_invariantCompare, "\uFF66", "\u30F2", CompareOptions.IgnoreNonSpace, s_expectedHalfToFullFormsComparison };
286             yield return new object[] { s_invariantCompare, "\uFF66", "\u30F2", CompareOptions.None, s_expectedHalfToFullFormsComparison };
287 
288             yield return new object[] { s_invariantCompare, "\u3060", "\u30C0", CompareOptions.IgnoreKanaType, 0 };
289             yield return new object[] { s_invariantCompare, "\u3060", "\u30C0", CompareOptions.IgnoreCase, s_expectedHiraganaToKatakanaCompare };
290             yield return new object[] { s_invariantCompare, "c", "C", CompareOptions.IgnoreKanaType, -1 };
291 
292             // Spanish
293             yield return new object[] { new CultureInfo("es-ES").CompareInfo, "llegar", "lugar", CompareOptions.None, -1 };
294         }
295 
IndexOf_TestData()296         public static IEnumerable<object[]> IndexOf_TestData()
297         {
298             yield return new object[] { s_invariantCompare, "foo", "", 0,  0, 0 };
299             yield return new object[] { s_invariantCompare, "", "", 0, 0, 0 };
300             yield return new object[] { s_invariantCompare, "Hello", "l", 0,  2, -1 };
301             yield return new object[] { s_invariantCompare, "Hello", "l", 3,  3, 3 };
302             yield return new object[] { s_invariantCompare, "Hello", "l", 2,  2, 2 };
303             yield return new object[] { s_invariantCompare, "Hello", "L", 0, -1, -1 };
304             yield return new object[] { s_invariantCompare, "Hello", "h", 0, -1, -1 };
305         }
306 
IsSortable_TestData()307         public static IEnumerable<object[]> IsSortable_TestData()
308         {
309             yield return new object[] { "", false, false };
310             yield return new object[] { "abcdefg",  false, true };
311             yield return new object[] { "\uD800\uDC00", true,  true };
312             yield return new object[] { "\uD800\uD800", true,  false };
313         }
314 
315         [Theory]
316         [MemberData(nameof(CompareInfo_TestData))]
LcidTest(string cultureName, int lcid)317         public static void LcidTest(string cultureName, int lcid)
318         {
319             var ci = CompareInfo.GetCompareInfo(lcid);
320             Assert.Equal(cultureName, ci.Name);
321             Assert.Equal(lcid, ci.LCID);
322 
323             Assembly assembly = typeof(string).Assembly;
324 
325             ci = CompareInfo.GetCompareInfo(lcid, assembly);
326             Assert.Equal(cultureName, ci.Name);
327             Assert.Equal(lcid, ci.LCID);
328 
329             ci = CompareInfo.GetCompareInfo(cultureName, assembly);
330             Assert.Equal(cultureName, ci.Name);
331             Assert.Equal(lcid, ci.LCID);
332         }
333 
334         [Theory]
335         [MemberData(nameof(SortKey_TestData))]
SortKeyTest(CompareInfo compareInfo, string string1, string string2, CompareOptions options, int expected)336         public void SortKeyTest(CompareInfo compareInfo, string string1, string string2, CompareOptions options, int expected)
337         {
338             SortKey sk1 = compareInfo.GetSortKey(string1, options);
339             SortKey sk2 = compareInfo.GetSortKey(string2, options);
340 
341             Assert.Equal(expected, SortKey.Compare(sk1, sk2));
342             Assert.Equal(string1, sk1.OriginalString);
343             Assert.Equal(string2, sk2.OriginalString);
344         }
345 
346         [Fact]
SortKeyMiscTest()347         public void SortKeyMiscTest()
348         {
349             CompareInfo ci = new CultureInfo("en-US").CompareInfo;
350             string s1 = "abc";
351             string s2 = "ABC";
352 
353             SortKey sk1 = ci.GetSortKey(s1);
354             SortKey sk2 = ci.GetSortKey(s1);
355 
356             SortKey sk3 = ci.GetSortKey(s2);
357             SortKey sk4 = ci.GetSortKey(s2, CompareOptions.IgnoreCase);
358             SortKey sk5 = ci.GetSortKey(s1, CompareOptions.IgnoreCase);
359 
360             Assert.Equal(sk2, sk1);
361             Assert.Equal(sk2.GetHashCode(), sk1.GetHashCode());
362             Assert.Equal(sk2.KeyData, sk1.KeyData);
363 
364             Assert.NotEqual(sk3, sk1);
365             Assert.NotEqual(sk3.GetHashCode(), sk1.GetHashCode());
366             Assert.NotEqual(sk3.KeyData, sk1.KeyData);
367 
368             Assert.NotEqual(sk4, sk3);
369             Assert.NotEqual(sk4.GetHashCode(), sk3.GetHashCode());
370             Assert.NotEqual(sk4.KeyData, sk3.KeyData);
371 
372             Assert.Equal(sk4, sk5);
373             Assert.Equal(sk4.GetHashCode(), sk5.GetHashCode());
374             Assert.Equal(sk4.KeyData, sk5.KeyData);
375 
376             AssertExtensions.Throws<ArgumentNullException>("source", () => ci.GetSortKey(null));
377             AssertExtensions.Throws<ArgumentException>("options", () => ci.GetSortKey(s1, CompareOptions.Ordinal));
378         }
379 
380         [Theory]
381         [MemberData(nameof(IndexOf_TestData))]
IndexOfTest(CompareInfo compareInfo, string source, string value, int startIndex, int indexOfExpected, int lastIndexOfExpected)382         public void IndexOfTest(CompareInfo compareInfo, string source, string value, int startIndex, int indexOfExpected, int lastIndexOfExpected)
383         {
384             Assert.Equal(indexOfExpected, compareInfo.IndexOf(source, value, startIndex));
385             if (value.Length > 0)
386             {
387                 Assert.Equal(indexOfExpected, compareInfo.IndexOf(source, value[0], startIndex));
388             }
389 
390             Assert.Equal(lastIndexOfExpected, compareInfo.LastIndexOf(source, value, startIndex));
391             if (value.Length > 0)
392             {
393                 Assert.Equal(lastIndexOfExpected, compareInfo.LastIndexOf(source, value[0], startIndex));
394             }
395         }
396 
397         [Theory]
398         [MemberData(nameof(IsSortable_TestData))]
IsSortableTest(string source, bool hasSurrogate, bool expected)399         public void IsSortableTest(string source, bool hasSurrogate, bool expected)
400         {
401             Assert.Equal(expected, CompareInfo.IsSortable(source));
402 
403             bool charExpectedResults = hasSurrogate ? false : expected;
404             foreach (char c in source)
405                 Assert.Equal(charExpectedResults, CompareInfo.IsSortable(c));
406         }
407 
408         [Fact]
VersionTest()409         public void VersionTest()
410         {
411             SortVersion sv1 = CultureInfo.GetCultureInfo("en-US").CompareInfo.Version;
412             SortVersion sv2 = CultureInfo.GetCultureInfo("ja-JP").CompareInfo.Version;
413             SortVersion sv3 = CultureInfo.GetCultureInfo("en").CompareInfo.Version;
414 
415             Assert.Equal(sv1.FullVersion, sv3.FullVersion);
416             Assert.NotEqual(sv1.SortId, sv2.SortId);
417         }
418     }
419 }
420