icu/icu4c/source/test/cintltst/trietest.c
Fredrik Roubert 030fa1a479 ICU-21148 Consistently use standard lowercase true/false everywhere.
This is the normal standard way in C, C++ as well as Java and there's no
longer any reason for ICU to be different. The various internal macros
providing custom boolean constants can all be deleted and code as well
as documentation can be updated to use lowercase true/false everywhere.
2022-09-07 20:56:33 +02:00

890 lines
27 KiB
C

// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
* Copyright (C) 2001-2016, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
* file name: trietest.c
* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
* created on: 2001nov20
* created by: Markus W. Scherer
*/
#include <stdbool.h>
#include <stdio.h>
#include "unicode/utypes.h"
#include "unicode/utf16.h"
#include "utrie.h"
#include "cstring.h"
#include "cmemory.h"
#if 1
#include "cintltst.h"
#else
/* definitions from standalone utrie development */
#define log_err printf
#define log_verbose printf
#undef u_errorName
#define u_errorName(errorCode) "some error code"
#endif
/* Values for setting possibly overlapping, out-of-order ranges of values */
typedef struct SetRange {
UChar32 start, limit;
uint32_t value;
UBool overwrite;
} SetRange;
/*
* Values for testing:
* value is set from the previous boundary's limit to before
* this boundary's limit
*/
typedef struct CheckRange {
UChar32 limit;
uint32_t value;
} CheckRange;
static uint32_t U_CALLCONV
_testFoldedValue32(UNewTrie *trie, UChar32 start, int32_t offset) {
uint32_t foldedValue, value;
UChar32 limit;
UBool inBlockZero;
foldedValue=0;
limit=start+0x400;
while(start<limit) {
value=utrie_get32(trie, start, &inBlockZero);
if(inBlockZero) {
start+=UTRIE_DATA_BLOCK_LENGTH;
} else {
foldedValue|=value;
++start;
}
}
if(foldedValue!=0) {
return ((uint32_t)offset<<16)|foldedValue;
} else {
return 0;
}
}
static int32_t U_CALLCONV
_testFoldingOffset32(uint32_t data) {
return (int32_t)(data>>16);
}
static uint32_t U_CALLCONV
_testFoldedValue16(UNewTrie *trie, UChar32 start, int32_t offset) {
uint32_t foldedValue, value;
UChar32 limit;
UBool inBlockZero;
foldedValue=0;
limit=start+0x400;
while(start<limit) {
value=utrie_get32(trie, start, &inBlockZero);
if(inBlockZero) {
start+=UTRIE_DATA_BLOCK_LENGTH;
} else {
foldedValue|=value;
++start;
}
}
if(foldedValue!=0) {
return (uint32_t)(offset|0x8000);
} else {
return 0;
}
}
static int32_t U_CALLCONV
_testFoldingOffset16(uint32_t data) {
if(data&0x8000) {
return (int32_t)(data&0x7fff);
} else {
return 0;
}
}
static uint32_t U_CALLCONV
_testEnumValue(const void *context, uint32_t value) {
(void)context; // suppress compiler warnings about unused variable
return value^0x5555;
}
static UBool U_CALLCONV
_testEnumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
const CheckRange **pb=(const CheckRange **)context;
const CheckRange *b=(*pb)++;
value^=0x5555;
if(start!=(b-1)->limit || limit!=b->limit || value!=b->value) {
log_err("error: utrie_enum() delivers wrong range [U+%04lx..U+%04lx[.0x%lx instead of [U+%04lx..U+%04lx[.0x%lx\n",
start, limit, value,
(b-1)->limit, b->limit, b->value);
}
return true;
}
static void
testTrieIteration(const char *testName,
const UTrie *trie,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UChar s[100];
uint32_t values[30];
const UChar *p, *limit;
uint32_t value;
UChar32 c;
int32_t i, length, countValues;
UChar c2;
/* write a string */
length=countValues=0;
for(i=0; i<countCheckRanges; ++i) {
c=checkRanges[i].limit;
if(c!=0) {
--c;
U16_APPEND_UNSAFE(s, length, c);
values[countValues++]=checkRanges[i].value;
}
}
limit=s+length;
/* try forward */
p=s;
i=0;
while(p<limit) {
c=c2=0x33;
if(trie->data32!=NULL) {
UTRIE_NEXT32(trie, p, limit, c, c2, value);
} else {
UTRIE_NEXT16(trie, p, limit, c, c2, value);
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE_NEXT(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
testName, c, c2, value, values[i]);
}
if(
c2==0 ?
c!=*(p-1) :
!U16_IS_LEAD(c) || !U16_IS_TRAIL(c2) || c!=*(p-2) || c2!=*(p-1)
) {
log_err("error: wrong (c, c2) from UTRIE_NEXT(%s): (U+%04lx, U+%04lx)\n",
testName, c, c2);
continue;
}
if(c2!=0) {
int32_t offset;
if(trie->data32==NULL) {
value=UTRIE_GET16_FROM_LEAD(trie, c);
offset=trie->getFoldingOffset(value);
if(offset>0) {
value=UTRIE_GET16_FROM_OFFSET_TRAIL(trie, offset, c2);
} else {
value=trie->initialValue;
}
} else {
value=UTRIE_GET32_FROM_LEAD(trie, c);
offset=trie->getFoldingOffset(value);
if(offset>0) {
value=UTRIE_GET32_FROM_OFFSET_TRAIL(trie, offset, c2);
} else {
value=trie->initialValue;
}
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE_GETXX_FROM_OFFSET_TRAIL(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
testName, c, c2, value, values[i]);
}
}
if(c2!=0) {
value=0x44;
if(trie->data32==NULL) {
UTRIE_GET16_FROM_PAIR(trie, c, c2, value);
} else {
UTRIE_GET32_FROM_PAIR(trie, c, c2, value);
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE_GETXX_FROM_PAIR(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
testName, c, c2, value, values[i]);
}
}
++i;
}
/* try backward */
p=limit;
i=countValues;
while(s<p) {
--i;
c=c2=0x33;
if(trie->data32!=NULL) {
UTRIE_PREVIOUS32(trie, s, p, c, c2, value);
} else {
UTRIE_PREVIOUS16(trie, s, p, c, c2, value);
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE_PREVIOUS(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
testName, c, c2, value, values[i]);
}
if(
c2==0 ?
c!=*p:
!U16_IS_LEAD(c) || !U16_IS_TRAIL(c2) || c!=*p || c2!=*(p+1)
) {
log_err("error: wrong (c, c2) from UTRIE_PREVIOUS(%s): (U+%04lx, U+%04lx)\n",
testName, c, c2);
}
}
}
static void
testTrieRangesWithMalloc(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges,
UBool dataIs32, UBool latin1Linear) {
UTrieGetFoldingOffset *getFoldingOffset;
const CheckRange *enumRanges;
UNewTrie *newTrie;
UTrie trie={ 0 };
uint32_t value, value2;
UChar32 start, limit;
int32_t i, length;
UErrorCode errorCode;
UBool overwrite, ok;
uint8_t* storage =NULL;
static const int32_t DEFAULT_STORAGE_SIZE = 32768;
storage = (uint8_t*) uprv_malloc(sizeof(uint8_t)*DEFAULT_STORAGE_SIZE);
log_verbose("\ntesting Trie '%s'\n", testName);
newTrie=utrie_open(NULL, NULL, 2000,
checkRanges[0].value, checkRanges[0].value,
latin1Linear);
/* set values from setRanges[] */
ok=true;
for(i=0; i<countSetRanges; ++i) {
start=setRanges[i].start;
limit=setRanges[i].limit;
value=setRanges[i].value;
overwrite=setRanges[i].overwrite;
if((limit-start)==1 && overwrite) {
ok&=utrie_set32(newTrie, start, value);
} else {
ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
}
}
if(!ok) {
log_err("error: setting values into a trie failed (%s)\n", testName);
return;
}
/* verify that all these values are in the new Trie */
start=0;
for(i=0; i<countCheckRanges; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit) {
if(value!=utrie_get32(newTrie, start, NULL)) {
log_err("error: newTrie(%s)[U+%04lx]==0x%lx instead of 0x%lx\n",
testName, start, utrie_get32(newTrie, start, NULL), value);
}
++start;
}
}
if(dataIs32) {
getFoldingOffset=_testFoldingOffset32;
} else {
getFoldingOffset=_testFoldingOffset16;
}
errorCode=U_ZERO_ERROR;
length=utrie_serialize(newTrie, storage, DEFAULT_STORAGE_SIZE,
dataIs32 ? _testFoldedValue32 : _testFoldedValue16,
(UBool)!dataIs32,
&errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
utrie_close(newTrie);
return;
}
/* test linear Latin-1 range from utrie_getData() */
if(latin1Linear) {
uint32_t *data;
int32_t dataLength;
data=utrie_getData(newTrie, &dataLength);
start=0;
for(i=0; i<countCheckRanges && start<=0xff; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit && start<=0xff) {
if(value!=data[UTRIE_DATA_BLOCK_LENGTH+start]) {
log_err("error: newTrie(%s).latin1Data[U+%04lx]==0x%lx instead of 0x%lx\n",
testName, start, data[UTRIE_DATA_BLOCK_LENGTH+start], value);
}
++start;
}
}
}
utrie_close(newTrie);
errorCode=U_ZERO_ERROR;
if(!utrie_unserialize(&trie, storage, length, &errorCode)) {
log_err("error: utrie_unserialize() failed, %s\n", u_errorName(errorCode));
return;
}
trie.getFoldingOffset=getFoldingOffset;
if(dataIs32!=(trie.data32!=NULL)) {
log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
}
if(latin1Linear!=trie.isLatin1Linear) {
log_err("error: trie serialization (%s) did not preserve Latin-1-linearity\n", testName);
}
/* verify that all these values are in the unserialized Trie */
start=0;
for(i=0; i<countCheckRanges; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
if(start==0xd800) {
/* skip surrogates */
start=limit;
continue;
}
while(start<limit) {
if(start<=0xffff) {
if(dataIs32) {
value2=UTRIE_GET32_FROM_BMP(&trie, start);
} else {
value2=UTRIE_GET16_FROM_BMP(&trie, start);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
if(!U16_IS_LEAD(start)) {
if(dataIs32) {
value2=UTRIE_GET32_FROM_LEAD(&trie, start);
} else {
value2=UTRIE_GET16_FROM_LEAD(&trie, start);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).fromLead(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
}
}
if(dataIs32) {
UTRIE_GET32(&trie, start, value2);
} else {
UTRIE_GET16(&trie, start, value2);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
++start;
}
}
/* enumerate and verify all ranges */
enumRanges=checkRanges+1;
utrie_enum(&trie, _testEnumValue, _testEnumRange, &enumRanges);
/* test linear Latin-1 range */
if(trie.isLatin1Linear) {
if(trie.data32!=NULL) {
const uint32_t *latin1=UTRIE_GET32_LATIN1(&trie);
for(start=0; start<0x100; ++start) {
if(latin1[start]!=UTRIE_GET32_FROM_LEAD(&trie, start)) {
log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get32(U+%04lx)\n",
testName, start, latin1[start], UTRIE_GET32_FROM_LEAD(&trie, start), start);
}
}
} else {
const uint16_t *latin1=UTRIE_GET16_LATIN1(&trie);
for(start=0; start<0x100; ++start) {
if(latin1[start]!=UTRIE_GET16_FROM_LEAD(&trie, start)) {
log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get16(U+%04lx)\n",
testName, start, latin1[start], UTRIE_GET16_FROM_LEAD(&trie, start), start);
}
}
}
}
testTrieIteration(testName, &trie, checkRanges, countCheckRanges);
uprv_free(storage);
}
static void
testTrieRanges(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges,
UBool dataIs32, UBool latin1Linear) {
union{
double bogus; /* needed for aligning the storage */
uint8_t storage[32768];
} storageHolder;
UTrieGetFoldingOffset *getFoldingOffset;
UNewTrieGetFoldedValue *getFoldedValue;
const CheckRange *enumRanges;
UNewTrie *newTrie;
UTrie trie={ 0 };
uint32_t value, value2;
UChar32 start, limit;
int32_t i, length;
UErrorCode errorCode;
UBool overwrite, ok;
log_verbose("\ntesting Trie '%s'\n", testName);
newTrie=utrie_open(NULL, NULL, 2000,
checkRanges[0].value, checkRanges[0].value,
latin1Linear);
/* set values from setRanges[] */
ok=true;
for(i=0; i<countSetRanges; ++i) {
start=setRanges[i].start;
limit=setRanges[i].limit;
value=setRanges[i].value;
overwrite=setRanges[i].overwrite;
if((limit-start)==1 && overwrite) {
ok&=utrie_set32(newTrie, start, value);
} else {
ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
}
}
if(!ok) {
log_err("error: setting values into a trie failed (%s)\n", testName);
return;
}
/* verify that all these values are in the new Trie */
start=0;
for(i=0; i<countCheckRanges; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit) {
if(value!=utrie_get32(newTrie, start, NULL)) {
log_err("error: newTrie(%s)[U+%04lx]==0x%lx instead of 0x%lx\n",
testName, start, utrie_get32(newTrie, start, NULL), value);
}
++start;
}
}
if(dataIs32) {
getFoldingOffset=_testFoldingOffset32;
getFoldedValue=_testFoldedValue32;
} else {
getFoldingOffset=_testFoldingOffset16;
getFoldedValue=_testFoldedValue16;
}
/*
* code coverage for utrie.c/defaultGetFoldedValue(),
* pick some combination of parameters for selecting the UTrie defaults
*/
if(!dataIs32 && latin1Linear) {
getFoldingOffset=NULL;
getFoldedValue=NULL;
}
errorCode=U_ZERO_ERROR;
length=utrie_serialize(newTrie, storageHolder.storage, sizeof(storageHolder.storage),
getFoldedValue,
(UBool)!dataIs32,
&errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
utrie_close(newTrie);
return;
}
if (length >= (int32_t)sizeof(storageHolder.storage)) {
log_err("error: utrie_serialize(%s) needs more memory\n", testName);
utrie_close(newTrie);
return;
}
/* test linear Latin-1 range from utrie_getData() */
if(latin1Linear) {
uint32_t *data;
int32_t dataLength;
data=utrie_getData(newTrie, &dataLength);
start=0;
for(i=0; i<countCheckRanges && start<=0xff; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit && start<=0xff) {
if(value!=data[UTRIE_DATA_BLOCK_LENGTH+start]) {
log_err("error: newTrie(%s).latin1Data[U+%04lx]==0x%lx instead of 0x%lx\n",
testName, start, data[UTRIE_DATA_BLOCK_LENGTH+start], value);
}
++start;
}
}
}
utrie_close(newTrie);
errorCode=U_ZERO_ERROR;
if(!utrie_unserialize(&trie, storageHolder.storage, length, &errorCode)) {
log_err("error: utrie_unserialize() failed, %s\n", u_errorName(errorCode));
return;
}
if(getFoldingOffset!=NULL) {
trie.getFoldingOffset=getFoldingOffset;
}
if(dataIs32!=(trie.data32!=NULL)) {
log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
}
if(latin1Linear!=trie.isLatin1Linear) {
log_err("error: trie serialization (%s) did not preserve Latin-1-linearity\n", testName);
}
/* verify that all these values are in the unserialized Trie */
start=0;
for(i=0; i<countCheckRanges; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
if(start==0xd800) {
/* skip surrogates */
start=limit;
continue;
}
while(start<limit) {
if(start<=0xffff) {
if(dataIs32) {
value2=UTRIE_GET32_FROM_BMP(&trie, start);
} else {
value2=UTRIE_GET16_FROM_BMP(&trie, start);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
if(!U16_IS_LEAD(start)) {
if(dataIs32) {
value2=UTRIE_GET32_FROM_LEAD(&trie, start);
} else {
value2=UTRIE_GET16_FROM_LEAD(&trie, start);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).fromLead(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
}
}
if(dataIs32) {
UTRIE_GET32(&trie, start, value2);
} else {
UTRIE_GET16(&trie, start, value2);
}
if(value!=value2) {
log_err("error: unserialized trie(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
testName, start, value2, value);
}
++start;
}
}
/* enumerate and verify all ranges */
enumRanges=checkRanges+1;
utrie_enum(&trie, _testEnumValue, _testEnumRange, &enumRanges);
/* test linear Latin-1 range */
if(trie.isLatin1Linear) {
if(trie.data32!=NULL) {
const uint32_t *latin1=UTRIE_GET32_LATIN1(&trie);
for(start=0; start<0x100; ++start) {
if(latin1[start]!=UTRIE_GET32_FROM_LEAD(&trie, start)) {
log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get32(U+%04lx)\n",
testName, start, latin1[start], UTRIE_GET32_FROM_LEAD(&trie, start), start);
}
}
} else {
const uint16_t *latin1=UTRIE_GET16_LATIN1(&trie);
for(start=0; start<0x100; ++start) {
if(latin1[start]!=UTRIE_GET16_FROM_LEAD(&trie, start)) {
log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get16(U+%04lx)\n",
testName, start, latin1[start], UTRIE_GET16_FROM_LEAD(&trie, start), start);
}
}
}
}
testTrieIteration(testName, &trie, checkRanges, countCheckRanges);
}
static void
testTrieRanges2(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges,
UBool dataIs32) {
char name[40];
testTrieRanges(testName,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
dataIs32, false);
testTrieRangesWithMalloc(testName,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
dataIs32, false);
uprv_strcpy(name, testName);
uprv_strcat(name, "-latin1Linear");
testTrieRanges(name,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
dataIs32, true);
testTrieRangesWithMalloc(name,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
dataIs32, true);
}
static void
testTrieRanges4(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges) {
char name[40];
uprv_strcpy(name, testName);
uprv_strcat(name, ".32");
testTrieRanges2(name,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
true);
uprv_strcpy(name, testName);
uprv_strcat(name, ".16");
testTrieRanges2(name,
setRanges, countSetRanges,
checkRanges, countCheckRanges,
false);
}
/* test data ----------------------------------------------------------------*/
/* set consecutive ranges, even with value 0 */
static const SetRange
setRanges1[]={
{0, 0x20, 0, false},
{0x20, 0xa7, 0x1234, false},
{0xa7, 0x3400, 0, false},
{0x3400, 0x9fa6, 0x6162, false},
{0x9fa6, 0xda9e, 0x3132, false},
{0xdada, 0xeeee, 0x87ff, false}, /* try to disrupt _testFoldingOffset16() */
{0xeeee, 0x11111, 1, false},
{0x11111, 0x44444, 0x6162, false},
{0x44444, 0x60003, 0, false},
{0xf0003, 0xf0004, 0xf, false},
{0xf0004, 0xf0006, 0x10, false},
{0xf0006, 0xf0007, 0x11, false},
{0xf0007, 0xf0020, 0x12, false},
{0xf0020, 0x110000, 0, false}
};
static const CheckRange
checkRanges1[]={
{0, 0}, /* dummy start range to make _testEnumRange() simpler */
{0x20, 0},
{0xa7, 0x1234},
{0x3400, 0},
{0x9fa6, 0x6162},
{0xda9e, 0x3132},
{0xdada, 0},
{0xeeee, 0x87ff},
{0x11111,1},
{0x44444,0x6162},
{0xf0003,0},
{0xf0004,0xf},
{0xf0006,0x10},
{0xf0007,0x11},
{0xf0020,0x12},
{0x110000, 0}
};
/* set some interesting overlapping ranges */
static const SetRange
setRanges2[]={
{0x21, 0x7f, 0x5555, true},
{0x2f800,0x2fedc, 0x7a, true},
{0x72, 0xdd, 3, true},
{0xdd, 0xde, 4, false},
{0x201, 0x220, 6, true}, /* 3 consecutive blocks with the same pattern but discontiguous value ranges */
{0x221, 0x240, 6, true},
{0x241, 0x260, 6, true},
{0x2f987,0x2fa98, 5, true},
{0x2f777,0x2f833, 0, true},
{0x2f900,0x2ffee, 1, false},
{0x2ffee,0x2ffef, 2, true}
};
static const CheckRange
checkRanges2[]={
{0, 0}, /* dummy start range to make _testEnumRange() simpler */
{0x21, 0},
{0x72, 0x5555},
{0xdd, 3},
{0xde, 4},
{0x201, 0},
{0x220, 6},
{0x221, 0},
{0x240, 6},
{0x241, 0},
{0x260, 6},
{0x2f833,0},
{0x2f987,0x7a},
{0x2fa98,5},
{0x2fedc,0x7a},
{0x2ffee,1},
{0x2ffef,2},
{0x110000, 0}
};
/* use a non-zero initial value */
static const SetRange
setRanges3[]={
{0x31, 0xa4, 1, false},
{0x3400, 0x6789, 2, false},
{0x30000,0x34567,9, true},
{0x45678,0x56789,3, true}
};
static const CheckRange
checkRanges3[]={
{0, 9}, /* dummy start range, also carries the initial value */
{0x31, 9},
{0xa4, 1},
{0x3400, 9},
{0x6789, 2},
{0x45678,9},
{0x56789,3},
{0x110000,9}
};
static void
TrieTest(void) {
testTrieRanges4("set1",
setRanges1, UPRV_LENGTHOF(setRanges1),
checkRanges1, UPRV_LENGTHOF(checkRanges1));
testTrieRanges4("set2-overlap",
setRanges2, UPRV_LENGTHOF(setRanges2),
checkRanges2, UPRV_LENGTHOF(checkRanges2));
testTrieRanges4("set3-initial-9",
setRanges3, UPRV_LENGTHOF(setRanges3),
checkRanges3, UPRV_LENGTHOF(checkRanges3));
}
/* test utrie_unserializeDummy() -------------------------------------------- */
static int32_t U_CALLCONV
dummyGetFoldingOffset(uint32_t data) {
(void)data; // suppress compiler warnings about unused variable
return -1; /* never get non-initialValue data for supplementary code points */
}
static void
dummyTest(UBool make16BitTrie) {
int32_t mem[UTRIE_DUMMY_SIZE/4];
UTrie trie;
UErrorCode errorCode;
UChar32 c;
uint32_t value, initialValue, leadUnitValue;
if(make16BitTrie) {
initialValue=0x313;
leadUnitValue=0xaffe;
} else {
initialValue=0x01234567;
leadUnitValue=0x89abcdef;
}
errorCode=U_ZERO_ERROR;
utrie_unserializeDummy(&trie, mem, sizeof(mem), initialValue, leadUnitValue, make16BitTrie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("utrie_unserializeDummy(make16BitTrie=%d) failed - %s\n", make16BitTrie, u_errorName(errorCode));
return;
}
trie.getFoldingOffset=dummyGetFoldingOffset;
/* test that all code points have initialValue */
for(c=0; c<=0x10ffff; ++c) {
if(make16BitTrie) {
UTRIE_GET16(&trie, c, value);
} else {
UTRIE_GET32(&trie, c, value);
}
if(value!=initialValue) {
log_err("UTRIE_GET%s(dummy, U+%04lx)=0x%lx instead of 0x%lx\n",
make16BitTrie ? "16" : "32", (long)c, (long)value, (long)initialValue);
}
}
/* test that the lead surrogate code units have leadUnitValue */
for(c=0xd800; c<=0xdbff; ++c) {
if(make16BitTrie) {
value=UTRIE_GET16_FROM_LEAD(&trie, c);
} else {
value=UTRIE_GET32_FROM_LEAD(&trie, c);
}
if(value!=leadUnitValue) {
log_err("UTRIE_GET%s_FROM_LEAD(dummy, U+%04lx)=0x%lx instead of 0x%lx\n",
make16BitTrie ? "16" : "32", (long)c, (long)value, (long)leadUnitValue);
}
}
}
static void
DummyTrieTest(void) {
dummyTest(true);
dummyTest(false);
}
void
addTrieTest(TestNode** root);
void
addTrieTest(TestNode** root) {
addTest(root, &TrieTest, "tsutil/trietest/TrieTest");
addTest(root, &DummyTrieTest, "tsutil/trietest/DummyTrieTest");
}