1 /*
2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 4406815 8222969
27  * @summary RuleBasedCollatorTest uses very limited but selected test data
28  *  to test basic functionalities provided by RuleBasedCollator.
29  * @run testng/othervm RuleBasedCollatorTest
30  */
31 
32 import java.text.CollationElementIterator;
33 import java.text.CollationKey;
34 import java.text.RuleBasedCollator;
35 import java.text.Collator;
36 import java.text.ParseException;
37 import java.util.Arrays;
38 import java.util.Locale;
39 
40 import org.testng.annotations.BeforeGroups;
41 import org.testng.annotations.DataProvider;
42 import org.testng.annotations.Test;
43 import org.testng.SkipException;
44 import static org.testng.Assert.*;
45 
46 public class RuleBasedCollatorTest {
47 
48     static RuleBasedCollator USC;
49     static String US_RULES;
50 
51     @BeforeGroups("USC")
setup()52     public void setup() {
53         Collator c = Collator.getInstance(Locale.US);
54         if (!(c instanceof RuleBasedCollator)) {
55             throw new SkipException("skip tests.");
56         }
57         USC = (RuleBasedCollator) c;
58         US_RULES = USC.getRules();
59     }
60 
61 
62     @DataProvider(name = "rulesData")
rulesData()63     Object[][] rulesData() {
64         //Basic Tailor
65         String BASIC_TAILOR_RULES = "< b=c<\u00e6;A,a";
66         String[] BASIC_TAILOR_DATA = {"\u00e6", "b", "a", "c", "A"};
67         String[] BASIC_TAILOR_EXPECTED = {"b", "c", "\u00e6", "A", "a"};
68 
69         //Contraction
70         String CONTRACTION_RULES = US_RULES + "& b < ch ,cH, Ch, CH < c ";
71         String[] CONTRACTION_DATA = {"b", "c", "ch", "CH", "Ch", "cH"};
72         String[] CONTRACTION_EXPECTED = {"b", "ch", "cH", "Ch", "CH", "c"};
73 
74         //Expansion
75         String EXPANSION_RULES = US_RULES + "& ae = \u00e4 < b";
76         String[] EXPANSION_DATA = {"ad", "af", "\u00e4"};
77         String[] EXPANSION_EXPECTED = {"ad", "\u00e4", "af"};
78 
79         //Punctuation
80         String PUNCTUATION_RULES = US_RULES + "< ' ' < '-'";
81         String[] PUNCTUATION_DATA = {"b-w", "b-W", "B-w", "B-W", "bW", "bw",
82                 "Bw", "BW", "b w", "b W", "B w", "B W"};
83         String[] PUNCTUATION_EXPECTED = {"bw", "bW", "Bw", "BW", "b w", "b W",
84                 "B w", "B W", "b-w", "b-W", "B-w", "B-W"};
85 
86         return new Object[][] {
87                 {BASIC_TAILOR_RULES, BASIC_TAILOR_DATA, BASIC_TAILOR_EXPECTED},
88                 {CONTRACTION_RULES, CONTRACTION_DATA, CONTRACTION_EXPECTED},
89                 {EXPANSION_RULES, EXPANSION_DATA, EXPANSION_EXPECTED},
90                 {PUNCTUATION_RULES, PUNCTUATION_DATA, PUNCTUATION_EXPECTED}
91         };
92     }
93 
94     @Test(dataProvider = "rulesData", groups = "USC")
testRules(String rules, String[] testData, String[] expected)95     public void testRules(String rules, String[] testData, String[] expected)
96             throws ParseException {
97         Arrays.sort(testData, new RuleBasedCollator(rules));
98         assertEquals(testData, expected);
99 
100     }
101 
102     @DataProvider(name = "FrenchSecondarySort")
FrenchSecondarySort()103     Object[][] FrenchSecondarySort() {
104         return new Object[][] {
105                 { "\u0061\u00e1\u0061", "\u00e1\u0061\u0061", 1 },
106                 //{"\u0061\u00e1", "\u00e1\u0041", 1},  //JDK-4406815
107                 //{"\u00e1\u0041", "\u0061\u00e1", -1}, //JDK-4406815
108                 {"\u1ea0a", "\u1ea2A", -1}, //case ignore
109                 { "\u1ea0b", "\u1ea2A", 1 },  //primary overwrite
110                 { "\u1e15", "\u1e1d", -1 },   //ignore sec diacritic
111                 { "a", "\u1ea1", -1 } };
112     }
113 
114     @Test(dataProvider = "FrenchSecondarySort", groups = "USC")
testFrenchSecondarySort(String sData, String tData, int expected)115     public void testFrenchSecondarySort(String sData, String tData,
116             int expected) throws ParseException {
117         String french_rule = "@";
118         String rules = US_RULES + french_rule;
119         RuleBasedCollator rc = new RuleBasedCollator(rules);
120         int result = rc.compare(sData, tData);
121         assertEquals(expected, result);
122     }
123 
124     @DataProvider(name = "ThaiLaoVowelConsonantSwapping")
ThaiLaoVowelConsonantSwapping()125     Object[][] ThaiLaoVowelConsonantSwapping() {
126         return new Object[][] {{"\u0e44\u0e01", "\u0e40\u0e2e", -1},//swap
127                 {"\u0e2e\u0e40", "\u0e01\u0e44", 1},//no swap
128                 {"\u0e44\u0061", "\u0e40\u0081", 1}//no swap
129         };
130     }
131 
132     @Test(dataProvider = "ThaiLaoVowelConsonantSwapping", groups = "USC")
testThaiLaoVowelConsonantSwapping(String sData, String tData, int expected)133     public void testThaiLaoVowelConsonantSwapping(String sData, String tData,
134             int expected) throws ParseException {
135         String thai_rule = "& Z < \u0e01 < \u0e2e <\u0e40 < \u0e44!";
136         String rules = US_RULES + thai_rule;
137         RuleBasedCollator rc = new RuleBasedCollator(rules);
138         int result = rc.compare(sData, tData);
139         assertEquals(expected, result);
140     }
141 
142     @Test
testIgnorableCharacter()143     public void testIgnorableCharacter() throws ParseException {
144         String rule = "=f<a<c";
145         RuleBasedCollator rc = new RuleBasedCollator(rule);
146         CollationElementIterator iter = rc.getCollationElementIterator("f");
147         int element = iter.next();
148         int primary = iter.primaryOrder(element);
149         assertEquals(primary, 0);
150     }
151 
152     @DataProvider(name = "Normalization")
Normalization()153     Object[][] Normalization() {
154         return new Object[][] {
155                 //micro sign has no canonical decomp mapping
156                 // 0:NO_Decomposition;
157                 // 1:CANONICAL_Decomposition;
158                 // 2:FULL_Decomposition
159                 {"\u00b5", "\u03BC", 0, -1},
160                 {"\u00b5", "\u03BC", 1, -1},
161                 {"\u00b5", "\u03BC", 2, 0}
162         };
163     }
164 
165     @Test(dataProvider = "Normalization", groups = "USC")
testNormalization(String sData, String tData, int decomp, int result)166     public void testNormalization(String sData, String tData, int decomp,
167             int result) {
168         RuleBasedCollator rc = (RuleBasedCollator)USC.clone();
169         rc.setDecomposition(decomp);
170         assertEquals(rc.compare(sData, tData), result);
171     }
172 
173     @Test
testEquality()174     public void testEquality() throws ParseException {
175         String rule1 = "<a=b";
176         RuleBasedCollator rc1= new RuleBasedCollator(rule1);
177         //test equals()
178         assertTrue(rc1.equals(new RuleBasedCollator(rule1)));
179 
180         //test semantic equality
181         String[] array1 = {"b", "c", "a"};
182         String[] array2 = Arrays.copyOf(array1, array1.length);
183         String[] expected = {"b", "a", "c"};
184         String rule2 = "<b=a";
185         RuleBasedCollator rc2= new RuleBasedCollator(rule2);
186 
187         Arrays.sort(array1, rc1);
188         Arrays.sort(array2, rc2);
189         assertEquals(array1, array2);
190         assertEquals(array1, expected);
191     }
192 
193     @Test
testBasicParsingOrder()194     public void testBasicParsingOrder() throws ParseException {
195         String rule1 = "< a < b & a < c";
196         String rule2 = "< a < c & a < b";
197         String rule3 = "< a < b < c";
198         String s = "abc";
199         RuleBasedCollator c1 = new RuleBasedCollator(rule1);
200         RuleBasedCollator c2 = new RuleBasedCollator(rule2);
201         RuleBasedCollator c3 = new RuleBasedCollator(rule3);
202         CollationKey k1 = c1.getCollationKey(s);
203         CollationKey k2 = c2.getCollationKey(s);
204         CollationKey k3 = c3.getCollationKey(s);
205         //rule1 should not equals to rule2
206         assertEquals(k1.compareTo(k2) == 0, false);
207 
208         //rule2 should equals to rule3
209         assertEquals(k2.compareTo(k3) == 0, true);
210     }
211 
212     @DataProvider(name = "ParseData")
ParseData()213     Object[][] ParseData() {
214         return new Object[][] {
215                 {""},
216                 {"a < b"},
217                 {"< a-b < c"},
218                 {"< ,a"},
219                 {"< a < b & c < d"}
220         };
221     }
222 
223     @Test(dataProvider = "ParseData",
224             expectedExceptions = ParseException.class)
testParseException(String rule)225     public void testParseException(String rule) throws ParseException{
226         new RuleBasedCollator(rule);
227     }
228 
229     @Test(expectedExceptions = NullPointerException.class)
testNullParseException()230     public void testNullParseException() throws ParseException{
231         new RuleBasedCollator(null);
232     }
233 }
234