1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2009, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7/**
8 * IntlTestCollator is the medium level test class for everything in the directory "collate".
9 */
10
11/***********************************************************************
12* Modification history
13* Date        Name        Description
14* 02/14/2001  synwee      Compare with cintltst and commented away tests
15*                         that are not run.
16***********************************************************************/
17
18#include "unicode/utypes.h"
19
20#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_FILE_IO
21
22#include "unicode/uchar.h"
23#include "unicode/tstdtmod.h"
24#include "cstring.h"
25#include "ucol_tok.h"
26#include "tscoll.h"
27#include "dadrcoll.h"
28
29U_CDECL_BEGIN
30static void U_CALLCONV deleteSeqElement(void *elem) {
31  delete((SeqElement *)elem);
32}
33U_CDECL_END
34
35DataDrivenCollatorTest::DataDrivenCollatorTest()
36: seq(StringCharacterIterator("")),
37status(U_ZERO_ERROR),
38sequences(status)
39{
40  driver = TestDataModule::getTestDataModule("DataDrivenCollationTest", *this, status);
41  sequences.setDeleter(deleteSeqElement);
42  UCA = (RuleBasedCollator*)Collator::createInstance("root", status);
43}
44
45DataDrivenCollatorTest::~DataDrivenCollatorTest()
46{
47  delete driver;
48  delete UCA;
49}
50
51void DataDrivenCollatorTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
52{
53  if(driver != NULL) {
54    if (exec)
55    {
56        logln("TestSuite Collator: ");
57    }
58    const DataMap *info = NULL;
59    TestData *testData = driver->createTestData(index, status);
60    if(U_SUCCESS(status)) {
61      name = testData->getName();
62      if(testData->getInfo(info, status)) {
63        log(info->getString("Description", status));
64      }
65      if(exec) {
66        log(name);
67          logln("---");
68          logln("");
69          processTest(testData);
70      }
71      delete testData;
72    } else {
73      name = "";
74    }
75  } else {
76    dataerrln("collate/DataDrivenTest data not initialized!");
77    name = "";
78  }
79
80
81}
82
83UBool
84DataDrivenCollatorTest::setTestSequence(const UnicodeString &setSequence, SeqElement &el) {
85  seq.setText(setSequence);
86  return getNextInSequence(el);
87}
88
89// Parses the sequence to be tested
90UBool
91DataDrivenCollatorTest::getNextInSequence(SeqElement &el) {
92  el.source.truncate(0);
93  UBool quoted = FALSE;
94  UBool quotedsingle = FALSE;
95  UChar32 currChar = 0;
96
97  while(currChar != CharacterIterator::DONE) {
98    currChar= seq.next32PostInc();
99    if(!quoted) {
100      if(u_isWhitespace(currChar)) {
101        continue;
102      }
103      switch(currChar) {
104      case CharacterIterator::DONE:
105        break;
106      case 0x003C /* < */:
107        el.relation = Collator::LESS;
108        currChar = CharacterIterator::DONE;
109        break;
110      case 0x003D /* = */:
111        el.relation = Collator::EQUAL;
112        currChar = CharacterIterator::DONE;
113        break;
114      case 0x003E /* > */:
115        el.relation = Collator::GREATER;
116        currChar = CharacterIterator::DONE;
117        break;
118      case 0x0027 /* ' */: /* very basic quoting */
119        quoted = TRUE;
120        quotedsingle = FALSE;
121        break;
122      case 0x005c /* \ */: /* single quote */
123        quoted = TRUE;
124        quotedsingle = TRUE;
125        break;
126      default:
127        el.source.append(currChar);
128      }
129    } else {
130      if(currChar == CharacterIterator::DONE) {
131        status = U_ILLEGAL_ARGUMENT_ERROR;
132        errln("Quote in sequence not closed!");
133        return FALSE;
134      } else if(currChar == 0x0027) {
135        quoted = FALSE;
136      } else {
137        el.source.append(currChar);
138      }
139      if(quotedsingle) {
140        quoted = FALSE;
141      }
142    }
143  }
144  return seq.hasNext();
145}
146
147// Reads the options string and sets appropriate attributes in collator
148void
149DataDrivenCollatorTest::processArguments(Collator *col, const UChar *start, int32_t optLen) {
150  const UChar *end = start+optLen;
151  UColAttribute attrib;
152  UColAttributeValue value;
153
154  if(optLen == 0) {
155    return;
156  }
157
158  start = ucol_tok_getNextArgument(start, end, &attrib, &value, &status);
159  while(start != NULL) {
160    if(U_SUCCESS(status)) {
161      col->setAttribute(attrib, value, status);
162    }
163    start = ucol_tok_getNextArgument(start, end, &attrib, &value, &status);
164  }
165}
166
167void
168DataDrivenCollatorTest::processTest(TestData *testData) {
169  Collator *col = NULL;
170  const UChar *arguments = NULL;
171  int32_t argLen = 0;
172  const DataMap *settings = NULL;
173  const DataMap *currentCase = NULL;
174  UErrorCode intStatus = U_ZERO_ERROR;
175  UnicodeString testSetting;
176  while(testData->nextSettings(settings, status)) {
177    intStatus = U_ZERO_ERROR;
178    // try to get a locale
179    testSetting = settings->getString("TestLocale", intStatus);
180    if(U_SUCCESS(intStatus)) {
181      char localeName[256];
182      testSetting.extract(0, testSetting.length(), localeName, "");
183      col = Collator::createInstance(localeName, status);
184      if(U_SUCCESS(status)) {
185        logln("Testing collator for locale "+testSetting);
186      } else {
187        errln("Unable to instantiate collator for locale "+testSetting);
188        return;
189      }
190    } else {
191      // if no locale, try from rules
192      intStatus = U_ZERO_ERROR;
193      testSetting = settings->getString("Rules", intStatus);
194      if(U_SUCCESS(intStatus)) {
195        col = new RuleBasedCollator(testSetting, status);
196        if(U_SUCCESS(status)) {
197          logln("Testing collator for rules "+testSetting);
198        } else {
199          errln("Unable to instantiate collator for rules "+testSetting);
200          return;
201        }
202      } else {
203        errln("No collator definition!");
204      }
205    }
206
207    int32_t cloneSize = 0;
208    uint8_t* cloneBuf = NULL;
209    RuleBasedCollator* clone = NULL;
210    if(col != NULL){
211      RuleBasedCollator* rbc = (RuleBasedCollator*)col;
212      cloneSize = rbc->cloneBinary(NULL, 0, intStatus);
213      intStatus = U_ZERO_ERROR;
214      cloneBuf = (uint8_t*) malloc(cloneSize);
215      cloneSize = rbc->cloneBinary(cloneBuf, cloneSize, intStatus);
216      clone = new RuleBasedCollator(cloneBuf, cloneSize, UCA, intStatus);
217      if(U_FAILURE(intStatus)){
218          errln("Could not clone the RuleBasedCollator. Error: %s", u_errorName(intStatus));
219          intStatus= U_ZERO_ERROR;
220      }
221      // get attributes
222      testSetting = settings->getString("Arguments", intStatus);
223      if(U_SUCCESS(intStatus)) {
224        logln("Arguments: "+testSetting);
225        argLen = testSetting.length();
226        arguments = testSetting.getBuffer();
227        processArguments(col, arguments, argLen);
228        if(clone != NULL){
229            processArguments(clone, arguments, argLen);
230        }
231        if(U_FAILURE(status)) {
232          errln("Couldn't process arguments");
233          break;
234        }
235      } else {
236        intStatus = U_ZERO_ERROR;
237      }
238      // Start the processing
239      while(testData->nextCase(currentCase, status)) {
240        UnicodeString sequence = currentCase->getString("sequence", status);
241        if(U_SUCCESS(status)) {
242            processSequence(col, sequence);
243            if(clone != NULL){
244                processSequence(clone, sequence);
245            }
246        }
247      }
248    } else {
249      errln("Couldn't instantiate a collator!");
250    }
251    delete clone;
252    free(cloneBuf);
253    delete col;
254    col = NULL;
255  }
256}
257
258
259void
260DataDrivenCollatorTest::processSequence(Collator* col, const UnicodeString &sequence) {
261  Collator::EComparisonResult relation = Collator::EQUAL;
262  UBool hasNext;
263  SeqElement *source = NULL;
264  SeqElement *target = NULL;
265  int32_t j = 0;
266
267  sequences.removeAllElements();
268
269  target = new SeqElement();
270
271  setTestSequence(sequence, *target);
272  sequences.addElement(target, status);
273
274  do {
275    relation = Collator::EQUAL;
276    target = new SeqElement();
277    hasNext = getNextInSequence(*target);
278    for(j = sequences.size(); j > 0; j--) {
279      source = (SeqElement *)sequences.elementAt(j-1);
280      if(relation == Collator::EQUAL && source->relation != Collator::EQUAL) {
281        relation = source->relation;
282      }
283      doTest(col, source->source, target->source, relation);
284    }
285    sequences.addElement(target, status);
286    source = target;
287  } while(hasNext);
288}
289
290#endif /* #if !UCONFIG_NO_COLLATION */
291