1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, 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+" - "+u_errorName(status));
200          return;
201        }
202      } else {
203        errln("No collator definition!");
204        return;
205      }
206    }
207
208    int32_t cloneSize = 0;
209    uint8_t* cloneBuf = NULL;
210    RuleBasedCollator* clone = NULL;
211    if(col != NULL){
212      RuleBasedCollator* rbc = (RuleBasedCollator*)col;
213      cloneSize = rbc->cloneBinary(NULL, 0, intStatus);
214      intStatus = U_ZERO_ERROR;
215      cloneBuf = (uint8_t*) malloc(cloneSize);
216      cloneSize = rbc->cloneBinary(cloneBuf, cloneSize, intStatus);
217      clone = new RuleBasedCollator(cloneBuf, cloneSize, UCA, intStatus);
218      if(U_FAILURE(intStatus)){
219          errln("Could not clone the RuleBasedCollator. Error: %s", u_errorName(intStatus));
220          intStatus= U_ZERO_ERROR;
221      }
222      // get attributes
223      testSetting = settings->getString("Arguments", intStatus);
224      if(U_SUCCESS(intStatus)) {
225        logln("Arguments: "+testSetting);
226        argLen = testSetting.length();
227        arguments = testSetting.getBuffer();
228        processArguments(col, arguments, argLen);
229        if(clone != NULL){
230            processArguments(clone, arguments, argLen);
231        }
232        if(U_FAILURE(status)) {
233          errln("Couldn't process arguments");
234          break;
235        }
236      } else {
237        intStatus = U_ZERO_ERROR;
238      }
239      // Start the processing
240      while(testData->nextCase(currentCase, status)) {
241        UnicodeString sequence = currentCase->getString("sequence", status);
242        if(U_SUCCESS(status)) {
243            processSequence(col, sequence);
244            if(clone != NULL){
245                processSequence(clone, sequence);
246            }
247        }
248      }
249    } else {
250      errln("Couldn't instantiate a collator!");
251    }
252    delete clone;
253    free(cloneBuf);
254    delete col;
255    col = NULL;
256  }
257}
258
259
260void
261DataDrivenCollatorTest::processSequence(Collator* col, const UnicodeString &sequence) {
262  Collator::EComparisonResult relation = Collator::EQUAL;
263  UBool hasNext;
264  SeqElement *source = NULL;
265  SeqElement *target = NULL;
266  int32_t j = 0;
267
268  sequences.removeAllElements();
269
270  target = new SeqElement();
271
272  setTestSequence(sequence, *target);
273  sequences.addElement(target, status);
274
275  do {
276    relation = Collator::EQUAL;
277    target = new SeqElement();
278    hasNext = getNextInSequence(*target);
279    for(j = sequences.size(); j > 0; j--) {
280      source = (SeqElement *)sequences.elementAt(j-1);
281      if(relation == Collator::EQUAL && source->relation != Collator::EQUAL) {
282        relation = source->relation;
283      }
284      doTest(col, source->source, target->source, relation);
285    }
286    sequences.addElement(target, status);
287    source = target;
288  } while(hasNext);
289}
290
291#endif /* #if !UCONFIG_NO_COLLATION */
292